Try the live demo
See the full flow in action without setting anything up locally.
Agent Checkouts Quickstart
Explore the full reference implementation this guide is based on.
How it works
A checkout walks a simple lifecycle with no webhooks in v1 — you poll until it reaches a terminal state:- Create a checkout and get back an
id. - Poll
GET /{id}(≈ every 1.5s) as it walks the lifecycle. - Embed the live browser session in an
<iframe>so the user can watch. - Respond to each
pendingUserActionby rendering a form from the JSON Schema it carries. - Read the terminal result — a receipt on success, or a failure reason.
Prerequisites
- Node.js 20+
- A client-side API key (
ck_production_...) with the scopesagent-checkouts.create | read | update | cancel, plusagent-checkouts.buyer-profiles.create | read | update | deletefor buyer profiles - An external auth provider (e.g. Stytch, Auth0, Clerk) that issues JWTs for your signed-in users — the key alone is not enough
Setup
Get a Crossmint API key
Sign in to the Crossmint Console and create a project.Under API Keys, create a client-side key (
ck_production_...) with the agent-checkouts.create | read | update | cancel and agent-checkouts.buyer-profiles.create | read | update | delete scopes, and add your app’s origin under the allowed-origins setting. The ck_ key is public by design — it authenticates against the browser’s Origin, so restrict it with allowed-origins rather than treating it as a secret.Register your auth provider in Crossmint
Checkouts run on behalf of a signed-in user, so every request carries two credentials — your
ck_ key and the user’s JWT.In the Crossmint Console, under 3P Auth providers, register the provider whose JWTs you want Crossmint to trust. Crossmint will then accept Authorization: Bearer <jwt> headers minted by that provider.Configure your client
Point your client at the production API and send both credentials on every request.
Save a buyer profile
A buyer profile is a reusable set of the buyer’s name, contact, and shipping (there is deliberately no payment block). Save one, then attach it to any checkout so the agent fills those fields from it instead of asking every time.
Create a checkout
Give the agent a The checkout fails with
target.url, an optional request (natural-language instruction), and a required maxCost. Attach the saved profile with buyerProfileId, and save the returned id.max_cost_exceeded rather than ever spending above maxCost.The request is where you steer the agent. The more you specify up front — size, delivery option, billing address, which payment method to use — the fewer questions it stops to ask; say nothing and it surfaces a pending action for each. The one thing you can’t put here is card details — the agent always collects those through a payment user action (the step below).Poll the lifecycle
There are no webhooks in v1 — poll
GET /{id} (≈ every 1.5s) until the status is terminal. Swallow transient poll errors and retry rather than killing the loop.Embed the live browser session
The view returns a
browser.embedUrl so your user can watch (and, with write permission, interact with) the session the agent is driving.Respond to user actions
When Payment is one of these actions. When the agent reaches the payment step it raises a payment action, and you submit the card details in the
status is awaiting_user_action, the view carries a pendingUserAction with a responseSchema (a JSON Schema). Render the form dynamically from that schema — never hardcode fields — so the same code handles shipping, payment, or size selection.values you send back — you can’t pre-supply them in the create request. Submit only an agent card or a single-use / virtual card number, never a real, reusable card number (PAN): a scoped or one-time number can’t be reused if it leaks; a reusable PAN can.Why single-use and virtual card numbers are safe to submit, but a real PAN is not
Why single-use and virtual card numbers are safe to submit, but a real PAN is not
The card networks put scoped, one-time numbers outside PCI-DSS scope precisely because a leak can’t be reused:
- Visa: single-use virtual Visa account numbers are “out of scope for PCI DSS protection requirements based on the low risk of fraud,” and EMVCo payment tokens “are not considered to be Visa account data and are not in scope for PCI DSS” — while “all other Visa primary account numbers (PANs) must be protected in accordance with PCI DSS” (Expanded Position on PCI DSS Applicability for Virtual Visa Accounts).
- Mastercard: Single-Use Virtual Card Numbers are treated as out of PCI-DSS scope because the number is disabled after one authorization and cannot be reused (Virtual Card Numbers and SDP Compliance FAQs).
Next Steps
Provide Purchase Context
Buyer profiles and the buyer request — prefill identity, shipping, and intent.
Choose a Payment Method
Supported methods, and how to pass a card safely.
API Reference
The full request/response schema for every endpoint.

