Learn

How to Implement ACP: A Merchant Integration Walkthrough

Andrew McPherson · Updated August 1, 2026

Depth · Advanced

Good for: Builders

Implementing the Agentic Commerce Protocol (ACP) as a merchant comes down to three responsibilities: publish a product feed so agents can find what you sell, host an Agentic Checkout API so an agent can build and complete a cart with you, and accept a Shared Payment Token so you get paid without your store ever touching a card. This guide walks through each, with the real endpoints and payloads from the spec. If you are already on Stripe, which co-authored ACP, most of this is provided and the lift is small; if you are on another processor, you implement the same open spec directly.

Throughout, remember the core principle: you stay the merchant of record. ACP standardizes the checkout handshake; it does not take over your store, your fulfillment, your tax, or your customer relationship.

Which spec revision this targets. The payloads below were built from the 2026-01-30 revision of ACP. The latest stable revision is 2026-04-17. Checked against the 2026-04-17 OpenAPI files, the endpoint set, the status-code behavior, the Shared Payment Token model and the Delegate Payment API are unchanged. Three things to know before you build. First, Idempotency-Key is now a required header on every POST, not an optional one. Second, 2026-04-17 adds cart, feed, orders, authentication and MCP surfaces that this guide does not cover. Third, the 2026-04-17 OpenAPI file’s own example payloads differ in places from the schema shapes introduced in 2026-01-30, most visibly on payment_data (see step 3). Treat the machine-readable spec in spec/2026-04-17/, plus your agent platform’s and payment provider’s own documentation, as authoritative, and validate before you ship.

How the pieces fit

The agent platform (for example ChatGPT) is the client. You, the merchant, are the server. The agent calls endpoints you host to create a checkout session, update it as the buyer chooses options, and complete it. Payment is tokenized by a payment provider into a Shared Payment Token that is scoped to you and to one exact cart total, and that token is handed to you on the final call. You charge it through your processor and return an order.

So an ACP integration is a small REST API you implement plus a payment step, not a connection you make to someone else’s system. That is what lets one integration work across every agent surface that speaks ACP.

Step 1: Publish a product feed

Before an agent can buy from you, it has to know what you sell. ACP merchants provide a structured product feed: each item with the fields an agent needs to choose and transact, including title, description, price, availability, images, and identifiers. The single most important property of the feed is that it matches your live store exactly. Agents transact against the data you publish, so a price or stock figure that has drifted from reality is the most common cause of a failed or wrong agent checkout. Keep the feed complete, structured, and current; on Stripe and similar platforms, feed syndication is largely handled for you. For the protocol-agnostic detail on getting this right, see how to prepare your product catalog for agentic commerce.

Step 2: Implement the Agentic Checkout API

This is the heart of the integration. You host five endpoints under a /checkout_sessions base path. Every request carries a few headers. Under 2026-04-17, four are required: Authorization (a bearer API key the agent platform presents, which you verify), Content-Type: application/json, API-Version (a date such as 2026-04-17), and Idempotency-Key on every POST (an opaque string of up to 255 characters, UUID v4 recommended, scoped to the authenticated identity plus the endpoint). Accept-Language, User-Agent, Request-Id, Signature, and Timestamp are optional but worth honoring.

POST /checkout_sessions                          create a session       -> 201 CheckoutSession
POST /checkout_sessions/{checkout_session_id}     update a session       -> 200 CheckoutSession
GET  /checkout_sessions/{checkout_session_id}     retrieve a session     -> 200 CheckoutSession
POST /checkout_sessions/{checkout_session_id}/complete  complete         -> 200 CheckoutSessionWithOrder
POST /checkout_sessions/{checkout_session_id}/cancel    cancel           -> 200 CheckoutSession

Note that update is a POST to the session path (there is no PUT or PATCH), and create returns 201 while the rest return 200. A cancel on a session that is already completed or canceled returns 405.

Create a session

The agent sends the line items, the settlement currency, and the capabilities it supports. Your job is to price the cart and return a full session.

POST /checkout_sessions
{
  "line_items": [
    { "item": { "id": "sku_running_shoe_42" }, "quantity": 1 }
  ],
  "currency": "usd",
  "buyer": { "email": "buyer@example.com" },
  "fulfillment_details": {
    "address": {
      "name": "Jane Doe", "line_one": "185 Berry Street", "city": "San Francisco",
      "state": "CA", "country": "US", "postal_code": "94107"
    }
  }
}

You respond with a CheckoutSession: an id, a status, the priced line_items, the totals, the fulfillment_options you can offer, any messages, your policy links, and your capabilities. Every monetary amount is an integer in minor units, so 4500 means 45.00 dollars.

{
  "id": "cs_01HV3P3ABC123",
  "status": "ready_for_payment",
  "currency": "usd",
  "line_items": [
    { "id": "li_001", "item": { "id": "sku_running_shoe_42" }, "quantity": 1,
      "totals": [{ "type": "subtotal", "display_text": "Subtotal", "amount": 12000 }] }
  ],
  "fulfillment_options": [
    { "type": "shipping", "id": "ship_standard", "title": "Standard (3-5 days)",
      "totals": [{ "type": "fulfillment", "display_text": "Shipping", "amount": 0 }] }
  ],
  "totals": [
    { "type": "subtotal", "display_text": "Subtotal", "amount": 12000 },
    { "type": "tax", "display_text": "Tax", "amount": 1080 },
    { "type": "total", "display_text": "Total", "amount": 13080 }
  ],
  "messages": [],
  "links": [{ "type": "return_policy", "url": "https://store.example.com/returns" }],
  "capabilities": {}
}

The session lifecycle

The status field drives the whole flow, and it is worth implementing as a state machine. The spec defines these values: incomplete, not_ready_for_payment, requires_escalation, authentication_required, ready_for_payment, pending_approval, complete_in_progress, completed, canceled, in_progress, and expired. The agent will not attempt payment until you report ready_for_payment, so your pricing, fulfillment, and validation logic should resolve the session to that status (or surface a clear message explaining what is missing).

Update a session

As the buyer chooses a shipping option or signs in, the agent posts a partial update. For example, selecting a fulfillment option:

POST /checkout_sessions/cs_01HV3P3ABC123
{
  "selected_fulfillment_options": [
    { "type": "shipping", "option_id": "ship_standard", "item_ids": ["li_001"] }
  ]
}

You recompute and return the updated session, including refreshed totals and a new status.

Step 3: Complete the checkout with a Shared Payment Token

This is the step people most often get wrong, so it is worth being precise. When the buyer pays, the payment provider issues a Shared Payment Token: a single-use credential scoped to your merchant id and the exact cart total, which the agent then hands to you. The token is delivered inside payment_data on the complete call. ACP’s 2026-01-30 payment-handlers release introduced a nested shape:

POST /checkout_sessions/cs_01HV3P3ABC123/complete
{
  "buyer": { "first_name": "Jane", "last_name": "Doe", "email": "buyer@example.com" },
  "payment_data": {
    "handler_id": "handler_stripe_card",
    "instrument": {
      "type": "card",
      "credential": { "type": "spt", "token": "spt_123" }
    }
  }
}

The credential.type of spt marks it as a Shared Payment Token, and handler_id names one of the payment handlers you advertised in your session capabilities.

Confirm the shape rather than assuming it. The 2026-01-30 changelog is explicit that the payment-handlers framework was a breaking change replacing { "token": "spt_123", "provider": "stripe" } with the nested form above. However, the current stable 2026-04-17 OpenAPI file still shows the flat { "token": "spt_123", "provider": "stripe" } form in its own complete-call examples, and Stripe’s ACP seller documentation also still documents the flat form. That is an unresolved inconsistency in ACP’s own published materials, not a settled answer, so check the expected shape with your agent platform and your payment provider and validate against the machine-readable schema before you go live. (The superficially similar nested handler_id plus credential.token structure in UCP is a different protocol’s payload; do not treat the two as interchangeable.)

Charge the token through your processor, and on success return a CheckoutSessionWithOrder, the session plus an order:

{
  "id": "cs_01HV3P3ABC123",
  "status": "completed",
  "order": {
    "id": "ord_88212",
    "checkout_session_id": "cs_01HV3P3ABC123",
    "permalink_url": "https://store.example.com/orders/88212",
    "status": "confirmed"
  }
}

The order.status progresses through confirmed, processing, shipped, and delivered as you fulfill.

Because the token is scoped to one merchant and one total and is single-use, the agent never holds reusable payment power and your store never sees the raw card. Merchants on Stripe can accept the token with minimal code. Merchants on other processors tokenize and charge through the protocol’s separate Delegate Payment API (POST /agentic_commerce/delegate_payment), which vaults a card under an allowance that fixes the max_amount, currency, merchant_id, checkout_session_id, and an expires_at, the same scoping by another route. It returns 201 with a vault token id (a vt_ prefixed string). That endpoint, its request shape and its allowance fields are unchanged in 2026-04-17. For the concepts behind all this, see how AI agents pay.

Security essentials

Three things keep the integration safe. Verify the bearer token on every request, so only authorized agent platforms can drive a checkout. Honor the optional Signature and Timestamp headers when present, by validating the detached signature over the request body within a short time window, to prevent tampering and replay. And implement idempotency properly, because under 2026-04-17 it is no longer optional. Store the Idempotency-Key against the request body and the endpoint, return the original result on a replay (with an Idempotent-Replayed: true response header), and handle the three defined failure cases: 400 with code idempotency_key_required when the header is missing, 409 with code idempotency_in_flight plus a Retry-After header when the original request is still processing, and 422 with code idempotency_conflict when the same key arrives with a different body. The Delegate Payment API uses the same idempotency and signing conventions.

Errors versus messages

ACP separates two kinds of problem, and your implementation should too. A protocol-level failure (malformed request, bad auth, rate limit) returns an Error object with a type, code, and message and an appropriate 4xx or 5xx status. A business-level condition that is part of a valid checkout (an item went out of stock, a coupon is invalid, a sign-in or 3-D Secure step is required) is not an HTTP error; it is a message inside an otherwise valid 200 session, with a code such as out_of_stock or requires_3ds and a matching status. Returning the right one is what lets an agent recover gracefully rather than giving up.

Test, then go live

Build against the spec’s examples and your processor’s sandbox first. Walk the full lifecycle: create a session, update it to select fulfillment, complete it with a test Shared Payment Token, and confirm you return an order. Check the unhappy paths too: an out-of-stock item, an expired session, an idempotent retry. When it behaves, going live is a matter of your processor enabling agentic payments and your feed being present and accurate. Then the same integration works across every ACP agent surface, which is the entire point of adopting a standard rather than building one deal at a time.

Where to go next

The conceptual companion to this page is ACP explained, and the authoritative detail lives in the ACP spec on GitHub, linked below. If your next step is exposing your own tools or data to agents rather than selling through them, see how to build a remote MCP server. And for where ACP sits among the other standards, see the protocol stack.

FAQ

What does a merchant actually have to build? A product feed, an Agentic Checkout API (create, update, get, complete, cancel a session), and payment handling that accepts a Shared Payment Token on completion. On Stripe much of this is provided.

How is the payment passed without my store seeing the card? On complete, the agent sends payment_data whose instrument.credential.token is a Shared Payment Token (credential.type of spt), scoped to your merchant id and the exact total. You charge that token; the raw card never reaches you.

Do I have to be on Stripe? No. Stripe provides a reference implementation, but ACP is an open standard. Other processors implement the same spec and use the Delegate Payment API or their own equivalent.

Which spec revision does this walkthrough target? The payloads were built from 2026-01-30. Latest stable is 2026-04-17, in which the endpoints, the Shared Payment Token model and the Delegate Payment API are unchanged, Idempotency-Key becomes required on every POST, and cart, feed, orders, authentication and MCP surfaces are added beyond what this guide covers.

What is the most common mistake? Assuming a payment_data shape without checking. The 2026-01-30 release replaced the flat { token, provider } form with the nested handler_id plus instrument.credential.token, but the 2026-04-17 OpenAPI file and Stripe’s ACP seller docs still show the flat form, so confirm with your agent platform and payment provider. The other common mistake is letting feed prices or stock drift from your live store, since amounts are integers in minor units and mismatches break checkout.

Primary sources

  1. Agentic Commerce Protocol specification (GitHub) · GitHub
  2. ACP Agentic Checkout API (OpenAPI, 2026-04-17) · GitHub, 2026-04-17
  3. ACP Delegate Payment API (OpenAPI, 2026-04-17) · GitHub, 2026-04-17
  4. ACP changelog (2026-01-30 payment handlers) · Agentic Commerce Protocol
  5. Stripe Agentic Commerce documentation · Stripe
  6. Stripe: Agentic Commerce Protocol · Stripe