AgentWallet ·

How we shipped AP2 v0.1 in production.

Three mandates, two DIDs, one dedup table, a 400-line verifier. A field report from one of the only production AP2 implementations on the open internet — covering the IntentMandate / CartMandate / PaymentMandate chain (with the IntentMandate and PaymentMandate signed by the payer and the CartMandate signed by the merchant), did:web key discovery via /.well-known/did.json, the ap2_mandates(account_id, mandate_hash) replay table keyed by sha256(jws), AES-256-GCM-sealed private JWKs in the signing_keys table, ES256 / P-256 across the board, and eight gaps the AP2 v0.1 spec leaves to the implementer including FX snapshotting, partial settlement, did:web SSRF hardening, optional kid headers, and the role-confusion footgun that breaks most third-party implementations.

  • Three mandates, two signers — IntentMandate and PaymentMandate are issued by the payer DID, CartMandate is issued by the merchant DID. Mixing them up is the most common implementation error.
  • did:web for key discovery — resolve did:web:example.com to https://example.com/.well-known/did.json, inline or JWKS service entry. No certificate authority, no key-ceremony quorum.
  • Replay protection — sha256(jws) into ap2_mandates with UNIQUE (account_id, mandate_hash). Separate Idempotency-Key handling in middleware.
  • Stack — Express 5 + TypeScript 5.9 + jose for JWS + Drizzle ORM + Postgres + AES-256-GCM via lib/crypto.ts + ES256 / P-256.
  • Endpoint — POST /ap2/v1/payment for inbound payments; /.well-known/did.json, /.well-known/ap2-keys.json, /.well-known/jwks.json for key discovery.
  • Eight spec gaps the implementer has to fill in — exp seconds vs ms, merchant-signs-cart role confusion, parent-by-inlined-JWS not by id, cross-currency FX (we reject rather than convert), optional kid, did:web SSRF hardening, partial settlement undefined, and the Go reference's central-signing-service assumption.

Frequently asked questions

Is AP2 a payment rail or an authorization protocol?
Authorization only. AP2 produces a signed mandate-chain that proves a payer authorized a specific cart at a specific merchant up to a specific cap. It does not move money. You still need a settlement layer underneath — cards, ACH, USDC, whatever — to actually charge the buyer. At AgentWallet we settle via Payouts.com's 17 fiat rails and Coinbase CDP for USDC on Base.
How is AP2 different from x402 or ACP?
AP2 is about WHO is allowed to spend, and HOW MUCH. x402 is about HOW the API server tells the agent the price (HTTP 402 Payment Required + USDC on Base). ACP (Stripe's Agentic Commerce Protocol) is about WHAT credential the agent presents at a merchant — a Shared Payment Token bound to one cart, one merchant. They compose: AP2 mandate authorizes the spend, ACP SPT presents the card credential, x402 handles the API micro-payment leg. AgentWallet implements all three in production.
Do I need to be on Google Cloud to use AP2?
No. AP2 is an open spec. The reference implementation Google published is in Go and assumes a particular signing-service architecture, but the protocol itself is just signed JWS objects keyed by did:web. We implemented it in TypeScript on Node 24 with the jose library. The full mandate-chain verification path is roughly 400 lines of code.
Who else has shipped AP2 in production?
As of May 2026, we're aware of AgentWallet, Stripe (limited pilots with Link), and Google's own first-party demo. Cobo wrote the canonical public explainer for AP2 but does not implement the protocol — they're a custody layer that holds keys agents use to sign. Crossmint, Ramp, Circle, and Coinbase Agentic Wallets have no AP2 implementation as of writing.
What's the production endpoint?
POST /ap2/v1/payment, taking a PaymentMandate JWS in the body. The handler verifies the full chain, deduplicates against ap2_mandates(account_id, mandate_hash), persists the receipt, and returns a verified-mandate handle. Settlement on the underlying rail (card / ACH / USDC) is a separate call against the same mandate handle. Public key discovery is at /.well-known/did.json, /.well-known/ap2-keys.json, and /.well-known/jwks.json.
What's AgentWallet's AP2 implementation stack?
Express 5 + TypeScript 5.9, jose for JWS (compactVerify / importJWK / SignJWT), Drizzle ORM + Postgres for the signing_keys and ap2_mandates tables, AES-256-GCM-sealed private JWKs in the column sealed_private_jwk, ES256 / P-256 across the board, WebAuthn-bound principals at the human end, did:web resolution via did:web:agentwallet.ai and per-agent subdomains.