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

# UCP Checkout: Cart Creation and Payment Integration

> Implement the UCP checkout flow — cart creation, order confirmation, shipping options, payment token handling, error responses, and PSP integration.

UCP checkout is a two-step flow: the agent first creates a cart session and receives shipping options, then confirms the order with a payment token from your payment service provider (PSP). Your backend owns all payment logic — UCP defines the request and response shape, not the payment infrastructure. This design means you can integrate whichever PSP you already use.

## How the checkout flow works

```
Agent                               Your backend
  │                                      │
  ├─ POST /ucp/checkout ────────────────►│  (cart + shipping address)
  │◄──── checkout_id, shipping options ──┤
  │                                      │
  ├─ POST /ucp/checkout/:id/confirm ────►│  (shipping choice + payment token)
  │◄──── order_id, confirmation ─────────┤
  │                                      │
  ├─ GET /ucp/orders/:order_id ─────────►│  (status check)
  │◄──── order status, tracking ─────────┤
```

## Step 1: Cart creation

The agent sends a `POST` to `/ucp/checkout` with the cart items and shipping address:

```json theme={null}
// POST /ucp/checkout
{
  "items": [
    {
      "product_id": "prod_123",
      "variant_id": "var_123_10_black",
      "quantity": 1
    }
  ],
  "shipping_address": {
    "name": "Jane Smith",
    "street": "123 Main St",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94102",
    "country": "US"
  }
}
```

Your backend responds with a checkout session ID, shipping options, tax, and an expiry timestamp:

```json theme={null}
{
  "checkout_id": "chk_abc123",
  "subtotal": { "amount": 12999, "currency": "USD" },
  "shipping_options": [
    {
      "id": "standard",
      "name": "Standard Shipping (5-7 days)",
      "cost": { "amount": 599, "currency": "USD" }
    },
    {
      "id": "express",
      "name": "Express Shipping (2 days)",
      "cost": { "amount": 1499, "currency": "USD" }
    }
  ],
  "tax": { "amount": 1170, "currency": "USD" },
  "expires_at": "2026-04-10T12:30:00Z"
}
```

### Cart request fields

<ParamField body="items" type="array" required>
  Array of cart line items. Each item must include `product_id`, `variant_id` (if applicable), and `quantity`.
</ParamField>

<ParamField body="items[].product_id" type="string" required>
  The `id` of the product from your catalog endpoint.
</ParamField>

<ParamField body="items[].variant_id" type="string">
  The `id` of the specific variant. Required for products with variants — omit only for products with no options.
</ParamField>

<ParamField body="items[].quantity" type="integer" required>
  Number of units. Must be a positive integer.
</ParamField>

<ParamField body="shipping_address" type="object" required>
  Customer's shipping address. Used to calculate applicable shipping options and tax.
</ParamField>

<ParamField body="shipping_address.name" type="string" required>
  Recipient's full name.
</ParamField>

<ParamField body="shipping_address.street" type="string" required>
  Street address including house number.
</ParamField>

<ParamField body="shipping_address.city" type="string" required>
  City name.
</ParamField>

<ParamField body="shipping_address.state" type="string" required>
  State, province, or region code (e.g. `"CA"`, `"NY"`).
</ParamField>

<ParamField body="shipping_address.zip" type="string" required>
  Postal or ZIP code.
</ParamField>

<ParamField body="shipping_address.country" type="string" required>
  ISO 3166-1 alpha-2 country code (e.g. `"US"`, `"GB"`, `"IN"`).
</ParamField>

## Step 2: Order confirmation

The agent sends the customer's chosen shipping option and a payment token obtained from your PSP's client-side SDK:

```json theme={null}
// POST /ucp/checkout/:checkout_id/confirm
{
  "shipping_option_id": "standard",
  "payment_method": {
    "type": "card",
    "token": "tok_visa_4242"
  }
}
```

Your backend processes the payment and returns the confirmed order:

```json theme={null}
{
  "order_id": "order_xyz789",
  "status": "confirmed",
  "total": { "amount": 14768, "currency": "USD" },
  "estimated_delivery": "2026-04-17",
  "confirmation_number": "ORD-2026-XYZ789"
}
```

## Payment provider integration

UCP is payment-provider-agnostic. Integrate the PSP you already use.

<Tabs>
  <Tab title="Stripe">
    Create a PaymentIntent when the agent confirms the order:

    ```javascript theme={null}
    const paymentIntent = await stripe.paymentIntents.create({
      amount: total.amount,
      currency: total.currency.toLowerCase(),
      payment_method: paymentToken,
      confirm: true,
      return_url: `https://yourstore.com/orders/${orderId}`
    })

    if (paymentIntent.status === 'succeeded') {
      // Fulfill the order
    }
    ```
  </Tab>

  <Tab title="Razorpay">
    Create a Razorpay order and capture payment using one-time authorization for the agentic flow:

    ```javascript theme={null}
    const order = await razorpay.orders.create({
      amount: total.amount,
      currency: total.currency,
      receipt: `ucp_${checkoutId}`
    })

    // See the Razorpay Agentic Payments guide for one-time auth capture
    ```
  </Tab>

  <Tab title="PayPal">
    Create and capture a PayPal order:

    ```javascript theme={null}
    const paypalOrder = await paypalClient.execute(
      new paypal.orders.OrdersCreateRequest({
        intent: 'CAPTURE',
        purchase_units: [{
          amount: {
            currency_code: total.currency,
            value: (total.amount / 100).toFixed(2)
          }
        }]
      })
    )
    ```
  </Tab>
</Tabs>

## Error responses

Return structured error objects so agents can relay accurate information to the customer and, where possible, recover automatically.

### Payment failure

```json theme={null}
{
  "error": {
    "code": "payment_failed",
    "message": "Payment method declined. Please try another card.",
    "retryable": true
  }
}
```

### Out of stock at confirmation

```json theme={null}
{
  "error": {
    "code": "out_of_stock",
    "message": "Running Shoes — Size 10 Black is no longer available.",
    "items": ["var_123_10_black"],
    "retryable": false
  }
}
```

### Invalid shipping address

```json theme={null}
{
  "error": {
    "code": "invalid_address",
    "message": "Shipping address could not be validated.",
    "fields": ["zip"],
    "retryable": true
  }
}
```

<Tip>
  Write error `message` values as human-readable sentences. The agent will read them directly and relay them to the customer. "Size 10 Black is sold out" is far more useful than `"variant_unavailable"`.
</Tip>

## Security requirements

<Warning>
  Never store raw card numbers or full payment details in your systems. Always use tokenized payment methods from your PSP's client-side SDK.
</Warning>

* Serve all checkout endpoints over HTTPS
* Validate all incoming request fields — item IDs, quantities, addresses — before processing
* Implement idempotency keys to prevent duplicate orders if the agent retries a request
* Re-check inventory availability at confirmation time, not just at cart creation
* Never handle raw card data directly; accept only PSP-issued payment tokens

## Best practices

<AccordionGroup>
  <Accordion title="Re-validate inventory at confirmation">
    Inventory can change in the minutes between cart creation and order confirmation. Always check stock again before processing the payment — not just when the cart session is opened.
  </Accordion>

  <Accordion title="Set and return session expiry">
    Cart sessions should expire after 15–30 minutes. Include `expires_at` in your cart response so agents know when the session becomes invalid. If an agent tries to confirm an expired session, return a clear error with `code: "session_expired"`.
  </Accordion>

  <Accordion title="Return actionable error messages">
    Error messages are read directly by the AI agent and presented to the customer. Descriptive messages reduce confusion and help agents offer next steps (e.g. suggesting an alternative size or payment method).
  </Accordion>

  <Accordion title="Send fulfillment webhooks">
    Once an order is placed, push fulfillment and tracking updates via webhook so the customer receives proactive shipping status inside the AI conversation — without needing to check their email.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="ACP checkout guide" icon="robot" href="/acp/checkout-guide">
    Implement ChatGPT Instant Checkout via the Agent Commerce Protocol.
  </Card>

  <Card title="Razorpay agentic payments" icon="indian-rupee-sign" href="/guides/razorpay">
    UPI-native agentic payments for Indian merchants.
  </Card>
</CardGroup>
