Skip to main content

Commerce API

Commerce lets a customer start shopping on one channel and finish on another — one cart, one checkout state machine, reconciled against whichever channel actually captures the payment. It also covers the “let an AI agent buy on the customer’s behalf” surfaces: scoped payment mandates, machine-to-machine metered sessions, and the storefront protocols third-party shopping agents (ChatGPT Instant Checkout, Google AP2-style agents) speak. Every handler re-derives totals and prices server-side, so a client-forged subtotal can never pass reconciliation. Every snapshot (cart, mandate, session, subscription) is a serializable object your application round-trips in the request body — this API computes the next valid state, your application is responsible for persisting it. (The conversational commerce checkout guide walks the cart → checkout flow end to end; the worked samples below extend to the agent-mandate, MPP, DCB, ACP/UCP, and subscriptions clusters.) Base path: /api/v1/commerce Authentication: API key (X-API-Key) or session JWT. Every response carries the same envelope: a data payload and a meta block with the request_id you quote when tracing a call with support.

Using the SDKs

Prefer the typed client. The Node SDK ships orbit.commerce.* helpers for the core cart surface — create, merge, transition, reconcile-payment, checkout-channel, abandonment-check — and the generic request() keeps auth/retries and the { data, meta } envelope identical for the rest of this page:
Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Raw curl in the body of this page works identically. Full SDK index at SDK quickstart.

Cart & checkout

One cart snapshot that any channel — WhatsApp Pay, RCS catalog carousels, Apple Messages for Business, Instagram DM product shares — folds contributions into. Step 1 — open the cart:
The cart snapshot you persist and round-trip in later calls:
Step 2 — drive the checkout state machine. Send the snapshot you persisted plus one event; the response is the next valid state:
An out-of-order event is refused without touching the snapshot you sent — the 422 envelope names the event that failed:
Round-trip the whole snapshot back even when the response added fields you did not send — extra keys are ignored on the way in.
A channel-agnostic hosted checkout URL — the fallback when checkout-channel returns no native option (SMS, email, Telegram, Viber, or a voice-IVR readout + QR code). Mint the link — one snapshot, reused for every channel that ends up delivering it:
Render the link for the channel you deliver on — the voice channel shapes a spoken readout, a messaging channel the short body text. A render never mutates the request snapshot; it only shapes how the URL arrives:
A channel that is not in the tenant’s capability set is refused with the same 422 envelope — the request snapshot is left untouched, so you can retry with a different channel:

In-thread channel checkout

Native checkout without the buyer leaving the conversation — WhatsApp Pay where Meta supports it (India UPI, Brazil Pix, Singapore), the hosted link everywhere else; same pattern for RCS. Resolve an in-thread checkout for the cart — the response is a PaymentRequest snapshot that either binds a native channel button or falls back to the hosted link:
native: false means Meta does not support in-thread pay for the buyer’s country — deliver the hosted URL and close out with /payment-request/reconcile; /rcs-checkout returns the same shape.

Agent payment mandates

The authorization layer that lets a voice or chat agent complete a purchase under a scoped, revocable, spend-capped consent the customer (the “principal”) issued once — modeled on the AP2 agent-payments pattern. A mandate carries a per-transaction cap, a total spend cap, an optional merchant/category allowlist, and a tamper-evident consent digest re-verified before every spend.
Dry-run a charge against the mandate — the decision is returned without advancing spend:
200 on the allow case — in-scope merchant + category, under both caps:
The deny case also returns 200 (spend never advances); the reason names the scope check that failed — a merchant off the allowlist reports merchant_not_allowed:
Other deny reasons a caller can branch on: revoked, expired, exhausted, integrity_failed (consent-digest tamper, also reported by /agent-mandate/verify), invalid_amount, currency_mismatch, category_not_allowed, exceeds_per_transaction, exceeds_total_cap. /agent-mandate/charge commits the same checks and surfaces the deny as a 422 VALIDATION_ERROR; /agent-mandate/network-token is a card-network pilot surface and is not live on most deployments — expect 503 NETWORK_TOKEN_NOT_CONFIGURED there.

Metered agent-to-agent sessions (MPP)

A pre-authorized, spend-capped, time-bounded session for machine-to-machine consumption of your own APIs or agent services — open a session once, then meter successive micropayments against it. /mpp-session/call is dark unless settlement is enabled for the deployment — an ungated call returns 503 MPP_SETTLEMENT_NOT_ENABLED. When it is on, settlement rides the x402 payment challenge: step 1 requests without a payment header and gets a 402 challenge; step 2 retries with the X-PAYMENT header and commits. Step 1 — no X-PAYMENT header → 402 challenge (spend untouched):
Step 2 — retry with the signed payment header → 200, spend commits only once settlement succeeds:
A call over the cap returns 200 with authorized: false (reason exceeds_per_call_cap or exceeds_session_cap) and settlement: null — the dry-run /mpp-session/meter exposes the same decision shape without asking for payment at all.

Direct carrier billing (DCB)

Charge to the customer’s mobile carrier bill instead of a card — merchant onboarding, the charge lifecycle, and settlement reconciliation on top of the carrier-billing network API. Initiate a charge — the merchant snapshot you configured at /dcb/merchant, plus the buyer’s number. Operator coverage is tenant-owned: onboard only the country/operator pairs your deployment actually supports (entries marked pilot are not live coverage).
Capture it once the operator dip (shaped at /dcb/operator-request) comes back confirmed:
Refund a captured charge — posting back the captured snapshot with a reason is all the route needs:

AI-shopping-agent storefronts (ACP / UCP)

The external protocol surface a third-party AI shopping agent (e.g. ChatGPT Instant Checkout) drives against your storefront: discover your catalog, open a cart/checkout session, then pay under a signed agent-payment mandate. Pricing is always re-derived server-side against your catalog, so an agent can never check out at a price you didn’t publish. Build the ACP discovery manifest — the JSON a shopping agent fetches to learn your catalog endpoints and accepted payment methods. baseUrl must be an HTTPS origin your endpoint paths join onto; categories are optional.
Running baseUrl values on .example.com are demonstrations only — publish your own origin. The UCP manifest endpoints (/ucp/manifest, /ucp/catalog) follow the same request/response shape.

Subscriptions

Recurring “subscribe & save” orders on top of one-time checkout — a schedule tracks the interval and next-charge date; each renewal reuses the same agent-payment-mandate authorization the customer already consented to, so there’s no re-prompt per cycle. Fire a due renewal — the subscription snapshot, the mandate it draws on, and the checkout config (hosted link base URL + merchant). interval is one of weekly, biweekly, monthly, quarterly; channel is whatsapp or rcs.
Success — mandate charged for the cycle, reorder checkout link minted, schedule advanced, and a commerce.subscription.renewed webhook payload returned for you to dispatch:
Renewing a paused (or not-yet-due) subscription is refused with a 422 VALIDATION_ERROR — the pause gate exists so a renewal can fire only an explicit, consented charge:
The schedule is left untouched on any refusal, so you can retry after resume or a mandate fix.

See also