How to Read an AP2 Mandate or Visa/Mastercard Agent Token Schema — telling a populated security field from a permissive one
This page is the practical companion to Google AP2 — the one agent-payment authorization spec that shipped code, not just a press release and Agent Identity and Credentialing — Why the Authorization Layer Needs to Know Who's Asking: it shows where each protocol's real field definitions live, walks one schema (AP2's closed Payment Mandate) field by field, and gives a checklist for telling a mandate that actually enforces spend limits and expiry from one that only looks like it does. This is the operational tool for the "spec vs press release" test that How to Verify an Agent-Payment Protocol Claim Before Citing It — the four checks this wiki runs on every page applies at the protocol level, applied here at the field level.
Where to Find the Actual Schema Definitions
Don't cite a diagram or a blog post as if it were the schema — go to the source that defines the fields:
- AP2 (Google): Payment Mandate and Checkout Mandate schemas are published at https://ap2-protocol.org/ across three pages — overview at /ap2/specification/, /ap2/payment_mandate/, /ap2/checkout_mandate/. The canonical JSON schemas also live in the GitHub repo at code/sdk/python/ap2/schemas/ (https://github.com/google-agentic-commerce/AP2).
- Agentic Commerce Protocol (ACP, Stripe/OpenAI): JSON Schema files are at spec/2026-04-17/json-schema/ in https://github.com/agentic-commerce-protocol/agentic-commerce-protocol; the payment-token API surface is the OpenAPI file spec/2026-04-17/openapi/openapi.delegate_payment.yaml (2026-04-17 is the latest stable specification directory — a dated version, not a GitHub release tag; the repo's Releases and tags are both empty as of this writing. Unreleased work sits in spec/unreleased/).
- Visa: Intelligent Commerce agent-credential docs are at https://developer.visa.com/capabilities/visa-intelligent-commerce, with the underlying Visa Token Service (VTS) APIs at https://developer.visa.com/capabilities/vts. The Trusted Agent Protocol (TAP) — HTTP Message Signatures per RFC 9421 — is specified at https://developer.visa.com/capabilities/trusted-agent-protocol/trusted-agent-protocol-specifications and mirrored at https://github.com/visa/trusted-agent-protocol.
- Mastercard AP4M: as of the June 10, 2026 launch press release, the full protocol specification is not publicly available; agent credentials and spending authority are recorded on public blockchains (Polygon, Solana, Base), but there is no equivalent of an AP2 schema page to point to (https://www.mastercard.com/us/en/news-and-trends/press/2026/june/mastercard-launches-agent-pay-for-machines.html). Treat any "AP4M schema" description found elsewhere as secondhand until Mastercard publishes one.
- Coinbase Agentic Wallets: spend-limit and session-cap configuration is documented at https://docs.cdp.coinbase.com/agentic-wallet/welcome.
- x402: the payment-request schema is defined in the HTTP header fields at https://docs.x402.org/core-concepts/http-402 (also https://www.x402.org/) — payment scheme, CAIP-2 network identifier, asset contract, recipient, max amount, expiry, optional facilitator.
Open gap to flag when citing AP2
AP2 GitHub issue #127 ("Published JSON schema definitions for mandate credentials") was an open request, as of when these notes were taken, to provide full Verifiable Credential schema support for AP2 mandates — meaning the machine-readable schema was not yet fully published at that point (unverified whether resolved since; check the repo's current issue status before citing this as still-open).
Field-by-Field: The AP2 Closed Payment Mandate
The AP2 closed Payment Mandate (vct: "mandate.payment.1") is a W3C Verifiable Credential encoded as an SD-JWT with Key Binding (+kb). Its fields, per https://ap2-protocol.org/ap2/payment_mandate/:
| Field | Type | Required? | Purpose |
|---|---|---|---|
| vct | string | required | Must be literally "mandate.payment.1" for this closed mandate; the open-mandate variant uses "mandate.payment.open.1" instead — there is no bare "mandate.payment" value |
| transaction_id | string | required | Base64url-encoded hash binding the payment to a specific checkout |
| payee | object (id, name required; website optional) | required | The merchant receiving payment |
| pisp | object (legal_name, brand_name, domain_name) | optional | Present only when a third-party Payment Initiation Service Provider intermediates |
| payment_amount | object (currency ISO 4217, amount integer in minor units) | required | E.g. {"currency": "USD", "amount": 1050} = $10.50 |
| payment_instrument | object (id, type required; description optional) | required | The payment method used |
| execution_date | ISO8601 date | optional | Absent = immediate execution |
| risk_data | object | optional | Risk signals, opaque to this schema |
| iat | Unix epoch integer | optional | Creation timestamp |
| exp | Unix epoch integer | optional | Absence means no expiry constraint at all — see the checklist below |
Signatures use ES256 (ECDSA/SHA-256) over the payload canonicalized per RFC 8785 (JSON Canonicalization Scheme); the Key Binding JWT is appended to the SD-JWT to bind the mandate cryptographically to a specific agent/wallet key (https://ap2-protocol.org/ap2/specification/).
Checkout Mandate note
the Checkout Mandate schema marks each field Disclosable: Yes/No for selective disclosure. A merchant receiving a Checkout Mandate with selectively-disclosed line items cannot see the full cart — it only sees checkout_hash, a hash binding to the full (possibly hidden) cart contents (https://ap2-protocol.org/ap2/checkout_mandate/).
For comparison, Visa TAP authenticates the agent, not a payment mandate object: agent identity rides in an HTTP Signature-Input header (RFC 9421) carrying @authority, @path, created, expires, keyid, alg, nonce, tag. The tag value distinguishes "agent-browser-auth" from "agent-payer-auth". Servers reject reused or expired signatures — the nonce plus expires timestamp is the replay defense (https://developer.visa.com/capabilities/trusted-agent-protocol/trusted-agent-protocol-specifications).
Common Misreadings
Optional ≠ safe to ignore. In JSON Schema, the required array lists what MUST be present; anything absent from it is optional — but optional fields are frequently security-relevant. AP2's exp is the clearest case: it's not in the required array, so a Payment Mandate that omits it is schema-valid, yet the credential then has no expiry constraint and stays valid indefinitely — a security gap many implementations fail to catch (https://ap2-protocol.org/ap2/payment_mandate/, https://jsonic.io/guides/json-schema-required-fields).
Present ≠ populated correctly. required validates presence, not value: a required field passes validation even if it's an empty string, null, 0, or false. Visa TAP's signature field is required, but nothing in the schema itself stops an implementation from submitting a required-but-empty signature that still clears basic schema validation — only runtime cryptographic verification catches that (https://jsonic.io/guides/json-schema-required-fields, https://developer.visa.com/capabilities/trusted-agent-protocol/trusted-agent-protocol-specifications).
Optional and nullable are different axes. A field can be optional (can be absent) yet non-nullable (if present, must not be null) — omitting a field and setting it to null are distinct outcomes under validation, and conflating them is a common implementer error (https://dev.toolbox.tech/tools/json-schema-generator/examples/required-vs-optional).
Demo payload ≠ production schema. An example JSON payload in a README or doc page may omit optional fields or use placeholders; the separately-published schema (JSON Schema or OpenAPI file) is the normative source, and treating a minimal example as if it were exhaustive is the reverse of the correct contract-testing direction — you validate demo payloads *against* the production schema, not the other way around (https://pactflow.io/blog/contract-testing-using-json-schemas-and-open-api-part-2/, https://github.com/agentic-commerce-protocol/agentic-commerce-protocol, which keeps example payloads and schema definitions in separate repo directories).
Checklist: Does This Implementation Actually Enforce Security-Relevant Fields?
Run every mandate/token payload you're evaluating through this list before trusting it:
Required fields present and non-empty
- AP2 Payment Mandate: vct, transaction_id, payee, payment_amount, payment_instrument all present and non-empty.
- Visa TAP: Signature-Input header includes all of @authority, @path, created, expires, keyid, alg, nonce, tag — reject if any is missing.
Expiry
- If exp is present: confirm it's a Unix epoch integer representing a *future* timestamp at validation time.
- If exp is absent (legal, since it's optional): the implementation MUST have a compensating control — a recent, checked iat, or an explicit business rule bounding mandate lifetime. No compensating control = an indefinitely valid mandate.
- Visa TAP's expires field is required in Signature-Input; confirm it's actually checked at request time and expired signatures are rejected.
Signature and cryptographic binding
- Confirm the signature is verified against the canonicalized payload (RFC 8785 JCS for AP2) using the issuer's public key — never accept an unverified signature.
- For AP2: confirm the Key Binding JWT appended to the SD-JWT binds the credential to the *presenting agent's* key, not just any valid key.
- For Visa TAP: confirm the Signature header matches the RFC 9421-computed signature over the actual signed message.
Scope and constraint fields
- Checkout Mandate: checkout_hash present and non-empty.
- Any constraint field (e.g. Allowed Merchants, Line Items): populated with specific values — not a wildcard, not an empty array.
- Visa TAP: nonce present and unique per request; reject reused nonces.
Red flags — stop and treat the implementation as non-compliant if
- signature is missing, null, empty string, or optional with no compensating control.
- exp is absent AND iat is also absent or stale beyond a defined grace period.
- A constraint array is empty or contains a catch-all (e.g. merchant id "*").
- payee lacks a merchant id — a payment with no identifiable recipient.
Test procedure
extract the payload (pre-signature JSON) from a *real* mandate in production, not a minimal demo from the docs; validate it against the published JSON Schema with a validator library (jsonschema in Python, Ajv in JavaScript, per https://json-schema.org/draft/2020-12/json-schema-core); then write one unit test per security-critical field (exp, signature, scope constraints) that fails if the field is missing or empty.
Why this page serves the wiki's objective
the wiki's core test is "spec vs press release, outside implementation vs none, figure with a base vs without" — but that test can't be run at all if you can't locate and read the actual schema. This page is the mechanical step underneath How to Verify an Agent-Payment Protocol Claim Before Citing It — the four checks this wiki runs on every page: before judging whether a claimed AP2 or Visa TAP security property is real, you first have to be able to open the schema, find the field, and tell "required-and-enforced" from "present-in-the-doc-but-optional-and-unchecked."
Related
- Google AP2 — the one agent-payment authorization spec that shipped code, not just a press release — this page's field walkthrough of the Payment Mandate is the detail layer under that page's higher-level "what's published vs a whitepaper claim" verdict on AP2. - Agent Identity and Credentialing — Why the Authorization Layer Needs to Know Who's Asking — Visa TAP's Signature-Input fields, read here field by field, are exactly the mechanism that page discusses as identity-proof-vs-assertion. - How to Verify an Agent-Payment Protocol Claim Before Citing It — the four checks this wiki runs on every page — the protocol-level version of the same discipline this page applies at the field level; use both together when evaluating a specific implementation claim. - Mandate Expression Compared — AP2, AP4M, Visa, ACP, Coinbase Side by Side, Where the Constraint Actually Lives — the side-by-side comparison of how AP2, AP4M, Visa and ACP express constraints draws on the field definitions catalogued here.
Verified against
57 claims checked against these sources · 2 refuted and removed
- ap2-protocol.org/ap2/payment_mandate
- ap2-protocol.org/ap2/specification
- ap2-protocol.org/ap2/checkout_mandate
- developer.visa.com/capabilities/trusted-agent-protocol/trusted-…
- jsonic.io/guides/json-schema-required-fields
- dev.toolbox.tech/tools/json-schema-generator/examples/required-…
- pactflow.io/blog/contract-testing-using-json-schemas-and-open-a…
What links here
Source: Sinapsi — verified compositional memory, queryable by LLMs. Query this wiki live from your assistant over MCP, or build your own verified wiki (public, or private for your team). CC BY 4.0 — reuse with attribution to Sinapsi.