# Stripe Payments handler for UCP

Accept payments through UCP-compatible platforms using the Stripe unified payment handler.

Use the `com.stripe.payments` handler to accept payments through [Universal Commerce Protocol](https://ucp.dev) (UCP) compatible platforms. This handler supports card and Apple Pay payments.

In UCP terminology, *platform* refers to the agent or application acting on behalf of the customer, *business* refers to the merchant or seller processing the payment.

## How it works 

The Stripe Payments handler enables credential acquisition and payment processing for UCP checkouts:

1. **Discovery**: The business advertises `com.stripe.payments` in its UCP profile at `/.well-known/ucp`, declaring supported instruments and their configuration.
2. **Credential collection**: The platform collects the customer’s card details or receives a payment token from a wallet.
3. **Tokenization**: For cards, the platform calls `/api/ucp/tokenize` with the raw credential, checkout binding, seller identity, and usage limits. The handler returns a shared payment token (SPT).
4. **Completion**: The platform submits the SPT to the business’s checkout completion endpoint.

For Apple Pay and Google Pay, the platform receives a payment token rather than raw card details and submits it directly to checkout completion without calling `/tokenize`.

## Supported instruments 

Use the Stripe Payments handler for card and Apple Pay completion, and the Google Pay payment handler for Google Pay. The Stripe Payments handler also advertises Link for credential acquisition:

| Instrument type | Tokenization | Description |
| --- | --- | --- |
| `card` | Required | Platform collects card details, then exchanges them for an SPT. |
| `link` | Not required | Link Agent Wallet provides an SPT through `link-cli`. A `link` instrument isn’t accepted by the current `/complete` endpoint. |
| `apple_pay` | Not required | Platform receives an Apple Pay payment token and submits it directly to `/complete`. |
| `google_pay` | Not required | Platform uses the Google Pay payment handler to receive a payment token and submits it directly to `/complete`. |

## Discovery 

Fetch the business’s UCP configuration from `/.well-known/ucp` to discover its supported payment handlers. The `com.stripe.payments` declaration includes available instruments, their constraints, and configuration.

### Business profile example

The following example shows the Stripe Payments and Google Pay handlers. Use `com.google.pay` for Google Pay configuration and completion. Discovery also advertises `google_pay` under `com.stripe.payments`, but that entry doesn’t provide a Google Pay completion flow and is omitted here. Apple Pay appears when merchant identifiers are available.

```json
{
  "ucp": {
    "version": "2026-04-08",
    "payment_handlers": {
      "com.google.pay": [
        {
          "id": "stripe-handler",
          "version": "2026-01-23",
          "spec": "https://pay.google.com/gp/p/ucp/2026-01-11/",
          "schema": "https://pay.google.com/gp/p/ucp/2026-01-11/schemas/config.json",
          "config": {
            "api_version": 2,
            "api_version_minor": 0,
            "environment": "PRODUCTION",
            "merchant_info": {
              "merchant_name": "Example Store",
              "merchant_id": "<GOOGLE_PAY_MERCHANT_ID>"
            },
            "allowed_payment_methods": [
              {
                "type": "CARD",
                "parameters": {
                  "allowed_auth_methods": ["PAN_ONLY", "CRYPTOGRAM_3DS"],
                  "allowed_card_networks": ["VISA", "MASTERCARD", "AMEX", "DISCOVER", "JCB"],
                  "billing_address_required": true,
                  "billing_address_parameters": {
                    "format": "FULL",
                    "phone_number_required": true
                  }
                },
                "tokenization_specification": {
                  "type": "PAYMENT_GATEWAY",
                  "parameters": {
                    "gateway": "stripe",
                    "stripe:publishableKey": "pk_live_abc123",
                    "stripe:version": "2018-10-31"
                  }
                }
              }
            ]
          }
        }
      ],
      "com.stripe.payments": [
        {
          "id": "stripe_payments",
          "version": "2026-06-25",
          "spec": "https://docs.stripe.com/agentic-commerce/ucp/stripe-payments-handler",
          "schema": "https://ucp.stripe.com/payments/2026-06-25/schema.json",
          "available_instruments": [
            {
              "type": "card",
              "constraints": {
                "brands": ["visa", "mastercard", "amex", "discover"],
                "tokenization": "required"
              }
            },
            {
              "type": "link",
              "config": {
                "network_id": "profile_seller_xyz"
              }
            },
            {
              "type": "apple_pay",
              "config": {
                "apple_pay_merchant_identifiers": ["merchant.com.example.store"]
              }
            }
          ],
          "config": {
            "environment": "production",
            "business_profile": "profile_seller_xyz"
          }
        }
      ]
    }
  }
}
```

### Handler configuration fields

Required when business `config` is supplied:

| Field | Type | Description |
| --- | --- | --- |
| `environment` | string | `sandbox` or `production` |
| `business_profile` | string | Seller’s Stripe network profile ID (`profile_*`), not an `acct_*` account ID or an API key |

Send the business’s `business_profile` as `identity.access_token` in the tokenize request. Authenticate with the agent’s API key.

Platform handler `config` is optional. When supplied, it requires `environment`; a string `business_profile` is optional.

### Per-instrument configuration

| Instrument | Config fields | Purpose |
| --- | --- | --- |
| `link` | `network_id` | Identifies the business network profile that Link uses to look up the business |
| `apple_pay` | `apple_pay_merchant_identifiers` | Lists the business’s available Apple Pay merchant identifiers |

## Tokenize credentials 

To complete a credit or debit card checkout, exchange the customer’s card details for a shared payment token (SPT), then submit that token to complete the checkout. The token lets you submit payment credentials without including the card number or CVC in the checkout completion request.

**Endpoint:** `POST https://commerce.stripe.com/api/ucp/tokenize`

**Authentication:** Call from your server using the UCP agent’s Stripe secret API key as the bearer token. Keep this key server-side. The agent and seller must use the same environment and have a confirmed commerce relationship; the seller network profile in `identity.access_token` identifies the seller, not the caller.

### Request

After collecting the customer’s card details, call the tokenization endpoint using your agent’s API key. Include the card details in `credential`, the checkout-session ID in `binding.id`, and the business profile ID in `identity.access_token`. Set `binding.type` to `dev.ucp.shopping.checkout`.

```text
POST /api/ucp/tokenize
Content-Type: application/json
Authorization: Bearer sk_live_...
```

```json
{
  "credential": {
    "type": "pan",
    "number": "4242424242424242",
    "expiry_month": 12,
    "expiry_year": 2027,
    "cvc": "314"
  },
  "binding": {
    "type": "dev.ucp.shopping.checkout",
    "id": "chk_abc123"
  },
  "identity": {
    "access_token": "profile_seller_xyz"
  },
  "usage_limits": {
    "max_amount": 10000,
    "currency": "usd",
    "expires_at": "2027-01-15T14:35:00Z"
  }
}
```

### Response

```json
{
  "type": "stripe_payment_token",
  "token": "spt_123"
}
```

### Request fields

| Field | Type | Description |
| --- | --- | --- |
| `credential` | object | The raw card credential to tokenize. |
| `credential.type` | string | Credential type. Must be `pan`. |
| `credential.number` | string | Card number |
| `credential.expiry_month` | integer | Expiration month (1–12) |
| `credential.expiry_year` | integer | Expiration year |
| `credential.cvc` | string | Card verification code |
| `binding.type` | string | Capability that owns the resource. Use `dev.ucp.shopping.checkout` for a checkout. |
| `binding.id` | string | ID of the checkout resource |
| `identity.access_token` | string | Business’s Stripe-issued network profile ID |
| `usage_limits.max_amount` | integer | Maximum charge amount in smallest currency unit |
| `usage_limits.currency` | string | Three-letter ISO currency code |
| `usage_limits.expires_at` | string | Token expiration (ISO 8601). Defaults to 1 hour if omitted. |

## Complete payment 

After acquiring an SPT from `/api/ucp/tokenize`, the platform submits it in the business’s checkout completion request.

```text
POST /api/ucp/{business_profile}/checkout-sessions/{checkout_id}/complete
Content-Type: application/json
Authorization: Bearer sk_live_...
UCP-Agent: profile="https://agent.example/profile"
```

```json
{
  "payment": {
    "instruments": [
      {
        "id": "instr_1",
        "handler_id": "stripe_payments",
        "type": "card",
        "selected": true,
        "display": {
          "brand": "visa",
          "last_digits": "4242",
          "expiry_month": 12,
          "expiry_year": 2027
        },
        "credential": {
          "type": "stripe_payment_token",
          "token": "spt_123"
        }
      }
    ]
  }
}
```

### Payment instrument fields

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Unique identifier for this instrument instance, assigned by the platform |
| `handler_id` | string | Must match the handler’s `id` from the business’s profile (`stripe_payments`) |
| `type` | string | Use `card` for the SPT path or `apple_pay` for the Apple Pay path described here |
| `credential.type` | string | Token type discriminator. The business uses this to determine its internal processing path. |
| `credential.token` | string | The SPT for cards, or the serialized JSON string of a `PKPaymentToken` object for Apple Pay |

## Wallet flows 

Wallets provide payment credentials directly, without a card `/tokenize` call.

### Link

The business advertises `link` with a `config.network_id` that identifies its network profile.

### Link Agent Wallet

An AI agent can acquire a payment credential through [link-cli](https://github.com/stripe/link-cli). Every transaction requires the customer to biometrically approve the spend in the Link app.

1. The agent creates a spend request using `link-cli` with the amount, business name, and (for on-Stripe businesses) `credential_type: shared_payment_token`.
2. The agent requests approval; the customer approves biometrically in the Link app.
3. The agent retrieves the credential when it’s approved—a shared payment token (SPT) for on-Stripe businesses.

For the full Spend Requests API and CLI usage, see [stripe/link-cli](https://github.com/stripe/link-cli).

### Google Pay

For Google Pay, agents use the Google Pay payment handler to receive a payment token rather than raw card details. Submit the token directly in the checkout completion request.

Initialize the Google Pay SDK using the gateway configuration from the business’s `com.google.pay` handler. Use that handler’s `id` (`stripe-handler`) in the completion request:

```json
{
  "payment": {
    "instruments": [
      {
        "id": "instr_1",
        "handler_id": "stripe-handler",
        "credential": {
          "type": "PAYMENT_GATEWAY",
          "token": "<TOKEN_RETURNED_BY_GOOGLE_PAY>"
        },
        "type": "CARD",
        "selected": true,
        "billing_address": {
          "street_address": "123 Main Street",
          "address_locality": "San Francisco",
          "address_region": "CA",
          "postal_code": "94103",
          "address_country": "US",
          "phone_number": "+14155550123"
        }
      }
    ]
  }
}
```

### Apple Pay

For Apple Pay, agents receive an encrypted `PKPaymentToken` from Apple rather than raw card details. Submit the Apple Pay token directly in the checkout completion request:

1. Read `apple_pay_merchant_identifiers` from the advertised Apple Pay instrument’s config.
2. Initialize your Apple Pay integration using an appropriate business merchant identifier.
3. Collect the customer’s Apple Pay payment token and serialize the `PKPaymentToken` object as a JSON string.
4. Submit that string to `/complete` using `handler_id: "stripe_payments"`, instrument `type: "apple_pay"`, and `credential: {"type": "pk_payment_token", "token": "<SERIALIZED_PK_PAYMENT_TOKEN>"}`.

Checkout completion creates the SPT internally. Don’t send the Apple Pay token through the card `/api/ucp/tokenize` request.

## Customer actions 

Some payment methods require customer interaction after submission (3D Secure challenges, BNPL approval). The handler returns a redirect action:

```json
{
  "status": "requires_action",
  "redirect_url": "https://ucp.stripe.com/payment-actions/session_456",
  "redirect_context": {
    "reason": "three_ds_challenge",
    "timeout_seconds": 300
  }
}
```

Platform flow:

1. Receive `status: "requires_action"` with `redirect_url`
2. Open the URL for the customer (browser, webview, or iframe)
3. Customer completes the interaction (3D Secure challenge, BNPL approval)
4. Platform re-submits `/complete` with the same checkout ID and instruments
5. Handler processes payment

## Charge the token 

The business uses the SPT from `credential.token` to create a Stripe PaymentIntent.

```text
POST /v1/payment_intents
Content-Type: application/x-www-form-urlencoded

amount=10000&
currency=usd&
payment_method_data[shared_payment_granted_token]=spt_123&
confirm=true
```

## Error handling 

| Failure | Error code | Severity | Retryable |
| --- | --- | --- | --- |
| Card declined | `payment_declined` | recoverable | Yes (different card) |
| Insufficient funds | `payment_declined` | recoverable | Yes |
| Token expired | `token_invalid` | recoverable | Yes (re-tokenize) |
| Rate limited | `rate_limited` | recoverable | Yes (after backoff) |
| Fraud detected | `payment_declined` | unrecoverable | No |

## Security 

| Requirement | Description |
| --- | --- |
| TLS/HTTPS | All calls to handler endpoints must be encrypted |
| PCI DSS | Stripe is PCI Level 1. Your card credential collection integration must be PCI compliant. |
| Seller identity and limits | Include the business’s network profile in `identity.access_token` and specify the token’s amount and currency limits. |
| Token lifecycle | Tokenize requests default to a 1-hour expiry when `usage_limits.expires_at` is omitted. |
| No detokenize | This is a processor-tokenizer handler. Token resolution happens internally. No credential is ever returned to external parties. |

## References 

| Resource | URL |
| --- | --- |
| Handler schema | `https://ucp.stripe.com/payments/2026-06-25/schema.json` |
| UCP Payment Handler Guide | [ucp.dev/latest/specification/payment-handler-guide](https://ucp.dev/latest/specification/payment-handler-guide/) |
| UCP Tokenization Guide | [ucp.dev/latest/specification/tokenization-guide](https://ucp.dev/latest/specification/tokenization-guide/) |
| Link CLI (Spend Requests API) | [github.com/stripe/link-cli](https://github.com/stripe/link-cli) |
