> ## Documentation Index
> Fetch the complete documentation index at: https://docs.peeker.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# How orders work

> Statuses, domain counts, idempotency, pending actions, and cancellations.

An order is one purchase: domains plus Google and/or Microsoft inboxes routed
to one workspace target.

IDs look like `ord_01HZX`.

Use a saved [bundle](/concepts/bundles) **or** custom license counts, never
both.

## Order flow

Connect a reusable workspace with `POST /workspaces`, then send its provider
and `wrk_...` ID to `POST /orders`.

Workspace creation does not use an `Idempotency-Key`. Each order does.

For Smartlead, the workspace ID always points to the connected main workspace.
Omit `destination.client_id` to use the main workspace. Include it to use one
client workspace. Orders never accept Smartlead login credentials, user data,
or customer data. A Smartlead Google order does not need the optional workspace
login pair. A Smartlead Microsoft or mixed order does.

See [Provider setup and ordering](/guides/provider-ordering).

## Statuses

| Value              | Meaning                                                |
| ------------------ | ------------------------------------------------------ |
| `in_progress`      | Accepted. Provisioning.                                |
| `completed`        | All domains and inboxes are live.                      |
| `failed`           | Cannot finish without a new order.                     |
| `action_required`  | Needs partner or customer input.                       |
| `cancel_scheduled` | Cancel accepted. Not finished yet.                     |
| `cancelled`        | Finished cancelling. Domains are free for a new order. |

Subscribe to `order.*` [webhooks](/webhooks), or poll `GET /orders/{id}`.

<Note>
  Open blockers set `action_required`. There is no `order.action_required` webhook. Poll `GET
    	/orders/pending` instead.
</Note>

## How many domains you need

| Mailbox   | Rule                                                                                |
| --------- | ----------------------------------------------------------------------------------- |
| Microsoft | `microsoft_licenses` is the domain count. Set 25, 50, 75, or 99 inboxes per domain. |
| Google    | Set `google_licenses` to 1, 2, or 3 inboxes on every submitted Google domain.       |

```text theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
total Google inboxes = Google domains × google_licenses
```

For example, 20 Google domains with `google_licenses: 2` creates 40 Google
inboxes. Bundled orders use the `google_licenses` value saved on the bundle.
Add `quantity: 2` to buy two copies: a 20-domain bundle then requires 40
submitted domains and creates twice the inboxes. Quantity defaults to 1 and is
not valid on custom orders.

### Mixed orders

Send one flat `domains` list. Peeker assigns each domain from its `usable_for`
values. Do not label domains by mailbox type.

### Personas and usernames

Every persona needs `first_name` and `last_name`. For Google inboxes, you may
also send `usernames`, which are the mailbox names before `@`.

Peeker keeps every supplied username and generates any missing seats. If one
persona receives two Google seats and supplies `usernames: ["connor"]`, Peeker
uses `connor` for one seat and generates the other. Send
`["connor", "connorscale"]` to control both.

Supplied usernames must be unique and cannot outnumber the seats assigned to
that persona.

### Domains you already own

1. Import first with `POST /domains/import` (or the async jobs route).
2. Unimported names are treated as registration candidates.
3. Blocked domains fail before wallet debit with `domains_not_submittable`.

Common reasons: `unavailable`, `premium`, `unknown`, `provider_error`,
`already_in_use`, `stale`.

## Idempotency

| Situation                                          | Result                                                   |
| -------------------------------------------------- | -------------------------------------------------------- |
| Same body + same `Idempotency-Key`                 | Original order. No second charge. No duplicate webhooks. |
| New key                                            | New attempt.                                             |
| Domain on another active or cancel-scheduled order | `domain_already_in_active_order`                         |

On retryable `503` or `500`, keep the same key and body. An exact replay returns
`created.order: false` because it returns the existing order.

For a Smartlead Microsoft or PlusVibe
`422 provider_login_credentials_required`, repair the connected workspace
first, then retry the unchanged order with its original key. Smartlead orders
do not accept `destination.login_credentials`.

Any other field change returns `409 idempotency_conflict`.

## Pre-warmed inventory

A normal `POST /orders` request never uses or changes pre-warmed pool data. It
buys and provisions the submitted domains as a separate order.

Only `POST /pool/attach` can reserve and attach pre-warmed domains.

## Pending actions

List open blockers with `GET /orders/pending`.

| Reason                           | Meaning                                     |
| -------------------------------- | ------------------------------------------- |
| `update_nameservers`             | Customer must update DNS at the registrar   |
| `replace_domain`                 | A domain must be swapped out                |
| `profile_picture_not_accessible` | Profile image URL is blocked or unreachable |

## Cancellations

Call `POST /orders/{id}/cancel`.

| Body                   | Effect                                        |
| ---------------------- | --------------------------------------------- |
| *(omit)*               | Cancel the whole order                        |
| `{ "domains": [...] }` | Cancel only those `dom_…` IDs or domain names |

Status moves to `cancel_scheduled` immediately. Finalization is scheduled
**30 days later** (`cancels_at`), not at the renewal date.

| Cancel type                       | What happens                                            |
| --------------------------------- | ------------------------------------------------------- |
| Whole order                       | Ends in `order.cancelled` when the grace window ends    |
| Some domains, order has survivors | `order.domains_cancelled`. Order can stay active        |
| One Google domain                 | Schedules the 2-3 seats on that domain to stop renewing |

Public `costs` on the order response are not rewritten when you schedule the
cancel.
