Skip to main content

Conversational Commerce Checkout

This guide walks a purchase end to end: a customer picks a product in WhatsApp, the order folds into one persistent cart, checkout resolves to a native in-thread payment where possible (falls back to a hosted pay-by-link otherwise), and the captured payment reconciles server-side against the cart. It closes with the abandonment hook you can use to re-engage a stalled checkout. You will:
  1. See what commerce ships
  2. Take a WhatsApp product into the cart
  3. Resolve the checkout channel — native pay or hosted pay-by-link
  4. Reconcile the payment with server-side totals
  5. Check for abandonment and re-engage
  6. Go further: mandates, carrier billing, pay links, subscriptions
All requests go to a single base URL:
Every request carries your key in the 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.

1. What commerce ships

Commerce gives you one checkout spine instead of per-channel islands:
  • One persistent cart across channels — contributions from WhatsApp catalog orders, RCS catalog carousel postbacks, Apple Messages for Business (AMB), and Instagram DM product shares fold into a single cart snapshot. A customer who adds two items on WhatsApp and one over RCS checks out once, on one cart.
  • Native in-thread checkout where it exists — WhatsApp Pay where Meta has rolled payments out (India UPI, Brazil Pix, Singapore PayNow/cards), Apple Pay inside AMB. The customer pays without leaving the conversation.
  • Hosted pay-by-link fallback — when checkout-channel returns no native option, Orbit mints a channel-agnostic hosted checkout URL. Render it for SMS, email, Telegram, Viber, or a voice-IVR readout with a QR code; it also opens cleanly in WhatsApp’s in-app browser.
  • AI-shopping storefronts — the ACP/UCP protocol surface third-party shopping agents (e.g. ChatGPT Instant Checkout, Google AP2-style agents) drive against your catalog, priced server-side.
  • Agent payment mandates — scoped, revocable, spend-capped consent that lets an AI agent complete a purchase on the customer’s behalf without re-prompting.
Every handler re-derives totals server-side, so a client-forged subtotal can never pass reconciliation. Every snapshot (cart, payment request, mandate) is a serializable object your application round-trips in the request body — the API computes the next valid state; you persist it.

2. Take a WhatsApp product into the cart

Create once, then fold channel contributions in:
The response is the cart snapshot in the browsing state. When a WhatsApp order arrives (catalog or interactive product message), merge it — value the items from the validated inbound payload, not from a client-rendered page:
Same-line contributions from different channels merge by product id (productRetailerId) and re-derive subtotal, itemCount, and lineTotal server-side. The first item moves the cart from browsing to cart_active; the returned snapshot is the source of truth — persist it verbatim. Move the buyer toward payment by advancing the state machine. Illegal transitions reject with VALIDATION_ERROR, so state bugs surface as 422s instead of dead carts:

3. Resolve the checkout channel

Ask Orbit for the ordered checkout-channel preference, restricted to the channels your tenant has connected and marked commerce-capable:
The response’s channels is an ordered preference — the buyer’s last channel leads, then the platform default order (WhatsApp, AMB, RCS, Instagram). An empty array means no channel can take the payment natively: fall back to a hosted pay-by-link. Native in-thread checkout. For a WhatsApp buyer, call POST /commerce/whatsapp-checkout; for RCS, POST /commerce/rcs-checkout. The adapter decides per buyer region and your tenant config between the native rail and the hosted fallback, and returns either a native order_details payload or a rendered hosted link — both mint the same PaymentRequest snapshot that one reconciliation endpoint closes out. Hosted pay-by-link. Mint one with POST /commerce/payment-request, then render it for the customer’s channel:
Hand the rendered content to your per-channel send infrastructure (the Commerce API produces the link content; it does not send). Send it with the same call you’d make for any text — for WhatsApp, POST /messages/whatsapp.

4. Reconcile the payment server-side

Capture the payment, then close out one transaction with one reconciliation call. Because totals are re-derived server-side, a forged subtotal never passes — match on amount + currency, not on channel. A checkout begun on WhatsApp can be paid via Apple Pay on AMB; reconciliation is cross-channel by design.
On an exact match the response returns matched: true:
On a mismatch the response says why — empty_cart, mixed_currency, currency_mismatch, or amount_mismatch — with delta carrying the signed difference (payment minus subtotal). A mismatch is terminal for that payment: refund or retry; do not advance the cart. When the payment was captured through a pay-by-link, close out POST /commerce/payment-request/reconcile with its snapshot instead; the snapshot advances to paid on an exact match. After a matched payment, advance the cart:

5. Check for abandonment and re-engage

The state machine treats abandoned as recoverable, not terminal. Check whether a cart has gone idle while still holding items in a pre-payment state:
idleThresholdMs defaults to 30 minutes (capped at 30 days) — omit it to use the default. The response returns abandoned: true, the measured idleMs, and the current state. When it comes back true, send a recovery nudge — a WhatsApp message with a rendered pay-by-link, or a catalog re-offer — then resume the cart so the follow-up merge resumes from the saved state, not a new cart:

6. Go further

The Commerce API also covers the surfaces the guide above deliberately skipped:
  • Agent payment mandates (/agent-mandate and /mpp-session) — scoped, revocable, spend-capped consent for AI-agent purchases, plus metered machine-to-machine sessions.
  • Direct carrier billing (/dcb/*) — charge to the customer’s mobile carrier bill instead of a card.
  • Hosted pay links (/payment-request/*) — the full lifecycle of the fallback link.
  • Subscriptions (/subscriptions/*) — recurring “subscribe & save” renewals that reuse the customer’s mandate.
  • AI-shopping storefronts (/agentic/*, /ucp/*) — the protocol surface for third-party shopping agents.
In the dashboard, open Messages → Commerce (/messages/commerce) for the commerce hub — the agent-mandate ledger, carrier-billing settlement, hosted pay links, AI storefront, and subscription schedule surfaces in one place. Use hub pages to watch what the API calls above mutate: pay links render their captured status, subscriptions show next-charge dates, and mandates show spend against caps.

See also