# Sell through agents

Sell your products through AI agents using Agentic Commerce Suite.

Use Agentic Commerce Suite (ACS) to start selling through agents with a single integration. ACS helps you make your products discoverable and accept agentic payments across multiple commerce protocols. It lets you share product, price, and availability information with agents while minimizing changes to your existing commerce systems. ACS is available in the US, Canada, and select European countries.

### View all supported countries

- AT
- BE
- BG
- CA
- CH
- CY
- CZ
- DE
- DK
- EE
- ES
- FI
- FR
- GB
- GI
- GR
- HR
- HU
- IE
- IT
- LI
- LT
- LU
- LV
- MT
- NL
- NO
- PL
- PT
- RO
- SE
- SI
- SK
- US

If you operate a platform, see the [guide for platforms](https://docs.stripe.com/connect/saas/tasks/enable-in-context-selling-on-ai-agents.md).

## Set up your Stripe account

To get set up for agentic commerce:

1. First, you need a Stripe account. [Create an account](https://dashboard.stripe.com/register).
2. After you create an account:
   - Verify your email.
   - Activate payments by providing business and personal information.
   - Connect a bank account for payouts.
   - Set up two-factor authentication.

1. Go to the [Agentic commerce](https://dashboard.stripe.com/agentic-commerce) page in the Dashboard and select **Get started** on **Agentic commerce for retail**, then choose to onboard as a seller.
2. In the modal, populate your business details by creating a [Stripe profile](https://docs.stripe.com/get-started/account/profile.md). Add your terms of service, privacy policy, and return policy.
3. Configure tax. Stripe calculates tax at checkout using the values in your catalog feed, and incomplete configuration can cause checkouts to fail. Configure a tax code for each taxable product. Stripe Tax is optional: set `stripe_product_tax_code` if you use [Stripe Tax](https://docs.stripe.com/tax.md) for automatic tax calculation (follow the [tax setup guide](https://docs.stripe.com/tax/set-up.md?dashboard-or-api=api) to configure it), or set `third_party_tax_code` if you use [Anrok](https://www.anrok.com) or [Sphere](https://www.getsphere.com) instead. See the [price and promotions field reference](https://docs.stripe.com/agentic-commerce/product-feed.md#price-and-promotions) for details on these fields.

## Create a catalog feed

Create a [catalog feed](https://docs.stripe.com/agentic-commerce/product-feed.md) to share your product and inventory data with agents. Format your feed as a CSV where each row is a product or variant and each column maps to a field in the [product feed field reference](https://docs.stripe.com/agentic-commerce/product-feed.md#product-feed-field-reference).

After you set up your catalog feed, follow these suggested best practices to prevent issues with outdated inventory or pricing. For example, agents might continue to report that a product isn’t available (even if it’s back in stock) until they receive an explicit signal that the inventory has been updated.

To troubleshoot continued issues, see how to [Handle out-of-stock and price failures](https://docs.stripe.com/agentic-commerce/for-sellers/handle-checkout-failures.md).

### Keep your catalog feed current

To prevent purchase failures during agentic checkout, refresh your product catalog feed frequently. How frequently depends on how fast your inventory moves, but in most cases, uploading inventory and pricing data every 15 minutes is enough.

Between full uploads, send targeted changes with the [incremental inventory](https://docs.stripe.com/agentic-commerce/for-sellers.md#inventory-updates) and [incremental price](https://docs.stripe.com/agentic-commerce/for-sellers.md#price-updates) feeds instead of re-uploading your entire catalog.

### Cleanly remove old products

When you remove a product from your inventory, send a clean deletion. In upsert mode, omitting a product from your feed leaves it unchanged in Stripe’s catalog. To explicitly remove it, set `delete=true`. Otherwise, the product remains visible to shoppers and agents.

### Only use replace mode for complete inventory refreshes

Feed uploads support two processing modes: `upsert` and `replace`. In replace mode, any product not included in the uploaded file is permanently deleted from Stripe’s catalog. Use `upsert` for all incremental updates and reserve replace mode for intentional full-catalog refreshes. See [Feed processing mode](https://docs.stripe.com/agentic-commerce/product-feed.md#feed-processing-mode).

| Feed type | Frequency | Purpose |
| --- | --- | --- |
| [Product data](https://docs.stripe.com/agentic-commerce/product-feed.md#product-feed-specification) | Once per day | Titles, descriptions, images, and categories |
| [Inventory](https://docs.stripe.com/agentic-commerce/product-feed.md#inventory-feed-spec) | Every 15 minutes | Prevents agents from showing out-of-stock items |
| [Pricing](https://docs.stripe.com/agentic-commerce/product-feed.md#price-feed-spec) | Every 15 minutes | Helps keep the checkout price aligned with the quoted price |
| [Promotions](https://docs.stripe.com/agentic-commerce/product-feed.md#promotion-feed-spec) | As needed | Offers discount codes, deals, and free shipping to drive conversion |

> Feed uploads are processed as independent, asynchronous tasks. We don’t guarantee uploads are processed or completed in the order you submit them. If you upload multiple files in quick succession, a later upload can finish before an earlier one.

#### API

Use Stripe APIs to upload your product data CSV. We recommend using the sandbox to validate parsing, field mappings, and data quality before enabling live updates.

> If you use a [restricted API key](https://docs.stripe.com/keys.md#create-restricted-api-key), it must have **Product Catalog Import** write permission. Without this permission, API requests return a `403` error.

### Create an import

Create a `ProductCatalogImport` object using the [Product Catalog Import API](https://docs.stripe.com/api/v2/commerce/product-catalog-imports.md). Send the following request:

```curl
curl -X POST https://api.stripe.com/v2/commerce/product_catalog/imports \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-07-29.preview" \
  --json '{
    "feed_type": "product",
    "mode": "upsert",
    "metadata": {
        "file_name": "march_11_2026_product_upload.csv"
    }
  }'
```

A successful request returns the [ProductCatalogImport object](https://docs.stripe.com/api/v2/commerce/product-catalog-imports/object.md) in the `awaiting_upload` state. Use the presigned URL in the response’s `status_details.awaiting_upload.upload_url.url` field to upload your file:

```json
{
  "id": "pcimprt_xxx",
  "object": "v2.commerce.product_catalog_import",
  "created": "2026-03-26T00:35:01.000Z",
  "feed_type": "product",
  "status": "awaiting_upload",
  "status_details": {
    "awaiting_upload": {
      "upload_url": {
        "expires_at": "2026-03-26T00:40:02.000Z",
        "url": "https://stripeusercontent.com/files/us-west-2/upload/wksp_xxx"
      }
    }
  },
  "livemode": true
}
```

### Upload your CSV

> The presigned upload URL expires after 5 minutes. Upload your CSV before the URL expires. If it expires, create a new `ProductCatalogImport` to get a new upload URL.

Upload your CSV to the presigned URL. The maximum file size is 4 GB.

```curl
curl -X PUT \
  -H "Content-Type: text/csv" \
  --data-binary @"/path/to/your/file.csv" \
  "{{PRESIGNED_URL}}"
```

After Stripe receives the file, the import transitions from `awaiting_upload` to `processing`. Stripe validates the file and ingests the items.

#### Dashboard

Go to the [Feed history](https://dashboard.stripe.com/agentic-commerce/catalog) page in the Dashboard and upload your product data CSV. This page also shows the total number of products currently syndicated to connected agents. Use this count to confirm that syndication is keeping pace with your ingested catalog.

## Monitor feed status and resolve errors

Stripe processes your product data, validates and cleans it, then indexes it in a format you can send to AI agents. We recommend listening for webhook events so you’re notified as soon as indexing completes, instead of polling for status. You can monitor indexing progress in two ways:

#### Webhooks

Stripe sends terminal webhook events after product data indexing completes. Set up an endpoint to listen for `v2.commerce.product_catalog.imports.succeeded`, `v2.commerce.product_catalog.imports.succeeded_with_errors`, and `v2.commerce.product_catalog.imports.failed` events. Each event includes the `v2.commerce.product_catalog_import` object. See the [webhooks guide](https://docs.stripe.com/webhooks.md) for step-by-step instructions.

Here’s an example of the `v2.commerce.product_catalog.imports.succeeded` webhook payload:

```javascript
{
  "id": "evt_65THl3VA5Zt5cTqbP16T9R4DRrSQbEWmWeLUx7WmOR8B",
  "object": "v2.core.event",
  "type": "v2.commerce.product_catalog.imports.succeeded",
  "created": "2026-03-26T00:40:00.000Z",
  "livemode": true,
  "reason": null,
  "related_object": {
    "id": "pcimprt_61THl3VA5Zt5cTqbP16T9R4DRrSQbEWmWeLUx7WmOR8K",
    "type": "v2.commerce.product_catalog.imports",
    "url": "/v2/commerce/product_catalog/imports/pcimprt_61THl3VA5Zt5cTqbP16T9R4DRrSQbEWmWeLUx7WmOR8K"
  },
  "changes": {
    "before": {"status": "PROCESSING"},
    "after": {"status": "SUCCEEDED"}
  },
  "data": {}
}
```

The webhook doesn’t include the full import object. Use the `related_object.url` to retrieve it:

```curl
curl https://api.stripe.com/v2/commerce/product_catalog/imports/{{PRODUCTCATALOGIMPORT_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-07-29.preview"
```

If your import status is `succeeded_with_errors`, you can download the error file:

1. Look for the `status_details.succeeded_with_errors.error_file.download_url.url` field in the response.
2. Download the CSV directly from that URL within 5 minutes, before it expires.
3. The CSV contains only the rows that failed, with a leading `stripe_error_message` column describing each error.

> Error file URLs expire after 5 minutes. To get a new URL, call the [retrieve endpoint](https://docs.stripe.com/api/v2/commerce/product-catalog-imports/retrieve.md) again.

#### API

If you can’t receive webhook events, poll for status instead. Send a `GET` request to the import object and check the `status` field. Continue polling until the object reaches a terminal state: `succeeded`, `succeeded_with_errors`, or `failed`.

```curl
curl https://api.stripe.com/v2/commerce/product_catalog/imports/{{PRODUCTCATALOGIMPORT_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-07-29.preview"
```

If the import completes without errors, it reaches `succeeded`. If the file is structurally valid but contains row-level errors, it reaches `succeeded_with_errors`. If the import can’t complete (for example, because the file was never uploaded, is unreadable, or an internal error occurs), it reaches `failed`.

If your import status is `succeeded_with_errors`, you can download the error file:

1. Look for the `status_details.succeeded_with_errors.error_file.download_url.url` field in the response.
2. Download the CSV directly from that URL within 5 minutes, before it expires.
3. The CSV contains only the rows that failed, with a leading `stripe_error_message` column describing each error.

> Error file URLs expire after 5 minutes. To get a new URL, call the [retrieve endpoint](https://docs.stripe.com/api/v2/commerce/product-catalog-imports/retrieve.md) again.

## Send incremental inventory updates

Keeping inventory current is required to prevent checkout failures. Send incremental inventory updates through the [Imports API](https://docs.stripe.com/api/v2/commerce/product-catalog-imports.md). Use the same upload process as product data uploads, but set `feed_type` to `inventory`. Inventory feeds support only `upsert` mode. See the [inventory feed specification](https://docs.stripe.com/agentic-commerce/product-feed.md#inventory-feed-spec) for the required fields.

```curl
curl -X POST https://api.stripe.com/v2/commerce/product_catalog/imports \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-07-29.preview" \
  --json '{
    "feed_type": "inventory",
    "mode": "upsert",
    "metadata": {
        "file_name": "march_11_2026_inventory_upload.csv"
    }
  }'
```

## Send incremental price updates

Keeping prices current is required to prevent checkout failures. Send incremental price updates through the [Imports API](https://docs.stripe.com/api/v2/commerce/product-catalog-imports.md). Use the same upload process as product data uploads and set `feed_type` to `pricing`. Price feeds support only `upsert` mode. See the [price feed specification](https://docs.stripe.com/agentic-commerce/product-feed.md#price-feed-spec) for the required fields.

```curl
curl -X POST https://api.stripe.com/v2/commerce/product_catalog/imports \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-07-29.preview" \
  --json '{
    "feed_type": "pricing",
    "mode": "upsert",
    "metadata": {
        "file_name": "march_11_2026_pricing_upload.csv"
    }
  }'
```

Price mismatches, where the price shown to a shopper doesn’t match the price we charge, cause checkouts to fail. To keep the checkout price aligned with the quoted price:

- Upload pricing feeds as soon as prices change, not on a scheduled delay.
- `sale_price_effective_date` is required when you set a `sale_price`. Stripe uses the end date to stop applying the sale price automatically, with no feed update needed.
- If the [product price and availability hook](https://docs.stripe.com/agentic-commerce/for-sellers/hooks.md#product-price-availability) returns a different `price` or `sale_price` than your feed, the hook value takes precedence.

## Enable sales on an AI chat agent

When you’re ready to sell through an AI interface:

1. Go to the [Agentic commerce](https://dashboard.stripe.com/agentic-commerce) page in the Dashboard.
2. Find the agent you want to sell through and review its terms.
3. Click the overflow menu (⋯), then select **Request connection**.

We send the agent an approval request that the agent must accept. When the connection succeeds, the agent’s **Status** column shows **Enabled**. To pause or stop selling on an AI chat agent, disable it on the same page.

## Respond to purchases and fulfill orders

Monitor orders placed through AI chat agents in three ways.

#### Webhooks

Stripe sends `checkout.session.completed` after the agent completes an order. Each order generates a unique `checkout.session.completed` event. The webhook includes the [CheckoutSession](https://docs.stripe.com/api/checkout/sessions/object.md) object. Set up an endpoint to listen for `checkout.session.completed` events. See the [webhooks guide](https://docs.stripe.com/webhooks.md) for step-by-step instructions.

```javascript
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

// Use the secret provided by Stripe CLI for local testing
// or your webhook endpoint's secret
const endpointSecret = 'whsec_...';

app.post('/webhook', (request, response) => {
  const sig = request.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
  } catch (err) {
    response.status(400).send(`Webhook Error: ${err.message}`);
    return;
  }

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    // Fulfill the order using the session data
    fulfillCheckout(session.id);
  }

  response.status(200).send();
});
```

Here’s an example of the `checkout.session.completed` webhook payload:

```javascript
{
  "id": "evt_1SUz6YRhxngcl2jFHhAi1Wiu",
  "object": "event",
  "api_version": "2025-10-29.clover",
  "created": 1763511518,
  "data": {
    "object": {
      "id": "cs_test_a1exHOZ77Pg40P1hPtcWe2oT2xI8G9ruoQohXq6jkKldIPQaGsNSPQmOGZ",
      "object": "checkout.session",
       ...
      "total_details": {
        "amount_discount": 0,
        "amount_shipping": 0,
        "amount_tax": 0
      }
    }
  },
  "livemode": false,
  ...
  "type": "checkout.session.completed"
}
```

After you receive the webhook, retrieve all required fields with a single API call. To avoid multiple requests, expand sub-resources using the [expand](https://docs.stripe.com/api/expanding_objects.md) request parameter with the preview header `Stripe-Version: 2025-12-15.preview`.

```curl
curl https://api.stripe.com/v1/checkout/sessions/{{SESSION_ID}}?expand[]=line_items.data.price.product&expand[]=line_items.data.taxes&expand[]=payment_intent.latest_charge \
  -u <<YOUR_SECRET_KEY>>: \
  -H "Stripe-Version: 2025-12-15.preview"
```

See fields in the expanded [CheckoutSession](https://docs.stripe.com/api/checkout/sessions/object.md), such as `amount_total`, quantity, and SKU ID.

### Checkout session field reference

| Order field | Available resource | API path |
| --- | --- | --- |
| **Order date** | `CheckoutSession.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.created` |
| **Order quantity** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].quantity` |
| **SKU** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].price.external_reference` |
| **Product description** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].price.product.description` |
| **Unit price** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].price.unit_amount` |
| **Tax amount** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].Taxes[].amount` |
| **Tax type** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].Taxes[].Rate.tax_type` |
| **Tax rate** | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].Taxes[].Rate.percentage` |
| **ShippingAddress** | `CheckoutSessions` | `CheckoutSessions.CollectedInformation.shipping_details` |
| **BillingAddress** | `CheckoutSessions.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.billing_details` |
| **Last4** | `CheckoutSessions.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.payment_method_details.card.last4` |
| **ExpMonth** | `CheckoutSessions.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.payment_method_details.card.exp_month` |
| **ExpYear** | `CheckoutSessions.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.payment_method_details.card.exp_year` |
| **CreditCardType** | `CheckoutSessions.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.payment_method_details.card.brand` |
| **Final amount** | `CheckoutSessions` | `CheckoutSessions.amount_total` |
| **GTIN** (Private preview) | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].price.product.identifiers.gtin` |
| **MPN** (Private preview) | `CheckoutSessions` | `CheckoutSession.LineItems.Data[].price.product.identifiers.mpn` |
| **Agent details** (Private preview) | `CheckoutSession.PaymentIntent` | `CheckoutSessions.PaymentIntent.agent_details` |
| **OrderNo** | `CheckoutSession.PaymentIntent.LatestCharge` | `CheckoutSessions.PaymentIntent.LatestCharge.receipt_number` |

#### Dashboard

View orders on the [Transactions page](https://dashboard.stripe.com/payments) in the Dashboard, where they’re tagged with the originating agent. You can also filter transactions by agent names.

#### Batch processing

Instead of fulfilling each order individually, bulk fulfill orders using the [List CheckoutSessions endpoint](https://docs.stripe.com/api/checkout/sessions/list.md).

```curl
# List all successful CheckoutSessions in the last hour
curl https://api.stripe.com/v1/checkout/sessions?created[gt]={{TIMESTAMP}}&status=complete \
  -u <<YOUR_SECRET_KEY>>:
```

To prevent duplicate fulfillments, use the `starting_after` parameter.

```curl
curl https://api.stripe.com/v1/checkout/sessions?created[gt]={{TIMESTAMP}}&status=complete&starting_after={{LAST_SESSION_ID}} \
  -u <<YOUR_SECRET_KEY>>:
```

## Test your integration

You can test your integration directly from the Dashboard in a [sandbox](https://docs.stripe.com/sandboxes.md):

1. Go to the [Agentic Commerce](https://dashboard.stripe.com/agentic-commerce) page, then click **View feed**.
2. Hover over the product you want to test, then click **Test**.

## Optional configuration

After your core integration is live, use these optional guides to refine your setup:

- [Set up manual capture](https://docs.stripe.com/agentic-commerce/for-sellers/manual-capture.md): Capture payments manually instead of immediately after purchase.
- [Set up hooks](https://docs.stripe.com/agentic-commerce/for-sellers/hooks.md): Configure order approval, checkout customization, and product price and availability hooks.
- [Handle out-of-stock and price failures](https://docs.stripe.com/agentic-commerce/for-sellers/handle-checkout-failures.md): Keep checkouts from failing when inventory or prices change between feed refreshes.
- [Add promotions to drive conversion](https://docs.stripe.com/agentic-commerce/for-sellers/promotions.md): Offer discount codes, deals, and free shipping through agents.
- [Handle refunds and disputes](https://docs.stripe.com/agentic-commerce/for-sellers/refunds-and-disputes.md): Manage cancellations, refunds, and disputes for agentic checkouts.
- [Export your catalog feed](https://docs.stripe.com/agentic-commerce/for-sellers/export-catalog-feed.md): Export a snapshot of the catalog feed you imported into Stripe.

## See also

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