# Use your own checkout

Run your own Universal Commerce Protocol checkout and accept Stripe payments with the Stripe Payments handler.

If you already run a checkout that follows [Universal Commerce Protocol](https://docs.stripe.com/agentic-commerce/protocols/ucp.md) (UCP), you can use Stripe only for payments. Agents get a payment credential through the Stripe Payments handler, send it to your checkout, and you charge it with Stripe. UCP supports several transports, including REST and Model Context Protocol (MCP).

For how to implement the UCP endpoints and publish your UCP profile, see the [UCP specification](https://ucp.dev). This page covers the Stripe-specific parts.

Use this guide if you:

- Run, or plan to run, your own UCP checkout.
- Want to accept agent payments with Stripe.

## Before you begin

To accept Stripe payments in your own UCP checkout, you need:

- A [Stripe account](https://stripe.com/register) with a [Stripe profile](https://docs.stripe.com/get-started/account/profile.md). Agents use your profile ID (`profile_...`) to issue payment credentials to you. Find it in the [Dashboard](https://dashboard.stripe.com/profiles).
- A UCP checkout, built to the [UCP specification](https://ucp.dev), that accepts a payment instrument when the agent completes the checkout.
- A confirmed commerce relationship with each agent, in the same environment. The Stripe Payments handler requires it before an agent can tokenize a card.

## Advertise the Stripe Payments handler

Declare the `com.stripe.payments` handler in your UCP profile. Set `config.business_profile` to your Stripe profile ID and `config.environment` to `sandbox` or `production`. For the handler declaration, the supported instruments, and the configuration fields, see the [Stripe Payments handler](https://docs.stripe.com/agentic-commerce/protocols/ucp/stripe-payments-handler.md#discovery).

For Apple Pay, advertise the `apple_pay` instrument in the same handler. For Google Pay, advertise the `com.google.pay` handler instead, because `com.stripe.payments` doesn’t provide a Google Pay completion flow. Wallet tokens aren’t SPTs, so see [Wallet flows](https://docs.stripe.com/agentic-commerce/protocols/ucp/stripe-payments-handler.md#wallets) for each credential format.

## Accept programmatic payments

Agents use the Stripe Payments handler to get a [Shared Payment Token](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md) (SPT) for the customer’s payment method. For cards, the agent exchanges the card details for an SPT with Stripe. The SPT is scoped to your checkout, your Stripe profile, and the checkout total. Because Stripe tokenizes the card, you never handle raw card data.

### Accept the payment instrument

The agent sends the payment instrument in the request that completes the checkout. For a `card` instrument, the `handler_id` matches the `id` of the handler in your profile, and the SPT is in `credential.token`:

```text
POST business.example.com/ucp/v1/checkout-sessions/chk_1234567890/complete
Content-Type: application/json
```

```json
{
  "payment": {
    "instruments": [
      {
        "id": "instr_1",
        "handler_id": "stripe_payments",
        "type": "card",
        "selected": true,
        "credential": {
          "type": "stripe_payment_token",
          "token": "spt_123"
        }
      }
    ]
  }
}
```

### Process the payment

To charge the SPT, pass it in `payment_method_data[shared_payment_granted_token]` when you create and confirm a `PaymentIntent`. Use the `total` entry in the checkout `totals` array as the `amount`. Make this request from your server with a [restricted API key](https://docs.stripe.com/keys/restricted-api-keys.md) that has the PaymentIntents write permission. Store the key in an environment variable or secrets manager, not in your code. See [best practices for managing secret keys](https://docs.stripe.com/keys-best-practices.md).

```curl
curl https://api.stripe.com/v1/payment_intents \
  -u "<<YOUR_SECRET_KEY>>:" \
  -H "Stripe-Version: 2026-09-30.preview" \
  -d amount=4500 \
  -d currency=usd \
  -d "payment_method_data[shared_payment_granted_token]=spt_123" \
  -d confirm=true
```

If the payment succeeds, complete the checkout. If it fails, return an error message with the `payment_failed` code and `recoverable` severity so the agent can ask the customer for another payment method.

## Test your integration

In a sandbox, use the [test helper](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#test-receiving-an-spt) to grant your account an SPT without an agent. Set `usage_limits` to simulate the limits an agent sets, such as the currency, a `max_amount` that matches your total, and an expiration.

```curl
curl https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens \
  -u "<<YOUR_SECRET_KEY>>:" \
  -H "Stripe-Version: 2026-09-30.preview" \
  -d payment_method=pm_card_visa \
  -d "usage_limits[currency]=usd" \
  -d "usage_limits[max_amount]=4500" \
  -d "usage_limits[expires_at]=1798761600"
```

Pass the returned token to your integration, then confirm that the `PaymentIntent` succeeds and that you receive the `shared_payment.granted_token.deactivated` webhook event. [Verify webhook signatures](https://docs.stripe.com/webhooks.md#verify-events) to confirm that events come from Stripe.

To test in live mode, issue a one-time SPT from your own Link account with the `link-cli`. Use a small amount, because live mode charges the payment method you select. For steps, see [Test your live mode integration](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#test-your-live-mode-integration).

## See also

- [Stripe Payments handler for UCP](https://docs.stripe.com/agentic-commerce/protocols/ucp/stripe-payments-handler.md)
- [Shared Payment Tokens](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md)
- [Customize with hooks](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md)
