Conversational Commerce Rails
The checkout guide covers one purchase flow end to end. This guide covers the five rails that flow can ride on, one worked snippet each, from first config call to a terminal state: agent payment mandates, direct carrier billing (DCB), hosted pay links, the agent-facing storefront, and recurring subscriptions. You will:- Reach each rail through the PAY-API
- Watch the rails in the console
- Handle inbound routing and lifecycle events
- Diagnose the common failure modes
- Simulate in sandbox, then cut over to live
X-API-Key header (or a session JWT). Use a sandbox key (dv_test_sk_…) while you build; swap in a live key (dv_live_sk_…) for production. Every rail round-trips a serializable snapshot — the API computes the next valid state; you persist the returned snapshot verbatim.
1. PAY-API ergonomics
1.1 Agent payment mandates — the consent token lifecycle
A mandate is a scoped, revocable, spend-capped consent token that lets an AI agent complete a purchase on a customer’s behalf without re-prompting. Issue it once:/agent-mandate/authorize (returns the decision without advancing spend), commit it with /agent-mandate/charge (advances spend and returns the updated snapshot + authorization + an AP2 verifiable credential), check integrity with /agent-mandate/verify (recomputes the consent digest — tamper evidence for auditors), and withdraw consent with /agent-mandate/revoke (terminal). To settle on a card network’s agentic program instead of a hosted link, present the authorized charge to /agent-mandate/network-token (Mastercard Agent Pay or Visa Trusted Agent Protocol).
VALIDATION_ERROR; a successful authorize/charge response carries reason: "ok" and, when settlement runs, an x402 settlement receipt with network + transaction hash.
1.2 DCB — confirm code relay, capture, settlement
Direct carrier billing charges the customer’s mobile operator bill instead of a card. Onboard the merchant first — settlement currency, a digital-goods category, a per-transaction cap, and the tenant-level coverage map of country+operator pairs (live, pilot, unsupported — only live pairs may be charged):
/dcb/operator-request (passes the raw MSISDN — it never lands on the snapshot) and submit it to the carrier-billing route. When the buyer replies with the confirm code, capture with /dcb/charge/capture (partial capture honoured); on decline, mark /dcb/charge/fail. Refund with /dcb/charge/refund (partial → partially_refunded, full headroom → refunded); record an operator-initiated reversal with /dcb/charge/chargeback. Close the batch with /dcb/reconcile, which matched/mismatched/missing/unexpected-flags the operator settlement records and advances matched charges to their settled form.
1.3 Pay links — mint, render, TTL, reconcile
A hosted pay-by-link is the channel-agnostic fallback every checkout guide reaches when no native wallet exists. Mint it, render it for the buyer’s channel, drive its lifecycle (MARK_VIEWED / MARK_PAID / EXPIRE / CANCEL), and reconcile the captured PSP payment:
expiresAt is the TTL you set — past it, /payment-request/transition with EXPIRE moves the request to expired (terminal). Hand the rendered content to your per-channel send call; the Commerce API produces link content only. When the PSP webhook reports the capture, close the request out:
paid — the terminal state.
1.4 Storefront — publish the agent-facing catalog wiring
The storefront is the tenant-owned surface a third-party AI shopping agent (ChatGPT Instant Checkout, Perplexity, AP2) discovers and drives with no Orbit credential. Publish (or replace) the stored config once — merchant name, currency, categories, and a bounded catalog (max 250 products):storefrontId, the publicUrl you hand to a shopping agent, and the normalized discovery manifest. From then on the public edge serves the manifest + product feed with no further calls from you; read the stored config back with GET /commerce/agentic/storefront. A shopping agent opens a checkout (/agentic/checkout), prices it server-side against your catalog, and completes it under a signed mandate (/agentic/checkout/complete) — your tenant-owned controls govern the catalog, the mandate scope, and whether the storefront is published at all. (A UCP-native agent uses the same primitives on the /ucp/* paths; that adapter is a design-partner pilot gated per tenant.)
1.5 Subscriptions — renewal cadence and dunning
A subscription reuses the consent the customer already gave as a mandate, so a renewal collects no new consent. Start it off an existing cart with an interval (weekly, biweekly, monthly, quarterly) and a channel (whatsapp or rcs):
/subscriptions/list to annotate and sort a set by next-charge date (soonest first). When a cycle falls due, run the dunning cadence — the renewal re-authorizes against the stored mandate and mints the reorder’s checkout:
webhookEvent your subscriber consumes (event, cycleNumber, chargeReference, nextChargeAt). A declined charge returns VALIDATION_ERROR — the dunning loop retries the renewal against a re-issued mandate instead of advancing the schedule. Pause/resume/cancel move the lifecycle; a nextChargeAt that fell in the past while paused is re-anchored one interval out on resume, so resuming never fires a backlog.
2. Console walkthrough
In the dashboard, open Messages → Commerce (/messages/commerce). The hub page links the five rail consoles — Agent mandate, DCB, Pay links, Storefront, Subscriptions — and the message side rail lets you jump from any conversation thread into the rail page the thread’s charge rides on. Use the consoles to watch what the API calls above mutate:
- Agent mandate — the consent ledger: scope, spend against caps, active/exhausted/revoked status, and the network-token mints a charge produced.
- DCB — operator-billed charges by country+operator, their lifecycle state (
initiated→captured/failed→refunded/charged_back), and the settlement reconciliation result (matched/mismatched/missing/unexpected). - Pay links — every minted link with its rendered channel, TTL expiry, and the history view of each charge’s status (
pending→viewed→paid/expired/cancelled) plus the PSP reconciliation reference. - Storefront — the published config a shopping agent sees: merchant details, categories, the catalog the public edge serves, and the public URL.
- Subscriptions — the schedule with next-charge dates and the renewal ledger (
cyclesCompleted, the last renewal reference, pause/resume/cancel state).
paid snapshot with the PSP reference; for a subscription, the last successful renewal cycle.
3. Inbound routing and lifecycle events
- DCB confirm-code reach — the operator sends the buyer an SMS with a confirmation code; the buyer’s MO reply routes through Orbit’s inbound messaging and your application submits the confirming dip to the carrier-billing route before you
/dcb/charge/capture. An unanswered confirm code leaves the chargeinitiateduntil you/dcb/charge/failit. - Subscription opt-out on cancel — when a buyer texts a stop keyword or cancels in-thread, cancel the schedule with
/subscriptions/cancel(terminal) and let your normal opt-out suppression take the number — the rail stops renewing and the consent surface (the mandate) should be revoked with/agent-mandate/revoketoo. - Charge-refund webhook events — for pay links the PSP webhook closes the request via
/payment-request/reconcile; for subscriptions each renewal emits thewebhookEventobject above; for DCB a refund or chargeback the operator reports is recorded with/dcb/charge/refundor/dcb/charge/chargebackso the settlement report flags it.
4. Common failure modes
- Carrier rejects a DCB charge — the merchant coverage map lists the country+operator pair as
pilotorunsupported, or the amount exceedsmaxChargeAmount./dcb/chargerejects withVALIDATION_ERROR; either route the buyer to a pay link or update the merchant coverage to alivepair. A charge the operator declined mid-flight is terminalfailedvia/dcb/charge/fail. - Mandate token expiry — a charge against an
expired(or cap-exhausted) mandate returnsauthorized: falsewith the reason. Re-issue a fresh mandate off the customer’s new consent, or fall back to a hosted pay link. For a card-network fallback the/agent-mandate/network-tokenroute returns 503NETWORK_TOKEN_NOT_CONFIGUREDwhen the program is not provisioned — fall back to/agent-mandate/charge. - Pay-link TTL — once
expiresAtpasses, lifecycle transitions other thanEXPIREreject. Mint a fresh link; never resurrect an expired one (the history view shows it terminal). - Storefront schema validation — a
PUT /agentic/storefrontbody missing a required product key (productId,title,price,currency) or over the 250-product bound rejects withVALIDATION_ERROR. A checkout completion whose re-priced total exceeds the mandate scope is rejected so an agent can never spend past signed consent. - Subscription renewal declined —
/subscriptions/renewvalidates the schedule is active and due and the mandate authorizes the charge; a mandate decline or a not-due schedule returnsVALIDATION_ERROR. Re-issue consent, then retry — do not advance the schedule on a declined cycle.
5. Sandbox and live cutover
Build each rail against a sandbox key (dv_test_sk_…) end to end:
- Mandate — issue, dry-run authorize, commit a charge, verify the digest, revoke. The terminal state is a settled authorization with an AP2 credential.
- DCB — configure the merchant with a
livecoverage pair, initiate a charge, build the operator request, capture it, then reconcile it against a synthetic settlement record. Terminal: a reconciled report withreconciled: true. - Pay link — mint, render for a test channel, mark viewed, reconcile a synthetic PSP capture. Terminal:
paid. - Storefront — publish the config, fetch the public URL, run a sandbox shopping-agent session against the manifest + feed, complete the checkout under a test mandate. Terminal: a
completedcheckout session. - Subscription — start, list, fire one renewal cycle, cancel. Terminal: the
canceledschedule with the finalwebhookEventrecorded.
dv_live_sk_…, point hostedBaseUrl at the production payment host, and for DCB replace the synthetic coverage map with the operator pairs your carrier agreement actually provisions (tenant-level, per country+operator — there is no global gate). Sandbox snapshots are yours to discard; live snapshots are the record you persist.
See also
- Conversational Commerce Checkout — the end-to-end checkout thread this guide’s rails plug into
- Checkout spine concept — why one cart resolves across surfaces
- Commerce API reference — every endpoint and field
- Opt-out lists — the suppression a subscription cancel defers to