# Order a data package

`POST /v1/esim/orders`

Purchases a data package at the offer's current price, locked into the order. Without `esim_id`, a new eSIM is provisioned carrying the package and install credentials become available as soon as provisioning starts. With `esim_id`, the package is added to that eSIM (a new zone stacks alongside existing packages, up to the eSIM's `package_limit`; the same zone adds a further package). Inline `delivery` is not supported. After completion, send credentials through the separate credential delivery endpoint.
Orders served from ready stock complete within the request and return `201` with `status: completed`. Otherwise the response is `202` and the order moves through its states asynchronously: poll it, or watch the eSIM's webhook events. A failed order delivers nothing and returns any charge.
The quoted price is charged to your workspace when the order is accepted. A workspace whose balance cannot fund it keeps the order in `charging`, with the order's `funding` object naming the total balance the wallet must hold (not the shortfall): top up and the charge lands on its own (retry the order to charge immediately), or cancel it. An order that stays unfunded past its funding window fails with `failure_code: insufficient_balance` and nothing is charged. Pass `offer_revision` and `expected_price` to pin the quote you displayed; a stale revision or a changed price is refused with a `409` instead of charging what the buyer did not see. When the mobile network operator cannot be reached the request fails with a `503`: retry with the same `Idempotency-Key`. When the package's validity would be cut short by the eSIM's service period, the order is refused with a `409` unless `acknowledge_shortened_validity` is set.
A top-up lands on the eSIM's own mobile network: an offer that network cannot serve is refused with a `409`, even when the same offer is orderable as a new eSIM.

## Code samples

**CLI**

```sh
bird esim orders create \
  --display-name 'Amsterdam trip, order 8812' \
  --offer-id eof_01krdgeqcxet5s7t44vh8rt9mg
```

Examples: [CLI](/docs/api/reference/create-esim-order.cli.md) · [MCP](/docs/api/reference/create-esim-order.mcp.md) · [cURL](/docs/api/reference/create-esim-order.curl.md)

## Example response `201`

```json
{
  "created_at": "2026-05-20T09:14:52Z",
  "updated_at": "2026-05-25T16:42:01Z",
  "id": "eor_01krdgeqcxet5s7t44vh8rt9mg",
  "status": "scheduled",
  "mode": "live",
  "offer_id": "eof_01krdgeqcxet5s7t44vh8rt9mg",
  "zone_id": "ezn_01krdgeqcxet5s7t44vh8rt9mg",
  "esim_id": "esm_01krdgeqcxet5s7t44vh8rt9mg",
  "subscriber_id": "esub_01krdgeqcxet5s7t44vh8rt9mg",
  "recurring_subscription_id": "ers_01krdgeqcxet5s7t44vh8rt9mg",
  "package_id": "epk_01krdgeqcxet5s7t44vh8rt9mg",
  "price": {
    "amount": "0.00995",
    "currency_code": "USD"
  },
  "wallet_transaction_id": "wtx_01krdgeqcxet5s7t44vh8rt9mg",
  "refund_transaction_id": "wtx_01krdgeqcxet5s7t44vh8rt9mg",
  "delivery": {
    "to": "traveler@example.com",
    "channel": "email",
    "locale": "pt-BR"
  },
  "funding": {
    "required_amount": {
      "amount": "0.00995",
      "currency_code": "USD"
    },
    "lapses_at": "2026-09-08T14:51:01Z"
  },
  "failure_code": "insufficient_balance"
}
```

## Request body

- `offer_id` (string, required): Offer to purchase.
- `esim_id` (string): Existing eSIM to add the package to. Omit to provision a new eSIM.
- `expected_price` (object): The price you displayed to the buyer. When set and the workspace's current resolved price differs, the order is refused with a conflict instead of charging a different amount. Catches billing-rate changes, which move independently of the offer revision.
- `expected_price.amount` (string, required): Decimal amount as a string, in major currency units.
- `expected_price.currency_code` (string, required): ISO 4217 currency code.
- `display_name` (string): Free-text label for the new eSIM, for your own reference. Ignored when esim_id is set.
- `tags` (array of object): Tags for the new eSIM, echoed on its lifecycle webhook events. Ignored when esim_id is set.
- `tags.name` (string, required): Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.
- `tags.value` (string, required): Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.
- `metadata` (object): Your own key-value data for the new eSIM, echoed on its lifecycle webhook events. Maximum 2 KB serialized. Ignored when esim_id is set.
- `acknowledge_shortened_validity` (boolean): Set to true to accept a validity cut short by the eSIM's service period. Without it, an order whose package would expire early is refused with a conflict that states the effective validity.
  - Variant `Option 1`
  - Variant `recurrence + subscriber_id + offer_revision`
    - `subscriber_id` (string, required): Person to assign the new eSIM to when delivery completes. Must be a subscriber in this workspace. Omit to leave it unassigned. Supplying it with esim_id returns 422; top-ups retain the existing assignment. An unknown subscriber or one outside this workspace returns 404 before charging. Identification guidance does not gate purchase.
    - `offer_revision` (integer, required): The offer revision you are quoting from. When set and the offer has since moved to a newer revision, the order is refused with a conflict instead of charging a price you did not see. Omitted, the current revision is used.
    - `recurrence` (object, required): Buy the first package and enable automatic renewal in one purchase. Requires subscriber_id, offer_revision and Idempotency-Key. Omit esim_id and expected_price.
    - `recurrence.recurrence_revision` (integer, required): The accepted recurring configuration revision.
    - `recurrence.accepted_price` (object, required)
    - `recurrence.accepted_price.amount` (string, required): Decimal amount as a string, in major currency units.
    - `recurrence.accepted_price.currency_code` (string, required): ISO 4217 currency code.

## Response body

- `created_at` (string, required)
- `updated_at` (string, required)
- `id` (string, required)
- `status` (string, required)
- `mode` (string, required)
- `offer_id` (string, required): Offer purchased.
- `offer_revision` (integer, required): Revision of the offer this order locked at creation. The quoted price stays that of this revision even if the offer changes later. The produced package snapshots its coverage at purchase; the zone's live country list governs new sales only.
- `zone_id` (string, required): Coverage zone of the purchased offer, captured at creation.
- `esim_id` (nullable string, required): The eSIM the package lands on. Set at creation when adding to an existing eSIM; set when provisioning starts for a new-eSIM order; null before that.
- `subscriber_id` (nullable string, required): Person accepted at creation for a new eSIM. Null when not requested, including top-ups. Delivery assigns this person atomically with the package. Cleared only during irreversible workspace deletion.
- `recurring_subscription_id` (string): The recurring service associated with this purchase. Absent for one-time orders.
- `package_id` (nullable string, required): The purchased data package, set when the order completes; null before that.
- `price` (object, required): The quoted price, locked at creation in your billing currency. A `mode: test` order quotes this price and is never charged it, so its `wallet_transaction_id` stays null.
- `price.amount` (string, required): Decimal amount as a string, in major currency units.
- `price.currency_code` (string, required): ISO 4217 currency code.
- `wallet_transaction_id` (nullable string, required): The wallet transaction that paid for this order, for reconciling against your billing transactions. Null until the charge lands, and always null for a `mode: test` order, which is never charged.
- `refund_transaction_id` (nullable string, required): The wallet transaction that credited the charge back after a failure. Null unless the order failed after charging.
- `delivery` (object): Where install credentials are delivered once available. Present when requested at creation.
- `delivery.to` (string, required): Recipient address. An email address for the email channel, an E.164 phone number for the sms channel.
- `delivery.channel` (string, required)

  Channel the install credentials are delivered over.

  Possible values: `email`, `sms`
- `delivery.locale` (string): Language for the message. Falls back to the closest available language, then English.
- `funding` (nullable object, required): Present once a charge attempt was refused for insufficient funds, while the order waits in `charging`; null otherwise. Recording the refusal details is best-effort, so a `charging` order can carry null here and still be waiting for funds. Read the required balance from billing rather than treating null as funded.
- `funding.required_amount` (object, required): The amount the wallet must hold for the charge to succeed, including tax, exactly as the billing engine reported it on the last refused attempt. The balance it was refused against is not echoed here - it goes stale the moment funds move, so read the live balance from billing.
- `funding.required_amount.amount` (string, required): Decimal amount as a string, in major currency units.
- `funding.required_amount.currency_code` (string, required): ISO 4217 currency code.
- `funding.lapses_at` (string, required): The earliest time a still-refused charge attempt fails the order with `failure_code: insufficient_balance` instead of parking it again. Not a hard expiry: a top-up landing after this time can still complete the order, right up to its next charge attempt.
- `failure_code` (nullable string, required)

  Machine-readable reason the order failed. Null unless status is failed. Open enum: treat unrecognized values as future failure kinds. canceled means the workspace canceled the order while it was waiting for funds; resolved_by_support means Bird support closed a stuck order as failed; esim_released means the top-up target became unserviceable before delivery: its eSIM was releasing, released, or failed; mode_mismatch means the offer's mobile networks changed after this order was routed, putting the order on the other side of the live/test boundary; it was failed instead of delivered, because a real purchase cannot be served by a test network and a test order cannot reserve real inventory. In every case any charge has been credited back.

  Possible values (may grow over time): `insufficient_balance`, `carrier_error`, `capacity_exhausted`, `offer_unavailable`, `internal_error`, `canceled`, `resolved_by_support`, `esim_released`, `mode_mismatch`
- `failure_reason` (nullable string, required): Why the order failed, in plain terms. Null unless status is failed.
- `completed_at` (nullable string, required): When the order reached completed. Null before that.

## Related resources

- [Should I use a Bird SDK or call the API directly?](/explained/platform/should-i-use-an-sdk-or-call-the-api-directly) (answer)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=api-basics)
