What Is AP2 and How Do You Implement It in 2026?

AP2 turns a shopper's approval into a signed credential that a merchant and a payment processor can each verify on their own. By the end of this page you will know the three things a merchant site has to ship: discovery, a signed checkout, and mandate verification.

CategoryAgent & AI protocols StatusEmerging Maintained byGoogle and payment partners Glippy checkAgent Interactivity (category 10)

AP2 (Agent Payments Protocol) is an open protocol that lets an AI agent prove to a merchant, and to the parties that handle the money, that a real person authorised a specific purchase. It does this with mandates: selectively disclosable JWT credentials, signed on a trusted surface, that pin down what is being bought and what may be paid for it. AP2 is an authorisation layer only. It produces evidence, not funds, so a payment service provider still settles every transaction.

Why AP2 matters for AI visibility

Card networks, issuers and acquirers all assume a human clicked "buy" on a page they trust. An agent breaks that assumption, and the usual response is to decline the transaction or push the shopper back to a browser. AP2 gives every party in the chain something deterministic to check instead: a user-signed Checkout Mandate that fixes the terms, and a Payment Mandate bound to the same checkout by a hash. For a merchant this is the difference between being a destination an agent can complete a purchase at and being a destination it has to hand back to a human.

The version you should build against is AP2 v0.2, tagged on 28 April 2026. Two things changed enough to invalidate most of what was written about AP2 in 2025. First, Google donated the protocol to the FIDO Alliance on the same day, so ongoing standardisation happens there rather than in a Google-owned repository. Second, the mandate model was rebuilt: the Intent Mandate and Cart Mandate from v0.1 are gone, replaced by a Checkout Mandate and a Payment Mandate, each issued as an SD-JWT and each answering to one verifier. The commerce protocol underneath is no longer assumed to be A2A either. AP2 v0.2 documents its merchant-side wiring against the Universal Commerce Protocol.

Where the spec lives

AP2 is split across two documentation sites: the protocol itself defines the credentials, and UCP defines where those credentials sit in an actual HTTP request.

  • AP2 v0.2 specification - the normative document: five roles, the two mandate types, direct versus autonomous modes, and the verification rules each role MUST follow
  • google-agentic-commerce/AP2 on GitHub - the reference implementation, the Python SDK under code/sdk, canonical JSON schemas, and runnable human-present and human-not-present scenarios for cards and x402
  • UCP AP2 Mandates extension - the merchant-facing half: the capability name, the merchant_authorization signature rules, where the mandate goes on complete, and the error codes to return
  • AP2 security and privacy considerations - the threat model, which assumes prompt injection cannot be prevented and treats every agent as a potential attacker
  • RFC 9901, Selective Disclosure for JWTs - the SD-JWT format the mandates are built on, including the salting and digest rules AP2 relies on for privacy
  • FIDO Alliance announcement - where AP2 is now standardised, and worth watching if you need to know whether a field name is settled before you build on it

Three ways to implement AP2

A merchant plays one AP2 role and it takes three separate pieces of work. The first is a static discovery file, which is all you need to be visible to an agent that is checking whether you support mandates at all. The second is signing your own checkout responses, which is the smallest change with real cryptography in it and the one your platform team owns. The third is verifying an incoming mandate before you charge anything, which is where the AP2 SDK earns its place and where a mistake costs money.

01

Declare AP2 support in your UCP profile

Start here. An agent reads your profile before it builds a cart, and it decides from this document whether a mandate flow is even possible with you. Publishing the capability without a usable signing key in keys[] is the most common way to fail the negotiation, so add both in one commit.

json/.well-known/ucp
{
  "ucp": {
    "version": "2026-08-25",
    "services": {
      "dev.ucp.shopping": [
        {
          "version": "2026-08-25",
          "spec": "https://ucp.dev/2026-08-25/specification/overview/",
          "transport": "rest",
          "endpoint": "https://shop.example/ucp/v1"
        }
      ]
    },
    "capabilities": {
      "dev.ucp.shopping.checkout": [
        {
          "version": "2026-08-25",
          "spec": "https://ucp.dev/2026-08-25/specification/shopping/checkout",
          "schema": "https://ucp.dev/2026-08-25/schemas/shopping/checkout.json"
        }
      ],
      "dev.ucp.common.payment.ap2_mandate": [
        {
          "version": "2026-08-25",
          "spec": "https://ucp.dev/2026-08-25/specification/payment/extensions/ap2-mandates",
          "schema": "https://ucp.dev/2026-08-25/schemas/common/payment_ap2_mandate.json",
          "extends": "dev.ucp.shopping.checkout",
          "config": { "vp_formats_supported": { "dc+sd-jwt": {} } }
        }
      ]
    },
    "payment_handlers": {}
  },
  "keys": [
    {
      "kid": "business_2026",
      "kty": "EC",
      "crv": "P-256",
      "x": "qIVYZVLCrPZHGHjP17CTW0_-D9Lfw0EkjqF7xB4FivA",
      "y": "Mc4nN9LTDOBhfoUeg8Ye9WedFRhnZXZJA12Qp0zZ6F0",
      "use": "sig",
      "alg": "ES256"
    }
  ]
}

What this does: the agent computes the intersection of its capabilities and yours, sees dev.ucp.common.payment.ap2_mandate in it, and the session is then security locked: neither side may fall back to an unsigned checkout. The keys[] array is an RFC 7517 JWK Set, so the same document doubles as the key source the agent uses to verify your checkout signature.

02

Sign the checkout response the mandate will bind to

Once AP2 is negotiated, every checkout response you return must carry ap2.merchant_authorization. This is the merchant's own commitment to the price and line items, and the shopper's mandate is computed over it, so getting the canonicalisation right matters more than anything else on this page.

javascriptcheckout/sign.mjs
import { readFileSync } from 'node:fs';
import canonicalize from 'canonicalize';
import { FlattenedSign, importJWK } from 'jose';

// Private half of the "business_2026" ES256 key published in /.well-known/ucp.
const jwk = JSON.parse(readFileSync('./secrets/ap2-signing-key.json', 'utf8'));
const key = await importJWK(jwk, 'ES256');

export async function signCheckout(checkout) {
  // 1. The ap2 object is the one member excluded from its own signature.
  const { ap2: _unsigned, ...payload } = checkout;

  // 2. JCS (RFC 8785) keeps the bytes reproducible after any re-serialisation.
  const canonical = new TextEncoder().encode(canonicalize(payload));

  // 3. An ordinary JWS over base64url(header) + "." + base64url(canonical).
  const jws = await new FlattenedSign(canonical)
    .setProtectedHeader({ alg: 'ES256', kid: jwk.kid })
    .sign(key);

  // 4. Detached content form: header, two dots, signature. No payload inline.
  return {
    ...payload,
    ap2: { merchant_authorization: `${jws.protected}..${jws.signature}` },
  };
}

What this does: it produces the detached JWS the agent verifies before it shows the cart to a human, which is what stops a compromised agent from quietly editing the total between your response and the consent screen. Every member of the response is covered, so if you strip a field somewhere in your serialisation layer the signature stops verifying months later during a dispute.

03

Verify the checkout mandate before you call your PSP

This is the part you should not hand-roll. In a human-not-present flow the agent presents a delegation chain: the open mandate the shopper signed, plus a closed mandate the agent signed with its own key. The SDK walks the chain, and a separate step checks that the closed mandate actually falls inside the constraints of the open one.

pythoncheckout/ap2_complete.py
"""Called from the UCP complete_checkout handler. Deterministic code only."""

from ap2.sdk.checkout_mandate_chain import CheckoutMandateChain
from ap2.sdk.jwt_helper import create_jwt
from ap2.sdk.mandate import MandateClient
from ap2.sdk.receipt_wrapper import ReceiptClient
from ap2.sdk.utils import compute_sha256_b64url

mandates = MandateClient()
receipts = ReceiptClient()


def complete_checkout(body, session, resolve_issuer_key, merchant_key, psp):
    token = body.get("ap2", {}).get("checkout_mandate")
    if not token:
        return {"error": "mandate_required"}

    # 1. Signature, key binding, audience and expiry on every hop of the chain.
    payloads = mandates.verify(
        token=token,
        key_or_provider=resolve_issuer_key,
        expected_aud="merchant",
        expected_nonce=session.nonce,
    )

    # 2. The closed mandate must sit inside the open one the shopper signed,
    #    and must be bound to the checkout JWT you actually issued.
    chain = CheckoutMandateChain.parse(payloads)
    violations = chain.verify(
        expected_checkout_hash=compute_sha256_b64url(session.checkout_jwt),
        checkout_jwt=session.checkout_jwt,
    )
    if violations:
        return {"error": "mandate_scope_mismatch",
                "error_description": "; ".join(violations)}

    # 3. Only now does money move, and only through the payment processor.
    order_id = psp.charge(session, body["payment"]["instruments"])

    # 4. The receipt binds to the closed leaf JWT, so extra hops do not break it.
    receipt = receipts.create_checkout_receipt(
        merchant="https://shop.example",
        reference=compute_sha256_b64url(mandates.get_closed_mandate_jwt(token)),
        order_id=order_id,
    )
    header = {"alg": "ES256", "typ": "JWT"}
    return {"order_id": order_id,
            "checkout_receipt": create_jwt(header, receipt.model_dump(mode="json"), merchant_key)}

What this does: it converts an agent's claim into checkable evidence, then stops. The charge itself is still psp.charge, and the Payment Mandate travelling inside the payment token is verified by your processor, not by you. Returning a signed Checkout Receipt matters as much as approving: an agent is required to wait for a rejection receipt before it reuses an open mandate, so a silent failure is what lets a double spend through.

Implementation guidelines

These are the failure modes that show up once real mandates start arriving.

  1. Publish the key before you advertise the capability. Add the new JWK to keys[], wait for caches to pick it up, then start signing with it. UCP asks for a grace period of at least seven days before you remove an old kid, because a mandate signed under it stays verifiable only while the key is still listed.
  2. Canonicalise with JCS, never with your JSON encoder. The signature covers the JCS form of the whole checkout minus the ap2 member. Removing any other member, including anything under the ucp namespace, changes the signed bytes and invalidates the signature.
  3. Sign the checkout JWT with ECDSA, and know why. AP2 v0.2 requires a non-deterministic scheme such as ES256 so that the checkout_hash is not guessable from a small set of possible carts. The spec text and the security considerations disagree on whether this is an algorithm rule or an entropy rule, and AP2 issue 268 tracks the fix, so pin ES256 until it lands.
  4. Re-check the hash against the live session, not the mandate's own copy. Compute the digest of the checkout_jwt you last issued and compare it to checkout_hash. If a repriced cart produced a newer JWT, reject with mandate_scope_mismatch rather than honouring a stale approval.
  5. Keep open mandates short-lived and enforce the nonce. Open mandates carry the agent key as a cnf claim and should set exp to the smallest window that lets the task finish. Reject a replayed nonce outright; the chain verifier only checks the values you pass it.
  6. Always return a receipt, including on failure. A Checkout Receipt with status of Error plus error and error_description is what tells the agent it may safely retry. Silence looks identical to a slow success and encourages a second attempt on the same open mandate.
  7. Store the compact SD-JWT with its disclosures. Dispute evidence is reconstructed by recomputing sd_hash, checkout_hash and the receipt reference, which only works if you kept the exact serialisation you received rather than a parsed copy.

Do this, not that

Do

  • Publish an EC P-256 key with "alg": "ES256" in keys[] at /.well-known/ucp before you list the AP2 capability.
  • Reject a complete_checkout that lacks ap2.checkout_mandate with the mandate_required error code once AP2 has been negotiated.
  • Pass the payment token straight through to your PSP and let them verify the Payment Mandate against the same checkout_hash.
  • Run every verification step in deterministic code, which the spec requires whether or not your merchant surface is agentic.

Do not

  • Do not treat a valid mandate as proof of funds. Nothing has settled until a Payment Receipt comes back with a psp_confirmation_id.
  • Do not build merchant_authorization over a hand-built JSON string; without JCS the signature will not reverify after any downstream re-encoding.
  • Do not let a model summarise, paraphrase or re-emit a mandate. AP2 assumes prompt injection cannot be prevented and treats the agent as a potential attacker.
  • Do not reuse the v0.1 vocabulary. Intent Mandate and Cart Mandate no longer exist, and a vct of mandate.cart.1 will not validate against any v0.2 schema.

How Glippy checks this

Glippy scores AP2 under Agent Interactivity (category 10). It fetches your A2A agent card and looks for an AP2 entry in capabilities.extensions, and it reads your UCP profile to confirm the payment extension sits in the current dev.ucp.common.payment.* namespace rather than the retired dev.ucp.shopping.* one. The mandate exchange itself happens at runtime and is not statically observable, so these surfaces are bonus-scored: declaring them earns credit, and their absence is reported as a tip with no penalty. The AI agent accessibility checker shows the full list of agent-facing files Glippy looks for.

Check your AP2 setup

Glippy runs 240+ checks across 16 categories on any page, including Agent Interactivity (category 10). No sign-up required.

Frequently asked questions

No. AP2 is an authorisation and evidence layer, not a payment rail. It produces two signed credentials, a Checkout Mandate that protects the merchant and a Payment Mandate that protects the funds, and the second one is verified by a credential provider, the card network and your merchant payment processor. Money still moves through whoever settles your transactions today, and the Payment Receipt with its psp_confirmation_id comes from them, not from you.

The mandate model was replaced. Version 0.1 defined an Intent Mandate, a Cart Mandate and a Payment Mandate; v0.2, tagged on 28 April 2026, defines a Checkout Mandate and a Payment Mandate, each an SD-JWT with a versioned vct claim such as mandate.checkout.1. The release also added human-not-present flows, in which a shopper signs open mandates carrying constraints and the agent signs the matching closed mandates with its own key. Google donated the protocol to the FIDO Alliance on the same day, so standardisation continues there.

No. AP2 is described as an extension for A2A, MCP and UCP, and it is deliberately agnostic about the commerce protocol carrying it. In practice v0.2 documents the merchant path against UCP, where the credentials travel as ap2.merchant_authorization on your checkout response and ap2.checkout_mandate on the completion request. If you do expose an A2A merchant agent, the older agent card extension URI is https://github.com/google-agentic-commerce/ap2/tree/v0.1, and the reference repository still ships runnable A2A scenarios.

They sit at different layers, so they are not really alternatives. AP2 is agnostic about the payment instrument: new instruments are added by defining a type in the Payment Instrument object, and the reference repository ships x402 scenarios for both human-present and human-not-present flows alongside the card ones. If you already settle in stablecoins, AP2 is what supplies the proof that a person authorised the specific purchase before that settlement happens.

Reviewed against the primary sources on . These standards move quickly, so check the linked specs before you ship.

Check your site for AI search readiness

Start free with the Glippy Chrome extension for instant page checks. Scaling up? Automate audits across many URLs and your whole sitemap with the Glippy MCP server.

Add Glippy to Chrome – free Automate with the MCP server →