Create order
POST/api/v1/orders
Creates a new order.
Request body:
ordersType="shop": purchase vouchers/codes.ordersType="dtu": direct top-up (no voucher codes; DTU attributes are returned).ordersType="dtu"+checkOnly=true: validate top-up (quote + provider check) without creating an order.ordersType="steam-gift": Steam Gift purchase (requiresquoteTokenfromPOST /steam-gifts/quotes,referenceId, exactly one gift,recipient_region+invite_url/profile_urlfields). Feature-gated default-off. Strict same-key/same-payload idempotency (payload conflict → HTTP 409).
referenceId is required for purchases (checkOnly=false) and acts as an idempotency key (unique within your account). If the same referenceId is sent again, the API returns the original result with statusCode=IDEMPOTENCY_REPLAY (even if the request body is different; exception: ordersType="steam-gift" requires the same canonical payload or returns HTTP 409).
If the purchase is accepted for asynchronous processing, the endpoint returns HTTP 202 and status=IN_PROGRESS. Poll GET /orders by orderId or referenceId until a terminal status.
eSIM orders (ordersType="esim")
- One purchase = exactly one eSIM (
quantityis always 1). - eSIM orders are always priced and settled in USD.
- Required scopes:
product:readfor the catalog,orders:writefor this endpoint andorders:readfor polling — there is no separateesimscope. - The activation payload (
result.esim:qrCodeText,iccid,smdpAddress,activationCode,iosInstallUrl,androidInstallUrl, ...) is usually issued asynchronously by the supplier. When it is not ready yet, the endpoint returns HTTP 202 withstatus=IN_PROGRESS,result=nulland aRetry-After: 15header. - Polling guidance: repeat
GET /orders?referenceId=...every 10–15 seconds. The upstream finalize sweep runs about once per 60 seconds, so the payload typically appears within 1–2 minutes. Treat ~10 minutes ofIN_PROGRESSas a timeout and contact support with theorderId— do NOT re-submit the purchase with a newreferenceId. - Replaying this POST with the same
referenceIdis also safe: it returns the refreshed state (statusCode=IDEMPOTENCY_REPLAY) without creating a second order.
Rate-limit / spend-cap responses (important)
There are two distinct refusal paths that historically looked identical to clients. They are now separated by HTTP status and statusCode:
- HTTP 429 /
statusCode=LIMIT_REACHED(8) — a true per-window rate limit (the per-endpoint counter or an upstream shop-service rate-limit). Safe to retry with back-off once the window resets. - HTTP 409 /
statusCode=API_KEY_LIMIT_EXCEEDED(13),errorCode="api_key_transaction_limit_exceeded"— the API key's statictransactionLimitcannot accommodate the quoted order amount. NOT a rate limit; retrying will keep failing. Raise the cap (or resettransactionUsed) through the control plane. The response message includes the attempted amount, the remaining headroom and the configured limit. - HTTP 429 /
statusCode=LIMIT_REACHED(8) can also be returned for a brief, self-resolving moment when several orders on the same API key are created concurrently and momentarily contend on the key's spend-counter row. The response carries aRetry-Afterheader (typically1); the order was NOT created and did NOT consume quota. Simply retry after the delay. (Previously this surfaced as HTTP 502 — clients should treat 429 here as retryable rather than a server failure.)
Provider availability (checkOnly=true)
DTU validation (ordersType="dtu" + checkOnly=true) is forwarded synchronously to the underlying provider via shop-service. When the provider does not respond within the tightened read budget, Public API retries the call once with a short jittered backoff. If the retry also times out, the response is:
- HTTP 504 Gateway Timeout /
statusCode=PROVIDER_UNAVAILABLE(14) — the provider failed to answer twice in a row. The response carries aRetry-After: 2header; safe to retry after that delay. The request did NOT debit funds and did NOT create an order. - HTTP 429 /
statusCode=LIMIT_REACHED(8) — Public API limits thePOST /orders (check)bucket to 120 requests / 60 seconds per account (shared by every API key on it).statusMessagenames that bucket and the response carriesRetry-After: 60; wait that long before retrying. This budget applies to the pre-check ONLY: creating an order is deliberately not throttled by this bucket, and the same validation runs during creation, so a non-essential pre-check can be skipped rather than retried.
Request
Responses
- 200
- 415
- 422
Successful Response
Unsupported media type. Clients must send Content-Type: application/json.
Validation Error