# Customize with hooks

Intervene at checkout events with hooks that Stripe calls on your endpoints.

Stripe manages the checkout lifecycle for agents by default, including taxes and shipping options from your catalog. To intervene at a checkout event, host a hook. Stripe sends a request to your endpoint when the event happens, and your response decides what happens next.

Hooks range from a single decision to full control of checkout:

| Hook | What you decide | Availability |
| --- | --- | --- |
| [Order approval hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#approval-hook) | Approve or decline a purchase before Stripe completes it. | Frontier |
| [Checkout customization hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-customization-hook) | Calculate taxes and shipping options, and restrict payment methods. | Frontier |
| [Product price and availability hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#product-price-availability) | Provide real-time prices and inventory to agents. | Frontier |
| [Checkout hooks](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-events) | Handle every checkout event, and process payments with your own processor. | Private preview, US only |

## Optional: Set up an order approval hook

Before we confirm a payment, we check inventory based on your product catalog data and might run fraud checks depending on your [Radar](https://docs.stripe.com/radar.md) setup. To control whether we complete a purchase, configure an order approval hook. Before we complete the checkout flow, we send an approval request to your service. You must approve or decline the request.

Stripe enforces a four-second timeout for your hook. If your hook doesn’t respond within this time, Stripe declines the payment.

To set up an order approval hook:

1. Specify the endpoint on the [Agentic Commerce settings](https://dashboard.stripe.com/settings/agentic-commerce) page in the Dashboard.
2. Enable **Order approvals**.
3. Implement your logic at the endpoint and use the request and response formats below.

> Stripe returns a `424` status code to agents if your endpoint returns a non-`2xx` status code. Some agents might retry these API requests, so you must make sure that your endpoint is idempotent.

### Request format 

Stripe sends the following request to your endpoint:

```typescript
{
  type: "v1.delegated_checkout.finalize_checkout",
  id: string,
  livemode: boolean,
  // account ID
  context?: string,
  // request specific data
  data: {
    amount_subtotal?: number,
    amount_total?: number,
    billing_details?: {
      name?: string,
      address?: {
        line1?: string,
        line2?: string,
        city?: string,
        state?: string,
        postal_code?: string,
        country?: string
      }
    },
    currency: string,
    email?: string,
    line_item_details: Array<{
      id: string,
      sku_id: string,
      unit_amount: number,
      amount_discount: number,
      amount_subtotal: number,
      amount_tax: number,
      amount_total: number,
      quantity: number,
      name: string,
      tax_rates: Array<{
        rate: {
          id: string,
          display_name: string,
          percentage: number,
          inclusive: boolean,
        },
        // Amount of tax applied for this rate.
        amount: number
      }>
    }>,
    payment_method_details?: {
      type: "card" | ...,
      card?: {
        brand: "amex" | "visa" | "master_card" | ...,
        country?: string,
        exp_month: number,
        exp_year: number,
        fingerprint?: string,
        funding: "credit" | "debit" | "prepaid" | "unknown",
        iin?: string,
        last4: string,
        wallet?: {
          type: "apple_pay" | "google_pay" | ...
        }
      }
    },
    phone?: string,
    shipping_details?: {
      name?: string,
      address?: {
        line1?: string,
        line2?: string,
        city?: string,
        state?: string,
        postal_code?: string,
        country?: string
      },
    },
    total_details?: {
      amount_discount?: number,
      amount_shipping?: number,
      amount_tax?: number
    },
    metadata?: Map<string,string>
  }
}
```

### Response format 

Your endpoint must return `200` HTTP responses with the following format:

```typescript
{
  manual_approval_details: {
    type: "approved" | "declined",
    declined?: {
      reason: string
    }
  },
  // Connect only: set an application fee for the transaction
  application_fee_details?: {
    application_fee_amount: number,
    transfer_data?: {
      amount?: number,
    }
  },
  // will be propagated to Checkout Session metadata
  metadata?: Map<string,string>
}
```

## Optional: Set up a checkout customization hook

By default, Stripe calculates taxes and shipping options for your products based on the options defined in your [product catalog](https://docs.stripe.com/agentic-commerce/concepts/catalog-feed.md).

When enabled for your account, this hook can also declare the payment method types allowed for an individual checkout session.

To calculate taxes or shipping options and costs dynamically with your logic:

1. Specify the endpoint on the [Agentic Commerce settings](https://dashboard.stripe.com/settings/agentic-commerce) page in the Dashboard.
2. Enable **Custom tax rates** or **Custom shipping options**.
3. Implement your logic at the endpoint and use the request and response formats below.

> Stripe returns a `424` status code to agents if your endpoint returns a non-`2xx` status code. Some agents might retry these API requests, so you must make sure that your endpoint is idempotent.

### Request format 

Stripe sends the following request to your endpoint:

```typescript
{
  type: "v1.delegated_checkout.customize_checkout",
  id: string,
  livemode: boolean,
  // Connected account ID
  context?: string,
  // Request specific data
  data: {
    // Used by the seller to determine whether they can set manual tax rates on line items
    automatic_tax: {
      enabled: boolean,
    },
    currency: string,
    line_item_details?: Array<{
      id: string,
      sku_id: string,
      unit_amount: number,
      amount_discount: number,
      amount_subtotal: number,
      amount_tax: number,
      amount_total: number,
      quantity: number,
      name: string,
      tax_rates: Array<{
        rate: {
          id: string,
          display_name: string,
          percentage: number,
          inclusive: boolean,
        },
        // Amount of tax applied for this rate.
        amount: number
      }>
    }>,
    shipping_details?: {
      // Same as the shipping rate object described at https://docs.stripe.com/api/shipping_rates/object#shipping_rate_object
      shipping_rate?: {
        id: string,
        display_name?: string,
        metadata?: Map<string,string>,
        tax_code?: string ,
        tax_behavior: 'unspecified' | 'inclusive' | 'exclusive',
        fixed_amount: {
          amount: number,
          currency: 'usd' | 'cad' | etc.,
          currency_options: {
            <currency>: {
              amount: number,
              tax_behavior: 'unspecified' | 'inclusive' | 'exclusive',
            }
          }
        },
        delivery_estimate?: {
          maximum: { unit: 'business_day' | 'day' | 'hour' | 'month' | 'year', value: number },
          minimum: { unit: 'business_day' | 'day' | 'hour' | 'month' | 'year', value: number }
        }
      },
      // Same as the shipping rate object described at https://docs.stripe.com/api/shipping_rates/object#shipping_rate_object
      shipping_rates?: Array<{
        id: string,
        display_name?: string,
        metadata?: Map<string,string>,
        tax_code?: string,
        tax_behavior: 'unspecified' | 'inclusive' | 'exclusive',
        fixed_amount: {
          amount: number,
          currency: 'usd' | 'cad' | etc.,
          currency_options: {
            <currency>: {
              amount: number,
              tax_behavior: 'unspecified' | 'inclusive' | 'exclusive',
            }
          }
        },
        delivery_estimate?: {
          maximum: { unit: 'business_day' | 'day' | 'hour' | 'month' | 'year', value: number },
          minimum: { unit: 'business_day' | 'day' | 'hour' | 'month' | 'year', value: number }
        }
      }>,
      address?: {
        line1?: string,
        line2?: string,
        city?: string,
        state?: string,
        postal_code?: string,
        country?: string
      }
    },
    amount_total?: number,
    amount_subtotal?: number,
    total_details?: {
      amount_discount?: number,
      amount_shipping?: number,
      amount_tax?: number
    },
    metadata?: Map<string,string>
  }
}
```

### Response format 

Your endpoint must return a `200` HTTP response with the following format:

```typescript
{
  // Optional open enum. A non-empty list sets the session's seller-declared payment method types.
  // Omit this field or return [] to use the active/default payment method configuration instead.
  // Stripe filters capability and presentment compatibility downstream.
  allowed_payment_method_types?: Array<string>,
  shipping_options?: Array<{
    // ID of the shipping rate, or data provided to create the shipping rate. Only provide one; not both
    shipping_rate?: string,
    shipping_rate_data: {
      display_name?: string,
      fixed_amount: {
        amount: number,
        currency: 'usd' | 'cad' | etc.,
      },
      metadata?: Map<string,string>,
      tax_code?: string ,
      tax_behavior?: 'unspecified' | 'inclusive' | 'exclusive',
      // Same as the shipping rate object described at https://docs.stripe.com/api/shipping_rates/create#create_shipping_rate-delivery_estimate
      delivery_estimate?: {
        maximum: { unit: 'business_day' | 'day' | 'hour' | 'month' | 'year', value: number },
        minimum: { unit: 'business_day' | 'day' | 'hour' | 'month' | 'year', value: number }
      }
    },
  }>,
  line_items?: Array<{
    // Corresponding ID of the line item to update
    id: string,
    // List of tax rates to apply to this line item
    // Provide either `rate` or `rate_data`
    tax_rates: Array<{
      // ID of a v1 tax rate
      rate?: string,
      // Or `rate_data`.
      // This will use an existing tax rate that matches the params or will create one if a matching rate does not exist
      rate_data?: {
        display_name: string,
        inclusive: boolean,
        // percentage out of 100
        percentage: number,
      }
    },
  }>,
  // will be propagated to Checkout Session metadata
  metadata?: Map<string,string>
}
```

## Optional: Set up a product price and availability hook

Implement this hook to provide agents with real-time pricing and inventory data. Without it, agents rely on your uploaded product catalog, which can result in out-of-stock errors or price mismatches at checkout.

Agents can call this endpoint when inventory is low or before showing a product to a buyer. Stripe can also call the endpoint to keep catalog data current.

To set up a product price and availability hook:

1. Specify the endpoint on the [Agentic Commerce settings](https://dashboard.stripe.com/settings/agentic-commerce) page in the Dashboard.
2. Enable **Product price and availability**.
3. Implement your logic at the endpoint and use the request and response formats below.

### Request format 

Stripe sends the following request to your endpoint:

```typescript
{
  type: "delegated_commerce.product_price_availability",
  id: string,
  livemode: boolean,
  // The ID of the merchant whose data is requested
  context?: string,
  // request specific data
  data: {
    sku_id: string,
  }
}
```

### Response format 

Your endpoint must return a `200` HTTP response with the following format:

```typescript
{
  sku_id: string,
  merchant_id: string,  // must match the context field from the request
  deleted?: boolean,    // when true, the product has been deleted; omit availability and price
  availability?: {      // required unless deleted is true
    status: "in_stock" | "out_of_stock" | "preorder" | "backorder",
    quantity?: number,          // current inventory count
    availability_date?: string  // ISO 8601 date when a preorder item becomes available
  },
  price?: {             // required unless availability.status is "out_of_stock" or deleted is true
    unit_amount: number,        // current selling price in smallest currency unit
    currency: string            // ISO 4217 currency code
  },
  sale_price?: {
    unit_amount: number,        // sale price in smallest currency unit
    currency: string,           // ISO 4217 currency code
    start_date: string,         // ISO 8601 sale start date
    end_date: string            // ISO 8601 sale end date
  },
  as_of?: number                // Unix timestamp of when this data was last accurate
}
```

## Optional: Test your hooks

You can test your order approval or checkout customization hook by providing a publicly accessible endpoint that can accept hook requests with a `POST` method. Set up your endpoint function so that it:

1. Handles `POST` requests with a JSON payload
2. Returns a successful status code (`200`)

For local development, use a tunneling tool such as [ngrok](https://ngrok.com/) to expose your local endpoint.

### Example endpoint

This code snippet shows an endpoint function that receives `v1.delegated_checkout.finalize_checkout` requests and returns a `200` response. You can find the signing secret under the **Agentic Commerce Extension** event destination in your webhook settings in the [Developer Dashboard](https://docs.stripe.com/development/dashboard.md).

#### Ruby

```ruby
require 'json'
require 'sinatra'
require 'stripe'

set :port, 4242

# Replace with your endpoint's secret from your webhook settings
endpoint_secret = 'whsec_...'

# Using Sinatra
post '/hooks' do
  payload = request.body.read
  sig_header = request.env['HTTP_STRIPE_SIGNATURE']

  # Verify the webhook signature
  begin
    Stripe::Webhook::Signature.verify_header(
      payload, sig_header, endpoint_secret
    )
  rescue Stripe::SignatureVerificationError => e
    status 400
    return
  end

  # Handle the payload
  payload = JSON.parse(payload)
  case payload['type']
  when 'v1.delegated_checkout.finalize_checkout'
    # Check inventory and accept payment
    data = { manual_approval_details: { type: 'approved' } }
  end

  status 200
  body data.to_json
end
```

## Handle every checkout event 

> Checkout hooks are available in the US. To request access and onboard your endpoints, [join the waitlist](https://go.stripe.global/agentic-commerce-contact-sales).

To host the checkout hooks, you take over the whole checkout lifecycle. Because you receive the Shared Payment Token (SPT) when the agent confirms, you can also process the payment with your own third-party processor.

Stripe calls the checkout hooks at these events:

| Event | Hook | Your endpoint |
| --- | --- | --- |
| The agent starts a checkout. | [Checkout creation hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-created) | Create the checkout and return its current state, totals, and options such as shipping methods. |
| The agent changes items, fulfillment options, or addresses. | [Checkout update hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-updated) | Recalculate totals, confirm inventory, and return the updated checkout. |
| The agent confirms the checkout with the customer’s payment credential. | [Checkout confirmation hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-confirm) | Receive the SPT, process the payment, and create the order. |
| The agent retrieves the latest checkout state. | [Checkout retrieval hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-retrieve) | Return the current checkout, with any changes. |

Seller API checkout hooks (See full diagram at https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks)

```text
[Customer] -- Clicks “Buy” --> [Agent]
[Agent] -- Initiate Checkout --> [Stripe]
[Stripe] -- Checkout create request --> [Seller]
[Seller] -- Create checkout session and check inventory --> [Seller]
[Seller] -- Checkout Create response --> [Stripe]
[Stripe] -- Renders checkout UI --> [Customer]
[Customer] -- Select shipping option and update shipping address --> [Agent]
[Agent] -- Update Checkout --> [Stripe]
[Stripe] -- Update checkout request --> [Seller]
[Seller] -- Update Checkout --> [Seller]
[Seller] -- Update Checkout response --> [Stripe]
[Stripe] -- Update checkout UI --> [Customer]
[Customer] -- Clicks pay and submits PaymentMethod --> [Agent]
[Agent] -- Confirm Checkout --> [Stripe]
[Stripe] -- Confirm checkout request with SharedPaymentToken --> [Seller]
[Seller] -- Resolve SharedPaymentToken --> [Stripe]
[Stripe] -- Return credential --> [Seller]
[Seller] -- Process payment with credential --> [Payment Processor]
[Payment Processor] -- Payment success --> [Seller]
[Seller] -- Confirm response --> [Stripe]
[Stripe] -- Render order confirmation --> [Customer]
```

## Before you begin

To host checkout hooks, you need:

- Access to the private preview. [Join the waitlist](https://go.stripe.global/agentic-commerce-contact-sales) to request it.
- A [Stripe account](https://stripe.com/register). You create your [Stripe profile](https://docs.stripe.com/get-started/account/profile.md) when you onboard in the Dashboard.
- HTTPS endpoints that your commerce backend serves for each checkout event, starting with the [checkout creation hook](https://docs.stripe.com/agentic-commerce/sellers/use-cases/retail/checkout/hooks.md#checkout-created).
- An account with your payment processor, if you process payments yourself.

## Set up a checkout creation hook

When a customer indicates that they want to place an order, the agent sends you a checkout request. Process the request and return the current checkout flow so the agent can show the customer details such as the total and available options such as shipping methods. If any required information is missing, the checkout flow remains incomplete.

#### Request

```json
POST api.seller.com/agentic/checkouts
{
  created: Timestamp,
  currency: "usd",
  // currently limited to single item checkouts
  line_items: [
    {
      sku_id: "sku_123",
      quantity: 2
    }
  ],
  buyer: {
    first_name: "John",
    last_name: "Doe",
    email: "john.doe@example.com",
    phone_number: "+1234567890"
  },
  fulfillment_details: {
     contact: {
        name: "Jane Doe",
        email: "jane.doe@example.com",
        phone_number: "+14155552671"
      },
      address: {
        "line_one": "123 Main St",
        "line_two": "Apt 4B",
        "city": "San Francisco",
        "state": "CA",
        "country": "US",
        "postal_code": "94105"
      }
  },
  agent_details: {
     network_profile: "profile_agent", // agent's Stripe provided unique id
     display_name: "Agent"
  }
}

```

#### Response

```json
{
  id: "checkout_123", // unique checkout identifier
  currency: "usd",
  status: "incomplete" (Enum: "incomplete | ready_for_payment | requires_escalation | processing | completed | canceled"),
  buyer: {
    first_name: "John",
    last_name: "Doe",
    email: "john.doe@example.com",
    phone_number: "+1234567890"
  },
  fulfillment_details: {
    contact: {
        name: "Jane Doe",
        email: "jane.doe@example.com",
        phone_number: "+14155552671"
      },
    address: {
      "line_one": "123 Main St",
      "line_two": "Apt 4B",
      "city": "San Francisco",
      "state": "CA",
      "country": "US",
      "postal_code": "94105"
    }
  },
  line_items: [
    {
      id: "sku_123",
      item: {
        id: "prod_abc123",
        name: "Shampoo",
        description: "Shampoo for curly hair",
        images: ["https://seller.com/images/shampoo.jpg"],
        unit_amount: 5000
      },
      quantity: 2,
      base_amount: 10000,  // pre-discount amount in cents
      discount: 1000,      // total discount applied
      subtotal: 9000,      // after discount, before tax
      tax: 720,            // tax amount
      total: 9720          // final line item total
    }
  ],
  fulfillment_options: [  // available shipping or delivery methods
    {
      type: "shipping",
      id: "ship_standard_001",
      title: "Standard Shipping",
      subtitle: "5-7 business days",
      carrier: "USPS",
      earliest_delivery_time: "2026-01-20T00:00:00Z",  // ISO 8601
      latest_delivery_time: "2026-01-22T23:59:59Z",
      subtotal: 500,
      tax: 40,
      total: 540
    },
    {
      type: "shipping",
      id: "ship_express_001",
      title: "Express Shipping",
      subtitle: "2-3 business days",
      carrier: "FedEx",
      earliest_delivery_time: "2026-01-15T00:00:00Z",
      latest_delivery_time: "2026-01-16T23:59:59Z",
      subtotal: 1500,
      tax: 0,
      total: 1500
    },
  ],
  fulfillment_option_id?: "ship_standard_001", // Implement default selected shipping option, if any
  totals: [  // itemized cost breakdown
    {
      type: "items_base_amount",
      display_text: "Items",
      amount: 10000
    },
    {
      type: "discount",
      display_text: "Discount",
      amount: -1000
    },
    {
      type: "subtotal",
      display_text: "Subtotal",
      amount: 9000
    },
    {
      type: "fulfillment",
      display_text: "Shipping",
      amount: 0  // at this step, if shipping option is not yet selected, no shipping cost to show
    },
    {
      type: "tax",
      display_text: "Sales Tax",
      amount: 720
    },
    {
      type: "total",
      display_text: "Total",
      amount: 9720
    },
    {
      type: "packing_fee",
      display_text: "Gift Wrap",
      amount: 100
    },
  ],
}
```

## Set up a checkout update hook

Agents can update a checkout flow to change items, select fulfillment options, or update addresses. After each update, recalculate totals and confirm inventory availability. When the checkout includes all required information, mark it as `ready_for_payment`.

#### Request

```json
POST api.seller.com/agentic/checkouts/:id
{
    fulfillment_option_id?: "ship_express_001", // updated shipping option
}

```

#### Response

```json
{
  id: "checkout_123", // unique checkout identifier
  currency: "usd",
  status: "ready_for_payment" (Enum: "incomplete | ready_for_payment | requires_escalation | processing | completed | canceled"),
  buyer: {
    first_name: "John",
    last_name: "Doe",
    email: "john.doe@example.com",
    phone_number: "+1234567890"
  },
  fulfillment_details: {
    contact: {
        name: "Jane Doe",
        email: "jane.doe@example.com",
        phone_number: "+14155552671"
      },
    address: {
      "line_one": "123 Main St",
      "line_two": "Apt 4B",
      "city": "San Francisco",
      "state": "CA",
      "country": "US",
      "postal_code": "94105"
    }
  },
  line_items: [
    {
      id: "sku_123",
      item: {
        id: "prod_abc123",
        name: "Shampoo",
        description: "Shampoo for curly hair",
        images: ["https://seller.com/images/shampoo.jpg"],
        unit_amount: 5000
      },
      quantity: 2,
      base_amount: 10000,  // pre-discount amount in cents
      discount: 1000,      // total discount applied
      subtotal: 9000,      // after discount, before tax
      tax: 720,            // tax amount
      total: 9720          // final line item total
    }
  ],
  fulfillment_options: [  // available shipping or delivery methods
    {
      type: "shipping",
      id: "ship_standard_001",
      title: "Standard Shipping",
      subtitle: "5-7 business days",
      carrier: "USPS",
      earliest_delivery_time: "2026-01-20T00:00:00Z",  // ISO 8601
      latest_delivery_time: "2026-01-22T23:59:59Z",
      subtotal: 500,
      tax: 40,
      total: 540
    },
    {
      type: "shipping",
      id: "ship_express_001",
      title: "Express Shipping",
      subtitle: "2-3 business days",
      carrier: "FedEx",
      earliest_delivery_time: "2026-01-15T00:00:00Z",
      latest_delivery_time: "2026-01-16T23:59:59Z",
      subtotal: 1500,
      tax: 0,
      total: 1500
    },
  ],
  fulfillment_option_id?: "ship_express_001", // Implement default selected shipping option, if any
  totals: [  // itemized cost breakdown
    {
      type: "items_base_amount",
      display_text: "Items",
      amount: 10000
    },
    {
      type: "discount",
      display_text: "Discount",
      amount: -1000
    },
    {
      type: "subtotal",
      display_text: "Subtotal",
      amount: 9000
    },
    {
      type: "fulfillment",
      display_text: "Shipping",
      amount: 1500  // updated shipping cost
    },
    {
      type: "tax",
      display_text: "Sales Tax",
      amount: 720
    },
    {
      type: "total",
      display_text: "Total",
      amount: 9720
    },
    {
      type: "packing_fee",
      display_text: "Gift Wrap",
      amount: 100
    },
  ],
}
```

## Set up a checkout confirmation hook

When the agent confirms the checkout, Stripe calls your confirmation endpoint with payment data. Your endpoint receives the SPT, processes the payment with your processor, reports the payment to Stripe, and returns the order details.

### Receive an SPT

When the agent collects the buyer’s payment information and confirms the checkout, your confirmation hook receives an [SPT](https://docs.stripe.com/api/shared-payment/granted-token.md). The SPT is a scoped grant of the customer’s payment method from the agent to your [Stripe profile](https://docs.stripe.com/get-started/account/profile.md) with specific usage and expiration limits.

```json
POST api.seller.com/agentic/checkouts/:id/confirm
{
  payment_data: {
    token: "spt_123",  // Stripe SharedPaymentToken ID
    provider: "stripe",
    billing_address?: {  // optional
      line1?: string,
      city?: string,
      state?: string,
      postal_code?: string,
      country?: string
    }
  },
  risk_details: {
    client_device_metadata_details: {
      user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
      ip_address: 1.2.3.4
    }
  }
}
```

### Use an SPT

Follow the [SPT resolve guide](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#resolve) to retrieve payment credentials and submit them to your payment processor. Before resolving a token, review the required [account configuration](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#configure-resolution-behavior) and [PCI requirements](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#meet-pci-requirements).

### Record a payment

After you capture the payment with your processor, [report the payment to Stripe](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md#record-a-payment), associating it with the SPT.

### Respond to confirm checkout and fulfill orders

Return the checkout status and order details to the agent.

```json
{
    // status must be in_progress or completed, or you must return an error
    status: "in_progress" | "completed",
    order: {
      id: string,
      permalink_url: string,
    },
    metadata?: Hash
}
```

## Set up a checkout retrieval hook

When an agent retrieves the latest checkout state, Stripe sends you the full current checkout state, and you respond with any changes to that state. If nothing has changed, you can return the current state without making any updates.

#### Request

```bash
GET api.seller.com/agentic/checkouts/:id
```

#### Response

```json
{
    "status": "in_progress"
}
```

## Test your integration

After Stripe onboards your endpoints, go to [Agentic Commerce](https://dashboard.stripe.com/agentic-commerce) in the Stripe Dashboard. This flow guides you through creating a [Stripe profile](https://docs.stripe.com/get-started/account/profile.md) and requesting onboarding for the agents you want to use.

Use Blueprints in [Workbench](https://docs.stripe.com/workbench.md) to test receiving hook requests in your [sandbox](https://docs.stripe.com/sandboxes.md):

- Test an `UpdateSession` request, which simulates the checkout update hook, with an invalid shipping address to verify that your error validation messages display correctly.
- Test a `CompleteSession` request, which simulates the checkout confirmation hook, with specific payment data to verify your order creation logic.

You can configure request payloads, including custom line items, buyer details, fulfillment addresses, and other fields, to match your test cases. Before you go live, confirm that your checkout flow updates as expected, your shipping calculations are accurate, and payment confirmation completes successfully.

When you’re ready to sell your products through an agent, review the [agent terms](https://stripe.com/legal/ssa-services-terms#stripe-agentic-commerce-seller-services-preview) and request onboarding for the agent in the Dashboard. Stripe sends the agent an approval request that the agent must accept. To pause or stop selling through the agent, disable the agent in the Dashboard.

## See also

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