# Development stores

A development store is a free store of your own for building and testing plugins. You create it from the partner dashboard, open it as its owner, install your plugins on it, and place test orders that mark themselves paid without any money moving. It never expires, and it can never become a live store.

Development stores are a partner feature that Orbit switches on. When they are on for your account, **Development stores** appears in the partner dashboard navigation between Plugins and Themes.

## What a development store is

A development store is a complete store in your partner organisation with a development flag set. The flag is enforced across the platform, not just displayed:

- **No live payments.** Card and wallet providers cannot be connected and payment intents are refused. The only payment method is **Test payment**, and that method can only be enabled on a development store.
- **Nothing to pay for.** The store cannot be billed or moved to a paid plan, and every plan feature is available on it. A paid plugin installed on it runs on a trial that never bills, so you can test your own pricing.
- **Never a merchant's store.** A development store cannot be transferred to a merchant. To build a store for a client, use the agency or affiliate paths instead.
- **Not a public shop.** The storefront shows a development store notice and asks search engines not to index it. It uses its Orbit address only; custom domains cannot be attached or bought for it.
- **Never expires.** It stays until you close it.

Storefront emails (order confirmations and the like) send normally, within a daily cap per development store, so email-driven plugins can be tested.

## Creating one

Open **Development stores** and choose **Create development store**.

| Field | Rules |
|---|---|
| **Store name** | 2 to 60 characters, no `<` or `>`. Used for the store's web address |
| **Label** | Optional, up to 120 characters. A note for your own list; only you and your team see it |
| **Add sample products, customers and orders** | On by default. Sample data is added once the store is ready |

You need a verified email address, because the storefront is reachable from the public internet. You can keep a small number of stores open at a time and there is a daily limit on new ones; the page shows your usage. At the limit, close a store to create another.

The store is provisioned in a few seconds and appears as a card with its name, label, storefront address and these actions:

- **Open store** signs you in to the store dashboard as the store's owner. Your team members reach it through their organisation role.
- **Sample data** shows **added**, **adding**, **none** or **failed**, with **Add sample data** or **Retry** where it applies. A failed seed does not stop you using the store.
- **Close** moves the store to the trash and takes its storefront offline.

### Sample data

Sample data is a pack of products, customers and orders, added by a background job so the store is usable straight away. **Add sample data** on a store that already has some tops it up.

### Test payment

Checkout on a development storefront offers **Test payment**. No money is taken and the order is marked paid straight away, so it lands as a paid order with a successful payment: `order.created` fires, then `payment.succeeded`, and order emails, stock and everything downstream behave as they do for a paid order. Refunds work. Card entry, wallets and 3-D Secure are not part of it, so a plugin whose job is payment processing cannot be tested end to end here.

## The trash

Closing a store moves it to the **Trash** section, where its card shows the date it is deleted for good. Until then, **Restore** brings it back, as long as that fits within your open-store allowance, and **Delete now** removes it immediately. Deletion cannot be undone, and a deleted store's storefront address stops answering.

## Testing your plugins on it

Each plugin page in the partner dashboard has a **Test on a development store** panel with **Install**, **Open in store** and **Test webhooks** for every open store. [Testing your plugin](/guides/testing) walks through the loop, including running the plugin from your own machine over a tunnel with a development release, and [Webhooks](/guides/webhooks#test-webhooks) covers the signing secret and test deliveries.

## The API

Every route is called with your partner dashboard session (`Authorization: Bearer <partner JWT>`), resolves your partner account from that session, and only ever sees your own development stores: another partner's store id and an unknown id are the same `404`.

| Method and path | Permission | Purpose |
|---|---|---|
| `GET /api/partners/me/dev-stores` | `partner:dev-store:read` | List your development stores, newest first, as `{ items, meta }`. Closed stores keep their name |
| `GET /api/partners/me/dev-stores/usage` | `partner:dev-store:read` | How many stores you have open and have created today, and the limits |
| `POST /api/partners/me/dev-stores` | `partner:dev-store:manage` | Create one. Body `{ name, label?, sampleData? }`; `sampleData` defaults to `true` |
| `PATCH /api/partners/me/dev-stores/{id}` | `partner:dev-store:manage` | Change the label. Body `{ label }`; `null` clears it |
| `POST /api/partners/me/dev-stores/{id}/login-token` | `partner:dev-store:manage` | A single-use sign-in URL for the store dashboard, returned as `{ url }`. Body `{ next? }`, a path under `/stores/<slug>/` to land on |
| `POST /api/partners/me/dev-stores/{id}/sample-data` | `partner:dev-store:manage` | Add sample products, customers and orders again |
| `GET /api/partners/me/dev-stores/{id}/plugins` | `partner:dev-store:read` | Your own plugins installed on the store, as `{ items, meta }`, each with its release numbers. `pluginId` is the plugin's row id and `pluginKey` its friendly id |
| `DELETE /api/partners/me/dev-stores/{id}` | `partner:dev-store:manage` | Close it (moves it to the trash) |
| `POST /api/partners/me/dev-stores/{id}/restore` | `partner:dev-store:manage` | Restore it from the trash |
| `DELETE /api/partners/me/dev-stores/{id}/permanent` | `partner:dev-store:manage` | Delete a trashed store now |

`partner:dev-store:read` is held by every partner role; `partner:dev-store:manage`, like `partner:plugin:dev-release`, by organisation owners, organisation admins and partner admins.

A store in a list or in the create response looks like this:

```json
{
  "id": "0f3c8b2a-1d4e-4a6b-9c2f-7e5a1b2c3d4e",
  "storeId": "8a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "label": "Stock sync testing",
  "status": "active",
  "storeName": "My plugin test store",
  "storeDomain": "my-plugin-test-store",
  "storefrontUrl": "https://my-plugin-test-store.<storefront domain>",
  "seedStatus": "done",
  "seededAt": "2026-09-29T10:02:11.000Z",
  "lastOpenedAt": "2026-09-29T10:05:40.000Z",
  "createdAt": "2026-09-29T10:01:58.000Z",
  "closedAt": null,
  "purgeDueAt": null,
  "dashboardUrl": "https://<store dashboard>"
}
```

- `storeId` is the id the plugin routes take: `devStoreIds` on a development release, `dev-stores/{storeId}/install`, and `storeId` on a test webhook.
- `storeDomain` is the store's slug in the store dashboard, `/stores/<slug>/`, and the `next` you can pass to the login token route is a path under it.
- `seedStatus` is `none`, `queued`, `seeding`, `done` or `failed`.
- `status` is `active` or `closed`; a closed store has `closedAt` and `purgeDueAt` set and no `storefrontUrl`.

### Responses to expect

| Status | When |
|---|---|
| `403` | Development stores are not switched on for your account, your partner account is not active, your email address is not verified, or you are at your open-store allowance (also when a restore would take you over it) |
| `429` | The daily limit for new stores has been reached, for your account or for the whole platform, or too many sign-in links were requested in a minute |
| `409` | The store is closed (open, sample data, plugin install), sample data is already being added, the store is not in the trash (restore, delete now), or it is past its deletion date (restore) |
| `404` | Not one of your development stores |

## Next steps

- [Testing your plugin](/guides/testing): install, run from your machine, place a test order, send a test webhook
- [Webhooks](/guides/webhooks): the signing secret and test webhooks
- [Publishing your plugin](/guides/publishing): what happens once it works
