Skip to main content

Create a checkout

Success: 201.

Headers

string
Makes this create safe to retry. A second POST with the same key returns the original checkout with 200 instead of starting a second run; the same key with a different body is a 409.Strongly recommended on every create. Without it, a POST that times out after we accepted it is indistinguishable from one that never landed, and the retry buys the item twice. Empty or whitespace-only is treated as absent.A key lives 24 hours from the creation of the checkout that claimed it. After that it is released and the same string starts a new purchase.See Idempotent creates below and Idempotency.

Body

The top level is strict: an unknown field is a 400, not a field we drop for you. A misspelled subjectt would otherwise have returned 201 with an untagged checkout the whole account can read. target, constraints and metadata stay permissive inside — they are extension points.
400 — a misspelled field
object
required
string
UUID of a buyer profile you own. Must exist and belong to your tenant, or you get 400 buyerProfileId not found.It is checked against this checkout’s subject, not the key’s. A subject-bound key reaching for another end user’s profile gets that same 400 — from where it stands the profile does not exist. A tenant-wide key naming one end user’s profile alongside another’s subject gets a 403 that names both. An untagged profile on a tagged checkout is allowed, and so is the reverse.Without one the agent has no address or email, and most checkouts cannot be completed.
string
Your own id for the end user this purchase is for. 1 to 200 characters after trimming, opaque to us, never sent to the merchant. Comes back on the checkout when set, and omitted when not.Empty or whitespace-only is a 400 — a subject that means nothing is worse than none, because it reads as isolation you do not have.On a subject-bound key this is filled in for you: omit it and the checkout is stamped with the key’s subject; name a different one and the request is a 403. On a tenant-wide key it is how a row gets tagged in the first place, and how you can later filter the list with ?subject=.It also namespaces the Idempotency-Key — two end users may use the same key string without colliding.
object
default:"{}"
object
default:"{}"
Arbitrary JSON, stored and echoed back on every read. Never sent to the merchant, never interpreted by us, not searchable. Use it to carry your own order reference.

Response

201 with the full checkout object, in status queued, already carrying the intent_started progress item.

Idempotent creates

With an Idempotency-Key header, this endpoint has a second success code: The body is hashed with its keys sorted and its defaults applied, so key order does not matter and "constraints": {} matches an omitted constraints. Keys live in a (tenant, subject) namespace and expire 24 hours after the checkout that claimed them was created — released by an hourly sweep, so the boundary is approximate to within an hour.
409
Two concurrent retries of the same request do not race into two purchases: the database picks a winner and the loser returns the winner’s checkout with 200. A replay is checked before the quota, so it does not consume one of your active-checkout slots, and does not launch a second browser. It is checked after URL, sandbox, subject and buyer-profile validation, so a replay whose target has since become unreachable — or whose buyer profile has since been deleted — can still return 400 rather than the checkout you expected.
This is idempotency of the call, not of the run. Once a checkout is failed, its key returns that failure until the key expires. Retrying for real means a new checkout and a new key.

Errors

403
Confinement is checked against target.allowedDomains as well as target.url — the offending host named in the message may be either.

Get a checkout

Success: 200.
This is the object you poll, and it is the same shape returned by create and by submitting an action.
string
required
UUID.
string
required
queued · running · awaiting_user_action · succeeded · failed · cancelled.
string
Omitted when the checkout is not tagged to an end user. Your own id when it is — set explicitly at creation, or stamped from the key’s binding. See End-user isolation.
object
required
Exactly what you sent, plus kind: "direct_url".
object
required
{} if you sent none.
string
Omitted when the checkout has no buyer profile.
object
required
{} if you sent none.
object
Omitted until a browser session exists.
Its presence means “a browser exists and there is something to watch”. embedTokenUrl points at the endpoint that mints a viewable URL; it is not viewable itself.
array
required
Every event so far, ordered by sequence ascending. Each item is { kind, label, data, at, sequence }. See the timeline.
object
Omitted unless an action is pending right now.
Always absent on a terminal checkout — cancelling or failing a run expires any question still open, so succeeded, failed and cancelled never advertise a pending action.detectedTotal is what the merchant’s own checkout says this order costs — shipping and tax included — read off the live page at the moment the run stopped to ask. Present on card actions. Show it to your user before you answer: after that the money has moved, and receipt.total only exists once the checkout has succeeded, which is too late to be a confirmation step. It is best-effort, so treat it as optional — omitted entirely when no total could be parsed, and currency can be absent when the page shows a bare number. A confident wrong price would be worse than no price, so nothing is guessed.See User actions.
object
Omitted unless the run failed. { "reason": "automation_failed" } — one of max_cost_exceeded, user_cancelled, user_action_expired, automation_failed. The detail message is on the final terminal progress item, not here.
object
Omitted unless status is succeeded.
total and merchantOrderId may be null. See the receipt.
string
required
ISO 8601.
string
required
ISO 8601.

Errors

404 Checkout not found — including when it belongs to another tenant, or to another end user on a subject-bound key.

List checkouts

Success: 200.

Query

integer
default:"20"
An integer from 1 to 100. Anything else is a 400.
string
The nextCursor from the previous page — an ISO timestamp. Returns checkouts created strictly before it. A value that is not a timestamp is a 400.
string
Filter to one status. An unrecognised value returns 400 Unknown status 'x'.
string
Filter to one end user. Composes with status, limit and cursor; a subject with no checkouts is an empty page, not an error.On a subject-bound key the page is already narrowed to its own end user, so the parameter is redundant. Passing its own subject is fine; naming a different one is a 403 — refused rather than quietly ignored.

Response

Deliberately a summary, not the full object. The full shape carries the entire event timeline, which is exactly what a list view must not fetch.
string
Omitted when the checkout is not tagged to an end user — the same convention as the full object. The third row above is an untagged checkout.
string | null
Lifted from target.url.
string | null
Lifted from target.request.
object
Omitted unless failed.
object
Omitted unless a receipt exists. Note this is the short form — { total, merchantOrderId } with no evidence.
string
Omitted unless an action is pending. The id only — fetch the checkout for the message and schema.
string | null
Pass back as ?cursor=. null on the last page.
A subject-bound key sees only its own end user’s checkouts here — other people’s runs are absent from the page rather than redacted out of it. A tenant-wide key sees everybody’s, tells them apart by the subject on each row, and narrows to one with ?subject=.

Cancel a checkout

Success: 202.
Returns 202 with an empty body. Cancellation is asynchronous. It stops the run even while it is parked on a user action, flips the row to cancelled, and reclaims the browser. Poll, or wait for the checkout.status_changed webhook, to observe the terminal state. A DELETE on an already-terminal checkout also returns 202 and does nothing. The 202 acknowledges the request, it does not assert an outcome. 404 Checkout not found if it does not exist or is not yours.
Not an undo. If the pay click has already landed, cancelling stops our automation but does not unwind an order the merchant has accepted.

Mint a live-view token

Success: 200.
string
HS256 JWT pinned to this checkout id, valid 10 minutes.
string
Ready to drop into an <iframe src>. Contains the token.
string
ISO 8601. No refresh — mint a new token when it lapses.
Body is ignored; no parameters. 404 Checkout not found if it is not yours. See Live view.