Agentic Commerce Protocol integration: the endpoints your store actually has to build
What an Agentic Commerce Protocol integration really involves: the four checkout endpoints, delegated payment tokens, capability negotiation and error rules.
Long Nguyen
Développeur fullstack · Ingénieur IA · Chercheur
What an ACP integration actually involves
The Agentic Commerce Protocol (ACP) is a seller-implemented REST interface. The agent — ChatGPT today, any compatible client later — renders the checkout UI and collects the buyer's selections and payment credentials. Your server stays the source of truth for pricing, tax, inventory and the order, and you remain the merchant of record.
That framing sets the scope of the whole project. An ACP integration is not a storefront, a plugin, or a product feed. It is four HTTPS endpoints that return the complete state of a checkout session on every single call, plus one payment step your PSP implements on your behalf.
| Piece | Who builds it | Where it runs |
|---|---|---|
| Checkout session API (4 endpoints) | You | Your commerce backend |
| Delegate payment endpoint | Your PSP | POST /agentic_commerce/delegate_payment at the PSP |
| Charging the token | You | Your existing PSP integration |
| Catalogue visibility inside the agent | The AI platform | Separate merchant onboarding |
Two things follow that teams usually discover late. First, the protocol is version-pinned by a date-based API-Version request header — is the published version at the time of writing — so you are building against a moving spec with breaking releases, not a stable v1. Second, implementing ACP does not put your products in front of anyone. Each AI platform runs its own application process; the spec only makes you transactable once you are accepted.
The four checkout endpoints, in the order the agent calls them
Every endpoint returns the same object: the full, authoritative checkout session. There are no deltas, no partial responses, and no server-side assumption that the agent remembers anything. In practice the serializer that builds that object is your integration — most of the work is making one function emit correct line items, totals, fulfilment options and messages fast enough to sit inside a conversation.
| Call | Endpoint | Success | Notable failures |
|---|---|---|---|
| Create session | POST /checkout_sessions |
201 | 422 when business logic blocks it (out of stock) |
| Read session | GET /checkout_sessions/{id} |
200 | 404 unknown session |
| Update session | POST /checkout_sessions/{id} |
200 | 422 when the update cannot be applied |
| Complete | POST /checkout_sessions/{id}/complete |
200 + order | 402 payment failed, 409 already completed |
| Cancel | POST /checkout_sessions/{id}/cancel |
200 | 405 already completed or canceled |
Three details that cause rework
- Amounts are integers in minor units.
unit_amount: 7999is $79.99. Any decimal arithmetic in your pricing layer has to be rounded and converted once, at the edge, not scattered through the serializer. - An update replaces the item list, it does not merge it. Treating
line_itemsas a patch is the single most common cart bug in agent integrations — it silently doubles quantities when the buyer changes their mind twice. - The
statusenum is a state machine, not a label. Values such asnot_ready_for_payment,ready_for_payment,requires_escalationandcompletedare what the agent branches on. If you returnready_for_paymentbefore a shipping option has been selected and the totals recalculated, the agent will attempt payment against a total you cannot honour.
The canonical field list lives in the ACP checkout API reference; build your response schema from it rather than from an example payload, because the required fields have changed between releases.
Capability negotiation: the part that breaks on upgrade
Since the release, every request carries a capabilities object describing what the agent supports, and every response must carry the seller's answer — the intersection of what both sides can do. The point is to fail fast: an unsupported payment handler or a 3-D Secure requirement the agent cannot render is discovered before authorisation, not after.
The same release replaced the flat payment-provider field with structured handlers, and it is a breaking change. Old integrations declared payment_provider.supported_payment_methods; current ones declare capabilities.payment.handlers[], where each handler names itself in reverse-DNS form, pins its own version, and states whether it needs delegated payment and whether it routes PCI-sensitive data.
{
"capabilities": {
"payment": {
"handlers": [
{
"id": "handler_stripe_card",
"name": "dev.acp.tokenized.card",
"version": "2026-01-30",
"requires_delegate_payment": true,
"requires_pci_compliance": false,
"psp": "stripe"
}
]
},
"interventions": { "supported": ["3ds"] },
"extensions": ["discount"]
}
}
Engineering judgment here: branch on the API-Version header, never on the shape of the payload. Date-versioned specs with breaking releases reward a thin request adapter per version and a single internal domain model behind it. Teams that inspect the body to guess the version end up with a parser that quietly accepts both and serves neither correctly.
Extensions follow the same discipline. The discount extension is opt-in and declared as discount@2026-01-30; if you do not declare it, nothing in your existing flow has to change. Add it only when you can actually validate codes synchronously, including the rejection reasons.
How payment works, and who carries the risk
The buyer's card never reaches the agent in usable form and never reaches you at all. The agent sends the credential to your PSP's delegate-payment endpoint, which returns a vault token constrained by an allowance. That allowance is what makes the token safe to hand around: a single-use reason, a maximum amount, a currency, an expiry, and the specific checkout session and merchant it may be spent against.
{
"allowance": {
"reason": "one_time",
"max_amount": 10000,
"currency": "usd",
"checkout_session_id": "cs_123",
"merchant_id": "acme_corp",
"expires_at": "2026-02-15T18:30:00Z"
}
}
Your complete call then receives the token inside the payment handler envelope, and you charge it through the PSP integration you already have:
POST /checkout_sessions/cs_123/complete
{
"payment_data": {
"handler_id": "handler_stripe_card",
"instrument": {
"type": "card",
"credential": { "type": "spt", "token": "spt_123" }
}
}
}
Read the allowance fields as a hard contract, not as metadata. A token bound to max_amount fails if your final total drifted upward between the last update and completion — a shipping surcharge, a tax recalculation, a currency rounding difference. Agent checkouts therefore punish exactly the pricing sloppiness that a human checkout page hides behind a visible total.
And because you stay the merchant of record, you keep what that implies: refunds, chargebacks, tax liability and customer support are yours. The protocol moves the interface, not the risk. The request and response schemas are set out in the delegate payment specification.
The error rule that decides whether a sale survives
This is the highest-value distinction in the whole spec and the one most implementations get backwards. ACP has two different error shapes, and choosing the wrong one ends the conversation.
| Situation | Return | What the agent can do |
|---|---|---|
| Session is valid, something is wrong with it (bad email, item out of stock, 3DS needed) | 2xx with a valid session and a MessageError in messages[] |
Ask the buyer to fix it and continue |
| No valid session can be returned (malformed request, idempotency violation, server failure) | 4xx/5xx with the protocol Error object |
Abandon or retry |
Each message carries a machine-readable code (out_of_stock, invalid, requires_3ds, quantity_exceeded) and a param that is a JSONPath to the offending field, for example $.buyer.email. That pair is what lets the agent say "that email looks wrong, what should I use?" instead of "checkout failed".
Most commerce backends do the opposite by default: a validation layer raises, a framework handler turns it into a 422, and the conversation dies. Mapping your domain exceptions onto message codes is a deliberate piece of work, and it is worth more to conversion than anything else on this list. Treat anything the buyer could plausibly fix in one sentence as a message on a 200, not as an HTTP failure.
One matching operational detail: send and honour Idempotency-Key on completion. An agent that retries a timed-out complete call must not create a second order, and the echo of the key in your response is what lets it tell a retry from a new attempt.
ACP, UCP and AP2 — which one to build first
ACP is not the only protocol in this space, and the three being discussed most often solve different problems. Confusing them leads to merchants building the wrong thing for the surface they actually care about.
| Protocol | Backed by | Solves | Merchant surface |
|---|---|---|---|
| ACP | OpenAI and Stripe | Checkout between an agent and a seller | REST endpoints you host |
| UCP | Google, with major retailers and platforms (announced January 2026) | Discovery through to checkout across Google's surfaces | Merchant Center data plus platform integration |
| AP2 | Google-led, open source | Authorising an agent to pay, via signed mandates | Payment layer, usually under another protocol |
A reasonable sequencing rule: pick the protocol that matches the surface where your buyers already are, and let your platform do the work wherever it can. If you sell on Shopify, agent checkout arrives largely as a platform capability, and your job is catalogue quality rather than endpoints. If you run a custom stack — Django, Laravel, Node, a headless setup — ACP is the smaller and better-documented surface to implement first, because it is four endpoints and a token rather than a platform-wide data contract.
What none of the three fixes is demand. An agent that cannot find a reason to recommend your product will never reach your checkout endpoints, however correct they are.
A sequencing checklist for a real store
Having built marketplace integrations across Amazon SP-API, eBay, TikTok Shop and Shopify, the sharpest difference with ACP is tempo. Marketplace work is asynchronous: you push listings, you poll orders, and a slow job is an operational annoyance. ACP is synchronous and conversational — your latency is the buyer's latency, and your pricing errors surface inside a chat window in real time. Sequence the work accordingly.
- Fix catalogue truth first. Stable item ids, correct variant mapping, real availability, prices that match what you would charge on your own site. Everything downstream inherits these errors.
- Build an authoritative quote service. One call that takes items plus an address and returns line items, shipping options, tax and totals, synchronously. If that cannot answer in a few hundred milliseconds, the rest of the integration will feel broken no matter how correct it is.
- Then the session state machine. Persist sessions, enforce the status transitions, make update replace rather than merge, and decide explicitly whether creating a session reserves inventory — the cancel endpoint exists so you can release it.
- Then payments. Declare your handlers, wire the vault token into your existing PSP charge path, and test the drift case where the final total exceeds the allowance.
- Then error mapping and observability. Domain errors to message codes, plus logs keyed by
Request-Idand session id so you can reconstruct a failed conversation.
For most teams, steps 1 and 2 are the real project; steps 3 to 5 are a couple of focused weeks on top of a backend that already prices correctly. If your pricing, tax and stock logic currently lives inside a checkout template rather than in a service, that refactor is the integration. This is the same groundwork we do when we take on eCommerce platform and API integration work, and it pays off well beyond agent traffic.
Starting from a store that is not sure its totals are reproducible outside its own checkout page? Tell us what you are running and we will scope the work — what has to change in your backend before ACP endpoints are worth writing, and what can be left alone.
FAQ
Questions fréquentes
Do I have to use Stripe to implement the Agentic Commerce Protocol?
No. ACP works with any compatible payment service provider; Stripe was the first with a shared payment token implementation. What matters is that your PSP exposes a delegate payment endpoint that issues allowance-scoped tokens, and that you declare the matching handler in your capabilities object.
Does implementing ACP mean my products appear inside ChatGPT?
No. The protocol makes your checkout transactable by any compatible agent, but each AI platform runs its own merchant onboarding and decides which catalogues appear. Treat the integration and the listing application as two separate workstreams.
Who is the merchant of record in an ACP transaction?
You are. The agent renders the interface and relays payment credentials, but the order, the tax liability, refunds, chargebacks and customer support all stay with your business. The protocol changes the interface, not the commercial risk.
How long does an ACP integration take?
The endpoints themselves are a few focused weeks for a backend that can already produce authoritative totals including tax and shipping for an arbitrary address. If that pricing logic lives inside your checkout templates, extracting it into a service is the larger part of the project.
Should I build ACP endpoints if I'm on Shopify or WooCommerce?
On a managed platform, check what the platform ships before writing code, since agent checkout is increasingly a platform capability and your effort is better spent on catalogue and feed quality. Custom stacks are where a direct ACP implementation makes sense, because nothing else will expose the endpoints for you.