| [ Web Proxy ] |
| Viewing: https://docs.stripe.com/agentic-commerce/for-sellers | [Back] [Original] |
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.
If you operate a platform, see the guide for platforms.
To get set up for agentic commerce:
stripe_product_tax_code if you use Stripe Tax for automatic tax calculation (follow the tax setup guide to configure it), or set third_party_tax_code if you use Anrok instead. See the price and promotions field reference for details on these fields.Create a catalog feed 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.
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 isnt available (even if its 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.
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 and incremental price feeds instead of re-uploading your entire catalog.
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 Stripes catalog. To explicitly remove it, set delete=true. Otherwise, the product remains visible to shoppers and agents.
Feed uploads support two processing modes: upsert and replace. In replace mode, any product not included in the uploaded file is permanently deleted from Stripes catalog. Use upsert for all incremental updates and reserve replace mode for intentional full-catalog refreshes. See Feed processing mode.
| Feed type | Frequency | Purpose |
|---|---|---|
| Product data | Once per day | Titles, descriptions, images, and categories |
| Inventory | Every 15 minutes | Prevents agents from showing out-of-stock items |
| Pricing | Every 15 minutes | Helps keep the checkout price aligned with the quoted price |
| Promotions | As needed | Offers discount codes, deals, and free shipping to drive conversion |
Feed uploads are processed as independent, asynchronous tasks. We dont 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.
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, it must have Product Catalog Import write permission. Without this permission, API requests return a 403 error.
Create a ProductCatalogImport object using the Product Catalog Import API. Send the following request:
curl -X POST https://api.stripe.com/v2/commerce/product_catalog/imports \ -H "Authorization: Bearer sk_test_wU7nrJCZspk1NPDxiQgAF05q" \ -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 in the awaiting_upload state. Use the presigned URL in the responses status_details.awaiting_upload.upload_url.url field to upload your file:
{ "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 }
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 -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.
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 youre notified as soon as indexing completes, instead of polling for status. You can monitor indexing progress in two ways:
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 for step-by-step instructions.
Heres an example of the v2.commerce.product_catalog.imports.succeeded webhook payload:
{ "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 doesnt include the full import object. Use the related_object.url to retrieve it:
If your import status is succeeded_with_errors, you can download the error file:
status_details.succeeded_with_errors.error_file.download_url.url field in the response.stripe_error_message column describing each error.Error file URLs expire after 5 minutes. To get a new URL, call the retrieve endpoint again.
Keeping inventory current is required to prevent checkout failures. Send incremental inventory updates through the Imports API. 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 for the required fields.
curl -X POST https://api.stripe.com/v2/commerce/product_catalog/imports \ -H "Authorization: Bearer sk_test_wU7nrJCZspk1NPDxiQgAF05q" \ -H "Stripe-Version: 2026-07-29.preview" \ --json '{ "feed_type": "inventory", "mode": "upsert", "metadata": { "file_name": "march_11_2026_inventory_upload.csv" } }'
Keeping prices current is required to prevent checkout failures. Send incremental price updates through the Imports API. 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 for the required fields.
curl -X POST https://api.stripe.com/v2/commerce/product_catalog/imports \ -H "Authorization: Bearer sk_test_wU7nrJCZspk1NPDxiQgAF05q" \ -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 doesnt match the price we charge, cause checkouts to fail. To keep the checkout price aligned with the quoted price:
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.price or sale_price than your feed, the hook value takes precedence.When youre ready to sell through an AI interface:
We send the agent an approval request that the agent must accept. When the connection succeeds, the agents Status column shows Enabled. To pause or stop selling on an AI chat agent, disable it on the same page.
Monitor orders placed through AI chat agents in three ways.
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 object. Set up an endpoint to listen for checkout.session.completed events. See the webhooks guide for step-by-step instructions.
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(); });
Heres an example of the checkout.session.completed webhook payload:
{ "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 request parameter with the preview header Stripe-Version: 2025-12-15.preview.
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 sk_test_wU7nrJCZspk1NPDxiQgAF05q: \ -H "Stripe-Version: 2025-12-15.preview"
See fields in the expanded CheckoutSession, such as amount_total, quantity, and SKU ID.
You can test your integration directly from the Dashboard in a sandbox:
After your core integration is live, use these optional guides to refine your setup:
| Web Proxy Viewer | New URL | Original Page |