> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# The complete_checkout tool for end-to-end agentic checkout

> Finish an in-conversation purchase with one MCP tool call: the consent gate, the channel-specific checkout rendering, the failure vocabulary, and the bounded reconcile probe.

# The complete\_checkout tool

`complete_checkout` is the in-agent MCP tool that completes a purchase inside an existing conversation. One call gates on the buyer's recorded consent, mints and renders the checkout that matches the conversation's channel, and runs one bounded reconcile probe for a paid or failed outcome. It pairs with `confirm_payment_mandate`, the tool that records the consent the gate requires.

This page is the tool contract for agent authors: what the call does, the two-phase consent flow, the channel map, the exact failure vocabulary, and what operators see in retry and sandbox contexts. For the consent model behind the gate, see [Authorization mandates](/agents/authorization-mandates). For the commerce primitives the tool orchestrates, see [Commerce checkout spine](/concepts/commerce-checkout-spine).

## What one call does

The tool takes `conversation_id` (required). Two optional arguments:

| Argument | Type | Purpose |
| - | - | - |
| `conversation_id` | string | The conversation whose cart is being checked out. |
| `channel` | string | The in-conversation channel slug. Must match the conversation's stored channel; when omitted, the tool reads the stored channel from the conversation record. |
| `tenant_hosted_pay_link` | string | An HTTPS override for the tenant's hosted pay-by-link base URL; otherwise the channel adapter's default hosted-link path is used. |

A call runs these steps in order and stops at the first failure:

1. **Resolve the conversation.** The tool reads the conversation record to get its stored channel (WhatsApp, RCS, Apple Messages for Business, or web chat). It never re-detects the channel by any other means.
2. **Check that an active cart exists.** The conversation must already carry a cart. If it does not, the tool returns `no_active_cart` and never creates a bare cart on the conversation.
3. **Gate on recorded consent.** The tool requires a fresh consent receipt from `confirm_payment_mandate` for this conversation. Without one it returns `not_confirmed` and mints nothing.
4. **Mint and render the PaymentRequest.** The tool mints a hosted PaymentRequest via `POST /commerce/payment-request` and renders it through the channel-specific adapter via `/commerce/payment-request/render`, so the buyer receives the native payload for their channel: an order details payload on WhatsApp, a hosted link on RCS, Apple Pay or a hosted link on Apple Messages for Business, or the embedded tokenized form on web chat. The tool returns the rendered payload to the agent, which relays it in the conversation.
5. **Run one bounded reconcile probe.** The tool polls `/commerce/payment-request/reconcile` once every 5 seconds for up to 10 minutes, classifying each snapshot as completed, failed, or still pending (see [Reading reconcile outcomes](#reading-reconcile-outcomes)).

On a paid outcome the tool returns the order confirmation the agent relays to the customer:

```json theme={null}
{
  "status": "completed",
  "tool": "complete_checkout",
  "order_confirmation": {
    "id": "preq_8f2ka1",
    "checkoutUrl": "https://orbit.devotel.io/pay/preq_8f2ka1",
    "amount": 49.99,
    "currency": "USD",
    "status": "paid"
  },
  "conversation_id": "conv_123",
  "channel": "whatsapp",
  "message": "Checkout completed — the PaymentRequest reconciled to `paid`. Relay this confirmation to the customer."
}
```

On a terminal failure the tool returns the reconcile reason so the agent can offer to retry from the mint step. When the 10-minute window ends without a terminal state, the tool returns `still_pending` with the open `checkout_link`: the link is still valid, so the agent tells the buyer the link remains open instead of rendering a second checkout.

## The two-phase consent flow

`complete_checkout` never asks the buyer for consent itself and never infers it from conversation text. Consent is captured in a first phase by `confirm_payment_mandate`:

1. The agent reads the cart back to the buyer verbatim: merchant, total amount, and currency.
2. The buyer gives an explicit yes to exactly that amount and merchant.
3. The agent calls `confirm_payment_mandate` with `merchant`, `amount`, `currency`, and `caller_confirmed` set to the literal boolean `true`. Anything else (absent, `false`, or a string) records nothing and returns `not_confirmed`.

A successful call records a structured, non-authorizing consent receipt in the agent runtime's in-process mandate-consent registry, scoped to the tenant and the conversation, valid for `expires_in_minutes` (default 15, maximum 1440). The receipt is evidence of the buyer's yes, not a payment authorization: it does not charge anyone and does not mint a signed mandate. Settlement is still authorized server-side against the buyer's on-file mandate, as described in [Authorization mandates](/agents/authorization-mandates).

In the second phase, `complete_checkout` checks the registry before it mints anything. If no fresh receipt exists for the conversation, the call returns `not_confirmed` with a hint, and no PaymentRequest is minted:

```json theme={null}
{
  "status": "not_confirmed",
  "tool": "complete_checkout",
  "hint": "Call confirm_payment_mandate first to capture the buyer's consent (merchant, amount, currency) with caller_confirmed=true, then retry complete_checkout.",
  "conversation_id": "conv_123",
  "channel": "whatsapp",
  "message": "No consent receipt was found for this conversation's cart. Run confirm_payment_mandate first."
}
```

The same applies when the receipt has expired: the agent re-runs the mandate flow and retries `complete_checkout`.

## Channel-specific rendering

The tool maps the conversation's stored channel to one of four supported checkout channels. There is no generic fallback: a conversation on any other channel (SMS, voice, email) returns `unsupported_channel`.

| Conversation channel | Rendered checkout |
| - | - |
| `whatsapp` | WhatsApp native pay, or the hosted pay-by-link |
| `rcs` | Hosted pay-by-link |
| `apple_messages` | Apple Pay for Apple Messages for Business, or the hosted pay-by-link |
| `web_chat` | Embedded tokenized form, or the hosted pay-by-link |

For the Apple Messages for Business setup side, see [Apple Messages commerce checkout](/guides/apple-messages-commerce-checkout).

## Failure surface

Every failure is a typed envelope the agent can branch on. The two cart and channel rejects look like this:

```json theme={null}
{
  "status": "error",
  "tool": "complete_checkout",
  "error": "no_active_cart",
  "conversation_id": "conv_123",
  "channel": "whatsapp",
  "message": "There is nothing to check out — the active cart for this conversation is empty or not yet started. Do not create a bare cart."
}
```

```json theme={null}
{
  "status": "error",
  "tool": "complete_checkout",
  "error": "unsupported_channel",
  "conversation_id": "conv_123",
  "channel": "sms",
  "message": "Checkout is not supported on this conversation's channel. Supported channels: WhatsApp, RCS, Apple Messages for Business, and web chat."
}
```

The full vocabulary, in the order a call can hit it:

| Envelope | Meaning | Agent behavior |
| - | - | - |
| `error: conversation_not_found` | The conversation is not visible to this tenant. | Do not retry; surface to the operator. |
| `error: unsupported_channel` | The stored channel is not one of the four. No generic checkout fallback is ever used. | Offer the hosted pay-by-link outside the conversation, or end the flow. |
| `error: no_active_cart` | The conversation carries no cart. A bare cart is never created. | Build the cart first, then retry. |
| `status: not_confirmed` | No fresh consent receipt from `confirm_payment_mandate`. | Run the mandate flow, then retry. |
| `error: checkout_initiation_failed` | The PaymentRequest mint or render step failed (for example a misconfigured `tenant_hosted_pay_link`). | Check the hosted pay-by-link configuration, then retry. |
| `status: failed` | The reconcile probe saw a terminal failure (`payment_reconciled_failed`). | Relay the reason and offer to retry from the mint step. |
| `status: still_pending` | The 10-minute window ended with the link still open. | Tell the buyer the link is still valid; do not render a second checkout. |

## Retry and sandbox semantics

`complete_checkout` and `confirm_payment_mandate` are registered as mutative tools. Read-only tools (such as `list_campaigns`) are retried with backoff when a call fails; mutative tools are not, because a replay after a timeout could mint a second hosted pay-by-link for the same cart or double-record the same verbal consent. Each call therefore executes exactly once. If a call times out on the client side, treat the attempt as possibly completed: check the conversation for an open payment request before invoking the tool again.

The same two tools are sandbox-blocked in the agent executor. When an agent runs in sandbox mode (test calls, eval and regression replays), the executor short-circuits the call before any dispatch and returns a deterministic, success-shaped mock envelope marked `sandboxed: true`. No PaymentRequest is minted against a live conversation, no consent receipt is recorded from a replayed "yes", and no provider traffic leaves the platform. Operators reading a sandboxed run trace see the mock envelope flagged as sandboxed, distinguishable from a genuine provider response. Read-only tools still execute normally in sandbox mode so replays keep realistic grounding.

## Payment rails boundary

Stripe is the only payment rail behind `complete_checkout`. The tool orchestrates Orbit's own in-conversation commerce stack and nothing else: the ACP storefront adapter under `/agentic/` and the UCP adapter under `/ucp/` are untouched by this tool. Those adapters serve external AI storefront discovery over A2A federation; `complete_checkout` is the in-agent path. Do not read this tool as a generic PSP abstraction.

For the external federation path, see [A2A agentic-commerce transact skill](/guides/agentic-commerce-transact): the `transact` skill is the A2A federation surface where a peer buyer agent submits a cart and mandate, while `complete_checkout` is the tool your own agent calls inside a live conversation. Both end in the same payment-request rails.

## Reading reconcile outcomes

The bounded probe classifies each polled PaymentRequest snapshot into one of three verdicts:

| Verdict | Snapshot statuses | Meaning |
| - | - | - |
| Completed | `paid`, `completed`, `succeeded` | The buyer paid; the tool returns the order confirmation. |
| Failed | `failed`, `cancelled`, `canceled`, `expired`, `declined`, `rejected`, `error` | Terminal failure; the tool returns the failure reason. |
| Still pending | anything else, including an unreadable reconcile envelope | No terminal state yet; the probe keeps polling until the 10-minute window ends. |

Two reading rules follow from that classification. A transient reconcile error (a non-200 response or an unparseable envelope) classifies as still pending, never as failed: the probe does not misreport a payment failure because a poll hiccuped. And `still_pending` at the end of the window is a terminal envelope, not an error: the hosted link is still open and the buyer can still pay on it, so the correct agent behavior is to point the buyer at the existing link rather than mint a new one.

For the endpoint reference behind each step, see the [Commerce API reference](/api-reference/commerce).

## Related

* [Authorization mandates](/agents/authorization-mandates): the consent model and the server-side charge authorization that settles what `confirm_payment_mandate` records.
* [A2A agentic-commerce transact skill](/guides/agentic-commerce-transact): the federation path for external buyer agents, as distinct from this in-agent tool.
* [Commerce checkout spine](/concepts/commerce-checkout-spine): the cart, mandate, and payment-request primitives both paths share.
* [MCP server handshake](/guides/mcp-server-handshake): how the agent connection that exposes these tools is established.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.