A few weeks ago I wrote about describing your site once so any AI can use it. Since then the thing I was hand-waving at ("agents will check out for users") stopped being hypothetical. OpenAI shipped ACP and Google shipped AP2, and they solve the same problem in almost opposite ways.
I implemented the merchant side of both. Here are the field notes, because the differences aren't obvious until you're in them.
The 30-second version
ACP (Agentic Commerce Protocol, OpenAI + Stripe) is session-based. The agent drives a live checkout session on your server, like a headless cart. It powers ChatGPT's Instant Checkout.
AP2 (Agent Payments Protocol, Google) is mandate-based. Your store signs a "here is the cart and the price" object; the buyer's agent signs a "I authorize this" object. It leans on verifiable credentials and now the FIDO Alliance.
Same goal. Completely different shape.
ACP: a checkout session you don't own the UI for
ACP is five REST endpoints and a state machine. The agent creates a session, updates it (address, shipping, coupon), and completes it:
POST /checkout_sessions create from line items
POST /checkout_sessions/:id update (address, shipping, discounts)
POST /checkout_sessions/:id/complete pay
What you return is a CheckoutSession: line items, live shipping options, and totals broken out (subtotal, discount, fulfillment, tax, total). Money is integer minor units (330 = $3.30). Payment completes when the agent hands you a Shared Payment Token and you charge it through Stripe. The card never touches the agent.
The mental model: it's your existing checkout, minus the browser.
AP2: sign the cart, don't run the session
AP2 has no session. The agent sends you an Intent Mandate ("a red basketball shoe, under $120"). You price it and return a Cart Mandate you have cryptographically signed:
{
"contents": { /* a W3C PaymentRequest: items, total, currency */ },
"merchant_authorization": "<RS256 JWT>" // iss, sub, aud, exp, jti, cart_hash
}
That JWT is a short-lived guarantee of the price. Amounts here are decimal major units (19.99), not cents. The buyer's credentials provider then returns a Payment Mandate signed on the user's side, and settlement runs through the payment network. Your job is to sign honestly and verify the binding.
The part nobody warns you about
If you support both, you're maintaining two different worlds: a stateful session vs a stateless signed document, minor units vs major units, you-charge vs network-settles.
And a subtle one that ate a day: the AP2 cart_hash has to be byte-identical across whoever computes it, or verification fails. JSON.stringify won't cut it (key order, number formatting, Go sorting map keys...). You need canonical JSON (RFC 8785 / JCS): sorted keys, no whitespace, integers without a decimal point. I only trusted it once every SDK produced the same golden string for the same object.
Why I didn't just pick one
I don't think merchants should have to. The catalog, the prices, the stock, the "is this allowed" rules are the same regardless of which protocol an agent speaks. So in AI2Web I built both on top of one manifest: describe the store once, and it serves an ACP session or signs an AP2 cart from the same source of truth. Same safety model too: server-authoritative pricing, no card data through the agent, and anything that moves money previews for approval.
That's the bet from the last post, now with real protocols under it instead of hand-waving.
What I want to know
Genuinely unsure here, and this is the useful question:
If you only support one, which and why? Is ChatGPT distribution (ACP) worth more than being on Google's rails (AP2), or vice versa?
Does a layer that gives you both earn its keep, or is two direct integrations honestly fine?
For the crypto folks: is per-merchant Cart Mandate signing the right trust boundary, or is it security theater until the user side is verified by the network?
It's early and open source (code MIT, spec CC-BY).
Validator you can point at any site:
https://ai2web.dev
Code and spec:
https://github.com/ai2web-foundation
Two protocols, one catalog. Tell me where that breaks.
Top comments (0)