# Accept service bookings and payments from agents

Help AI agents find, book, and pay for your services.

You can enable programmatic bookings and payments with any agent. Stripe partners with [Muse](https://muse.ai/platform), [Instinct](https://instinct.com), and others to provide native payments integrations. Each agent might have MCP or API requirements beyond the Stripe guidance in this guide.

Your customers can use AI agents to complete tasks such as booking travel, making restaurant reservations, and scheduling appointments. If your business offers bookable services, you can provide structured booking and payment flows that agents can use instead of navigating your website.

Use this guide if you:

- Operate a marketplace, platform, or booking system for bookable services.
- Have APIs or a Model Context Protocol (MCP) server that agents can use to search availability and manage bookings.
- Want agents to complete payments with customer-approved payment credentials.

## Before you begin

To accept agent payments, 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 [booking API or MCP server](https://docs.stripe.com/agentic-commerce/sellers/use-cases/booking.md#enable-programmatic-booking) that agents can use.

You don’t need to replace your current booking or payment architecture. Let agents book and pay programmatically by giving them access to your APIs or equivalent MCP tools.

Stripe doesn’t require a specific endpoint structure, tool naming convention, or payload schema. The examples in this guide show common patterns, not a required Stripe schema.

A user asks an agent to book a service. The agent searches and creates the booking through the business's booking API or MCP server, gets the supported payment handlers, requests a credential from Stripe that the user approves, and shares that credential with the business to complete the booking. (See full diagram at https://docs.stripe.com/agentic-commerce/sellers/use-cases/booking)

```text
[User] -- Request a service --> [Agent]
[Agent] -- Search availability --> [Business]
[Business] -- Return availability --> [Agent]
[Agent] -- Return availability --> [User]
[User] -- Approve booking --> [Agent]
[Agent] -- Create booking --> [Business]
[Business] -- Return payment handlers --> [Agent]
[Agent] -- Create spend request --> [Stripe]
[User] -- Approve in Link --> [Stripe]
[Stripe] -- Spend approval + payment credential --> [Agent]
[Agent] -- Share payment credential --> [Business]
[Business] -- Charge payment credential --> [Stripe]
[Stripe] -- Confirm payment --> [Business]
[Business] -- Confirm booking --> [Agent]
[Agent] -- Booking confirmed --> [User]
```

## Enable programmatic booking

Provide structured interfaces that let agents complete bookings without navigating your website. Support each stage of the booking lifecycle with operations that let agents:

- Search for services and availability.
- Create a booking.
- Retrieve or modify a booking.
- Cancel a booking.

You can provide these operations through a booking API or an MCP server. Follow industry protocols when they’re available, such as the [UCP Lodging Booking Capability](https://ucp.dev/draft/specification/lodging/booking/#flow-overview).

#### Booking API

You can make your booking API publicly available or provide access directly to selected agent partners. Provide a separate endpoint for each booking operation:

| Example endpoint | Purpose |
| --- | --- |
| `GET /availability` | Return open slots for a service, date, and party size or quantity. |
| `POST /bookings` | Create a booking for a specific slot and return a booking ID and confirmation details. |
| `GET /bookings/{id}` | Return the current status and details of a booking. |
| `POST /bookings/{id}/complete` | Accept a payment credential, process the payment, and confirm the booking. |
| `PATCH /bookings/{id}` | Change the slot, date, or party size of an existing booking. |
| `DELETE /bookings/{id}` | Cancel an existing booking. |

When a customer asks an agent to check availability, the agent sends the service, date, and quantity to your API:

```json
GET api.seller.com/availability?service_id=haircut&date=2026-09-10&party_size=1
```

Return available booking options in a structured format. The agent can present these options to the customer and use the selected option in the next booking request.

```json
{
  "service_id": "haircut",
  "date": "2026-09-10",
  "slots": [
    {
      "slot_id": "slot_1400",
      "start_time": "2026-09-10T14:00:00Z",
      "end_time": "2026-09-10T14:30:00Z",
      "price": {
        "amount": 4500,
        "currency": "usd"
      }
    },
    {
      "slot_id": "slot_1530",
      "start_time": "2026-09-10T15:30:00Z",
      "end_time": "2026-09-10T16:00:00Z",
      "price": {
        "amount": 4500,
        "currency": "usd"
      }
    }
  ]
}
```

Use stable identifiers throughout the booking lifecycle. Stable identifiers let the agent select an option and later retrieve, update, or cancel the resulting booking.

Return structured errors that explain what happened and whether the agent can retry. For example, if the selected time is no longer available, return a `409 Conflict` response with an error code that the agent can interpret:

```json
{
  "error": {
    "code": "slot_unavailable",
    "message": "The selected time is no longer available."
  }
}
```

This response lets the agent search for another time instead of ending the booking without a recovery path.

#### MCP server

Expose booking operations as tools through an MCP server. MCP tools give agents a structured alternative to navigating your website or calling an undocumented API. Use a separate tool for each operation:

| Example tool | Purpose |
| --- | --- |
| `search_availability` | Return open slots for a service, date, and party size or quantity. |
| `create_booking` | Create a booking for a specific slot and return a booking ID and confirmation details. |
| `complete_booking` | Accept a payment credential, process the payment, and confirm the booking. |
| `modify_booking` | Change the slot, date, or party size of an existing booking. |
| `cancel_booking` | Cancel an existing booking. |

For example, you might create a `search_availability` tool that accepts a service, date, and quantity. You can choose the tool name, inputs, and response format.

```typescript
server.registerTool(
  'search_availability',
  {
    description: 'Search available slots for a service on a given date.',
    inputSchema: {
      serviceId: z.string(),
      date: z.string(),
      partySize: z.number().int().positive().optional(),
    },
  },
  async ({ serviceId, date, partySize }) => {
    const slots = await searchAvailability({ serviceId, date, partySize })
    return { content: [{ type: 'text', text: JSON.stringify(slots) }] }
  },
)
```

Use clear tool names and descriptions so an agent knows when to call each tool. Return structured results and stable identifiers for the agent to pass between tools.

For example, `search_availability` returns a `slot_id` that the agent passes to `create_booking`. The agent then passes the returned `booking_id` to tools that retrieve, update, or cancel the booking.

## Accept programmatic payments

Agents can use the [Link agent wallet](https://docs.stripe.com/agentic-commerce/agents/link-agent-wallet.md) to send payment credentials through your existing booking API or MCP server. The Link agent wallet currently supports [Shared Payment Tokens](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md) (SPTs) and card credentials.

Declare which credential types your integration supports, and process these credentials with your existing Stripe or third-party payment integration. Stripe recommends following the [Universal Commerce Protocol (UCP) payment handler specification](https://ucp.dev/2026-01-23/specification/payment-handler-guide/).

### Return supported payment handlers

Before the agent completes checkout, return the payment handlers available for the transaction through your existing API. Include the final amount, currency, and credential expiration date. You can set the expiration to a maximum of 180 days after issuance. The agent uses this information to request customer approval and create a payment credential.

Use a UCP-compatible payment handler from your payment provider, or define your own:

```json
GET /bookings/booking_123

// Response
{
  "booking_id": "booking_123",
  "status": "awaiting_payment",
  "amount": 12500,
  "currency": "usd",
  "expires_at": "2026-09-23T00:30:00Z",
  "payment_handlers": [
    {
      "id": "stripe_payments",
      "type": "com.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"
        },
        {
          "type": "link",
          "config": {
            "network_id": "profile_xxx"
          }
        }
      ],
      "config": {
        "environment": "production",
        "business_profile": "profile_xxx"
      }
    },
    {
      "id": "platform_encrypted",
      "type": "com.example.platform_encrypted",
      "version": "2026-06-25",
      "spec": "https://platform.example.com/ucp/encrypted-handler.json",
      "schema": "https://platform.example.com/ucp/encrypted-handler/schema.json",
      "available_instruments": [
        {
          "type": "card"
        }
      ],
      "config": {
        "environment": "production",
        "business_id": "merchant_abc123",
        "public_key_id": "pk_abc123"
      }
    }
  ]
}
```

### Receive and process the payment credential

When the agent completes a booking, it sends the booking identifier, handler ID, instrument type, and a supported payment credential. Process the SPT or card credential with your payment provider. After you process the credential, return the booking state and payment result. If you expose booking tools through an MCP server, accept the payment credential as an input to the tool that completes the booking.

#### Process an SPT

An [SPT](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md) grants you scoped access to a customer’s payment method for an agent-initiated purchase. The agent issues an SPT to your [Stripe profile](https://docs.stripe.com/get-started/account/profile.md) and sends it to your payment endpoint when completing the purchase.

SPTs work natively with the [Payment Intents API](https://docs.stripe.com/payments/payment-intents.md). Pass the SPT in `payment_method_data[shared_payment_granted_token]` and set `confirm=true` when you create the PaymentIntent. See [Use a shared payment token](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#use-a-shared-payment-token) for details.

```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 you work with another processor, you can [resolve the SPT](https://docs.stripe.com/api/shared-payment/granted-token.md) to an encrypted or tokenized credential. Contact your Stripe representative to discuss availability and access requirements.

```json
POST /bookings/booking_123/complete
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

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

// Response
HTTP/1.1 200 OK
{
  "booking": {
    "id": "booking_123",
    "status": "confirmed"
  },
  "payment": {
    "status": "succeeded",
    "transaction_id": "pi_123",
    "instrument_type": "card"
  }
}
```

#### Process a card credential

The agent can also send an encrypted or tokenized card credential. If Stripe tokenized the credential, use the [Payment Intents API](https://docs.stripe.com/payments/payment-intents.md) to complete the payment. If the credential uses encryption defined by your handler or another payment provider’s handler, decrypt and process it according to that handler. The following example shows this flow.

```json
POST /bookings/booking_123/complete
Idempotency-Key: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Content-Type: application/json

{
  "payment": {
    "handler_id": "platform_encrypted",
    "instrument": {
      "type": "card"
    },
    "credential": {
      "encrypted_credential": {
        "algorithm": "YOUR_DEFINED_SCHEME",
        "key_id": "key_123",
        "ciphertext": "YOUR_ENCRYPTED_DATA",
        "nonce": "..."
      }
    }
  }
}

// Response
HTTP/1.1 200 OK
{
  "booking": {
    "id": "booking_123",
    "status": "confirmed"
  },
  "payment": {
    "status": "succeeded",
    "transaction_id": "pi_456",
    "instrument_type": "card"
  }
}
```

### Handle request retries safely

Accept an idempotency key in the `Idempotency-Key` request header to support [idempotent requests](https://docs.stripe.com/error-low-level.md#idempotency). If an agent retries a request with the same key and payload, return the original response. If the payload differs, return a `409 Conflict` error.

Store idempotency records for at least 24 hours so agents can safely retry requests.

## Test your integration

In a sandbox, use the [test helper](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#generate-an-spt-in-a-sandbox) 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

- [Shared Payment Tokens](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md)
