Skip to main content
POST
Error

Authorizations

Authorization
string
header
required

The control surface credential. Send Authorization: Bearer <token>.

Two kinds of token are accepted and they are told apart by shape, not by a separate header. A token beginning pbk_ is an org scoped API key, whose public half and secret half are generated together and of which only a hash of the secret is ever stored; anything else is treated as an OAuth 2.1 access token and verified against the authorization server's keys.

Both resolve to the same context: an org, a principal and a set of scopes. Nothing downstream branches on which channel you used, with one deliberate exception, key management, which requires a signed-in person so that a key can never mint another key.

Scopes are enforced when MCP tools are REGISTERED rather than when they are called, so a tool your credential cannot use is absent from tools/list rather than refused mid gesture.

Headers

Idempotency-Key
string

A key of your own, unique to this attempt, so a retry cannot buy twice. Send the SAME value on every retry of one purchase; up to 255 printable ASCII characters, and a random uuid is the usual choice.

With a key, a retry within 24 hours is answered with the ORIGINAL answer, the same checkout url and the same order id, and nothing new is created. Without one, a retry supersedes: the session you may already have open is expired and a different one is minted, which is safe for your money and inconvenient for whoever is looking at the old tab.

Reusing a key you already sent with a DIFFERENT purchase is refused rather than answered, because the alternative is handing you a link to the wrong thing.

Maximum string length: 255

Body

application/json

What to buy, or nothing at all. See the description for what an absent body means.

What to buy. Fields this service does not know are IGNORED, not refused: the route reads sku, billing, model, quoteId, region, quantity and addOns and drops everything else.

sku
enum<string>
required

What to buy. Must be one this deployment prices; see GET /v1/skus.

Available options:
emulator,
cloud_phone,
phone_robot_android,
phone_robot_ios
billing
enum<string>
required

How to pay for it.

Available options:
subscription,
payg,
day
model
string

Which model of that sku, by the id of one of the models the matching GET /v1/skus row listed. Required for monthly Cloud phone checkout; other pairs may omit it. Send an id the deployment did not declare and the answer is 400 invalid_argument. A supplier-listed monthly Cloud model with backorderable: true may be paid for while sold out. An unresolved supplier goodId is refused before payment. Validated against the current server catalog, never the copy a client holds.

Required string length: 1 - 64
quoteId
string

The quoteId published beside the selected model in GET /v1/skus. Required for a priced model; the server checks it against its current Price before creating an order or a payment session. Never an amount and never trusted as the charge source.

addOns
object

Add-on intents, Cloud phone with a model only. STRICT, unlike the body: an unknown key or a non-boolean value is 400 invalid_argument. Recorded on the order; nothing here changes the charge.

quantity
integer

How many phones of the chosen model, 1 to 20. Optional, legal only beside a model; absent means one. Respect the matching catalog entry's maxQuantity: modern Cloud first-month payments support up to three; all other plans support one. A larger value is refused before an order or payment exists. One Stripe payment creates separately tracked units, each with its own delivery, term and bounded refund.

Required range: 1 <= x <= 20
region
string

Where to place that model, by the code of one of the regions the chosen model listed on GET /v1/skus: an upper-case ISO 3166-1 alpha-2 code. Optional, and legal only beside a model that lists regions: send it for a model with no regions and the answer is 400 invalid_argument ("No region can be chosen for this model; omit region."); send a code the model did not list and the answer is 400 naming the codes it does. A listed sold-out region may be purchased as a Cloud backorder. Omit it and the deployment's default region for that model applies; an unlisted default is refused before payment.

Pattern: ^[A-Z]{2}$

Response

A started purchase. A named sku is fulfilled from a unit of THAT kind and no other, so a customer is never handed something other than what they paid for; if none is free the purchase still succeeds and the device is promised (see shipsNow on GET /v1/skus).

A started purchase.

checkoutUrl
string
required

Where to send the browser to complete the purchase. Single use, and it expires.

orderId
string
required

This attempt's order id, echoed so a caller can correlate.

expiresAt
string<date-time>
required

After this the URL stops being payable and a fresh attempt is needed.

quantity
integer
Required range: 1 <= x <= 3
fulfilmentIds
string[]

Stable opaque per-phone identifiers, committed as fulfillments only after verified payment. Quantity-one keeps its existing order identifier.

Required array length: 1 - 3 elements