博客 • AI / Agent Payments
Agent Payments Protocol(AP2)是什么?2026 AI Agent 自动支付、JSON API 与智能交易完整解析
你在接 AI Agent 电商或自动采购时,文档里会同时冒出 A2A、MCP,以及一套叫 AP2 的支付协议。前两者管「怎么对话、怎么调工具」,AP2 管「凭什么替用户付钱」。
Agent Payments Protocol(AP2)是 Google 于 2025 年 9 月与 60 多家支付和科技公司一起发布的开放协议,用来给「Agent 替用户付钱」这件事补上可验证的授权、真实意图和事后追责。2026 年的实现稿(v0.2)把交易拆成两张可验证凭证:Checkout Mandate 和 Payment Mandate,载荷是 JSON,封装多用 SD-JWT。
本文将说明:
- AP2 解决的三个问题:授权、真实性、责任
- 五种角色谁验什么
- Checkout / Payment Mandate 的 JSON 长什么样
- 人在场支付和自主代付差在哪
- 怎么用 JSON Schema 校验,并在 JSONNote 里本地调试
先记住这一点:AP2 不是又一套结账 UI,也不是替代 Stripe 的支付网关。它是 Agent 支付的信任层:用密码学签名的 Mandate 证明「用户允许这笔交易」。下面按「为什么需要 → 角色 → Mandate JSON → 两种模式 → Schema 校验 → 和 A2A/MCP 怎么叠」拆开。
AP2 是什么
Google Cloud 公告把 AP2 定义成一套支付无关的开放协议:用户、商户、支付机构用同一种语言完成 Agent 发起的交易。它可以作为Agent2Agent (A2A)和Model Context Protocol (MCP)的支付扩展,不替代两者。
2026 年公开规范见AP2 Specification v0.2,参考实现在google-agentic-commerce/AP2。
核心对象不是「订单表单」,而是Mandate(授权书):一份防篡改、可验证的数字合同,证明用户给了 Agent 某次购买或某类约束下的购买权限。规范要求 Mandate 用SD-JWT这类可验证数字凭证封装,而不是裸 JSON POST。
发布时的产品叙事用过 Intent Mandate / Cart Mandate / Payment Mandate 三张凭证。当前 v0.2 实现稿收敛成两张,并区分开放(open)与封闭(closed):
| 概念 | v0.2 对应 | 证明什么 |
|---|---|---|
| Intent / 开放约束 | Open Checkout / Open Payment Mandate | 用户预先批准的预算、商户范围、有效期 |
| Cart / 封闭结账 | Closed Checkout Mandate | 这张购物车的商品、价格、商户签名 Checkout JWT |
| Payment | Closed Payment Mandate | 为这一笔 Checkout 付款的金额、收款方、支付工具 |
读老文章时不要被三套名词卡住:产品层讲「意图 → 购物车 → 付款」,实现层就是开放约束 + 封闭 Checkout/Payment。
为什么 Agent 支付需要新协议
传统电商默认「人在可信页面点购买」。Agent 一旦能自己下单,旧假设破了。AP2 要回答三件事:
- 授权(Authorization):用户是否明确允许 Agent 付这一笔,或在这组约束内付款。
- 真实性(Authenticity):商户怎么确认 Agent 提交的购物车就是用户同意的那一单,而不是模型幻觉出来的 SKU。
- 责任(Accountability):出错或欺诈时,用 Mandate 和 Receipt 拼出不可抵赖的证据链。
只靠 prompt「帮我买票」没有密码学边界。模型可能改数量、换商户、重复提交。AP2 把「用户签过的约束」和「Agent 组装的封闭订单」绑在一起,验证必须在确定性代码里做,不能再丢回 LLM 判断。
支付方式本身仍走卡组、银行或稳定币轨道。AP2 不管清算,只管「这笔 Agent 交易有没有被授权」。加密货币方向有 A2A x402 扩展,和 Coinbase、Ethereum Foundation、MetaMask 等一起做 Agent 加密支付。
五种角色:谁签、谁验、谁收款
规范定义五个角色。一个主体可以兼任,但验证规则按角色叠加:
| 角色 | 英文 | 做什么 | 是否允许 Agent 化 |
|---|---|---|---|
| 购物 Agent | Shopping Agent | 发现商品、组结账、发起购买 | 预期是 Agent |
| 凭证提供方 | Credential Provider | 核发支付凭证,确认 Agent 有权使用该凭证 | 可以是,也可以不是 |
| 商户 | Merchant | 提供并完成 Checkout,核库存与价格 | 可以是,也可以不是 |
| 商户收单方 | Merchant Payment Processor | 处理付款,确认凭证绑定了这一笔 Checkout | 可以是,也可以不是 |
| 可信界面 | Trusted Surface | 向用户展示意图并收集签名 | 必须不是 Agent |
关键约束:Trusted Surface 必须是非 Agent 的确定性界面。用户签名不能交给另一个 LLM 去「转述」。Shopping Agent 可以是非确定性的,所以它发出的内容默认不可信,必须靠 Mandate 的签名和哈希来钉死。
Mandate:Checkout 与 Payment
v0.2 只定义两类 Mandate。购物 Agent 组好任务后,通过可信界面拿到签名,再分别交给商户和支付链路。
Checkout Mandate
给商户看:Shopping Agent 被授权购买它组装的那一笔 Checkout。商户必须先给出自己签名的 Checkout JWT;封闭 Checkout Mandate 用该 JWT 的密码学哈希(checkout_hash)绑死,防止 Agent 改完价格再拿旧授权去结账。
商户接受或拒绝后,必须返回 Checkout Receipt。
Payment Mandate
给凭证提供方、卡组和收单方看:Shopping Agent 被授权为这一笔Checkout 付款。绑定方式是 Checkout JWT 的密码学哈希。规范要求 Checkout JWT 用 ECDSA 这类非确定性签名,不要用 Ed25519,以免彩虹表攻击。
收单方接受或拒绝后,必须返回签名的 Payment Receipt,回给 Agent、凭证提供方,必要时回给卡组。争议时把 Checkout / Payment 的 Mandate 和 Receipt 拼在一起,就是证据包。
两种模式:人在场 vs 自主代付
验证方最终都收到封闭的 Checkout 和 Payment Mandate。差别只在封闭凭证是谁签的、开放约束怎么核。
-
1
Human Present(直接 / 人在场)
用户在可信界面看到封闭购物车,亲自签名。验证方核的是用户凭证或 Agent Provider 信任列表上的用户签名。
-
2
Human Not Present(自主 / 人不在场)
用户先签开放 Mandate:金额区间、允许的商户、有效期,并带上 Agent 公钥(cnf 声明)。条件满足后,Agent 用自己的密钥签封闭单;验证方必须核对封闭单落在开放约束内。
自主模式还有两条硬规则:同一张开放 Mandate 在上一笔被拒绝之前,不能再拿去签另一笔封闭单;出示开放 Mandate 时只披露验证封闭单所需的字段,保护用户隐私。
典型场景:票开售瞬间代抢、缺货补货自动下单、旅行预算内同时订机票和酒店。这些都是「约束先签、成交后补封闭单」,不是给 Agent 一张无限额信用卡。
JSON API:字段、vct 与 Schema
开发者接触 AP2,日常就是 JSON。官方 SDK 把规范对象放在code/sdk/python/ap2/schemas/,并用 Pydantic 生成模型。你调试时先当普通 JSON 对象看,再谈 SD-JWT 封装。
每张 Mandate 用vct声明类型和版本,例如mandate.payment.1、mandate.checkout.open.1。实现必须精确匹配整串,包括数字后缀;不兼容的改版会换成.2。
下面是规范里封闭 Payment Mandate 的业务载荷形态(金额单位依实现,示例用最小货币单位):
{
"vct": "mandate.payment.1",
"transaction_id": "NivWhuqfzcvZNapvIEJ2-3tsdQLkiuIcye2g46WVgX8",
"payee": {
"id": "merchant_1",
"name": "Demo Merchant",
"website": "https://demo-merchant.example"
},
"payment_amount": {
"amount": 19900,
"currency": "USD"
},
"payment_instrument": {
"id": "stub",
"type": "card",
"description": "Card ••••4242"
}
}
开放 Payment Mandate 不写死某一笔,而是写约束:
{
"vct": "mandate.payment.open.1",
"cnf": {
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "QpSyxPQHy38xckypDr54gZ3T42zj9iLtV4koyb5U27c",
"y": "37HLd7JJinxjJIn8J7HijssoeclbfhdW-gUL7feI9lw"
}
},
"exp": 1781203600,
"constraints": [
{
"type": "mandate.payment.allowed_payees",
"allowed": [{ "id": "merchant_1" }]
},
{
"type": "mandate.payment.amount_range",
"currency": "USD",
"min": 10000,
"max": 40000
}
]
}
传输时它们不是裸 JSON,而是 SD-JWT:可选择披露 + 密钥绑定。业务层调试时,你仍然先把披露还原成上面这种 JSON,再校验字段和约束。
对应的 JSON Schema 应至少锁住vct、transaction_id、payee、payment_amount和支付工具类型,避免模型漏字段或把金额写成字符串:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://jsonnote.com/schemas/ap2-payment-mandate-debug.json",
"title": "AP2 Closed Payment Mandate (debug)",
"type": "object",
"additionalProperties": false,
"required": ["vct", "transaction_id", "payee", "payment_amount", "payment_instrument"],
"properties": {
"vct": {
"type": "string",
"const": "mandate.payment.1"
},
"transaction_id": {
"type": "string",
"minLength": 16
},
"payee": {
"type": "object",
"required": ["id", "name"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"name": { "type": "string", "minLength": 1 },
"website": { "type": "string", "format": "uri" }
}
},
"payment_amount": {
"type": "object",
"required": ["amount", "currency"],
"properties": {
"amount": { "type": "integer", "minimum": 1 },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" }
}
},
"payment_instrument": {
"type": "object",
"required": ["id", "type"],
"properties": {
"id": { "type": "string" },
"type": {
"type": "string",
"enum": ["card", "bank_transfer", "stablecoin"]
},
"description": { "type": "string" }
}
}
}
}
生产环境请以官方仓库里的 canonical schema 为准。上面这份是调试精简版,方便贴进 JSONNote 做本地校验,不能替代规范里的完整字段和选择性披露标注。
实际示例:校验 Payment Mandate
Agent 侧常见失败不是验签失败,而是 JSON 先坏了:
- 模型把
vct写成mandate.payment,漏了版本后缀.1 - 金额写成
"19.90"字符串,而 schema 要求整数最小货币单位 transaction_id和 Checkout JWT 的哈希对不上,绑定断裂
业务层先 parse,再按 schema validate,最后才做 SD-JWT 验签和约束求值:
import json
from jsonschema import validate, ValidationError
PAYMENT_MANDATE_SCHEMA = {
"type": "object",
"required": ["vct", "transaction_id", "payee", "payment_amount"],
"properties": {
"vct": {"type": "string", "const": "mandate.payment.1"},
"transaction_id": {"type": "string", "minLength": 16},
"payee": {
"type": "object",
"required": ["id", "name"],
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
},
},
"payment_amount": {
"type": "object",
"required": ["amount", "currency"],
"properties": {
"amount": {"type": "integer", "minimum": 1},
"currency": {"type": "string", "pattern": "^[A-Z]{3}$"},
},
},
},
"additionalProperties": True,
}
def parse_payment_mandate(raw: str) -> dict:
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
raise ValueError(f"invalid mandate JSON: {e}") from e
try:
validate(instance=data, schema=PAYMENT_MANDATE_SCHEMA)
except ValidationError as e:
raise ValueError(f"mandate schema failed: {e.message}") from e
return data
# 用法:先过结构,再拿 transaction_id 去对 Checkout JWT 的哈希
mandate = parse_payment_mandate(disclosed_payload)
assert mandate["transaction_id"] == checkout_hash
这和 Agent 里校验tool_calls[].function.arguments是同一套纪律:先保证是合法 JSON,再保证符合契约,最后才执行副作用。见AI Agent 与 JSON Schema。
智能交易的完整链路可以看成:
-
1
用户签约束或当场签封闭单
可信界面出 Mandate,Agent 不得自己「补签」用户意图。
-
2
商户签发 Checkout JWT
价格、库存、优惠以商户签名为准,Agent 不能改完再假装同一笔。
-
3
封闭 Mandate 绑定 checkout_hash
Payment Mandate 的 transaction_id 必须等于该哈希。
-
4
各方验签并回 Receipt
失败返回带错误的 Receipt JWT,成功才进入真正的收单或推送资金。
AP2 vs 传统支付 / A2A / MCP
| 层 | 解决什么 | 典型对象 | 和 AP2 的关系 |
|---|---|---|---|
| 传统支付 API | 扣款、退款、令牌化卡号 | PaymentIntent、capture | AP2 不替代清算;Payment Mandate 证明「可以去调这些 API」 |
| A2A | Agent 与 Agent 互操作 | 任务、消息、能力发现 | AP2 可作为 A2A 的支付扩展;另有 x402 走加密货币 |
| MCP | Agent 调外部工具 | inputSchema / outputSchema | 工具契约描述参数;付钱仍要 AP2 Mandate |
| UCP 等商务协议 | 目录、改价、结账会话 | Checkout 对象 | AP2 明确兼容,自身不管商品浏览 |
| JSON Schema | 结构契约 | type / required / enum | Mandate 和工具参数都靠它;验签之前先过结构 |
一句话:MCP 让 Agent 会用工具,A2A 让 Agent 会协作,AP2 让 Agent 在被允许的范围内会付钱。三者叠在一起才是 2026 年的智能交易栈。MCP 工具契约怎么写,见AI Agent 与 JSON Schema;模型怎么稳定吐 JSON,见2026 Structured Output。
用 JSONNote 调试 AP2 JSON
接 AP2 时最慢的往往不是密码学,而是对 payload。Mandate、Checkout JWT 声明、Receipt、约束数组都是 JSON。JSONNote 在浏览器本地跑,原始交易数据不上传:
-
1
先看结构对不对
把披露还原后的 Mandate 贴进JSON 格式化,先排除缺逗号、尾逗号、半截 JWT。
-
2
用 Schema 卡住字段
把上面的调试 Schema 和实例一起放进JSON Schema,立刻看到缺字段、类型错、enum 越界。
-
3
对比两笔交易
开放约束 vs 封闭单、或两次 Agent 组装结果,用JSON Diff看哪些字段被改过。
-
4
本地分享调试样本
不要把真实卡号或私钥放进链接。用Hash 分享只传脱敏后的样例 JSON,数据留在 URL fragment,不上传服务器。
常见问题
AP2 和 A2A、MCP 是什么关系?
A2A 负责 Agent 之间怎么对话,MCP 负责 Agent 怎么调外部工具。AP2 只解决「谁授权这笔钱、凭什么付、事后怎么举证」。它可以作为 A2A / MCP 的支付扩展,不替代两者。
AP2 只支持信用卡吗?
不是。AP2 对支付工具不可知:卡、银行转账、稳定币都可以,用 Payment Instrument 的 type 区分。加密货币场景还有 A2A x402 扩展。
自主代付是不是 Agent 可以随便花钱?
不是。自主模式先由用户在可信界面签署开放 Mandate,写明金额上限、商户范围、有效期和 Agent 公钥。Agent 只能签符合这些约束的封闭 Mandate,验证方必须核对约束。
开发 AP2 为什么还要校验 JSON Schema?
Mandate 在传输层是 SD-JWT,业务层看到的仍是 JSON 对象。字段名、金额单位、vct 版本写错,验签还没开始就会失败。先用 JSON Schema 拦住结构错误,再做密码学验证。
公告里的 Intent / Cart Mandate 还算数吗?
产品叙事仍是「意图 → 购物车 → 付款」。实现时请以当前规范的 Checkout / Payment Mandate(含 open / closed)和官方 schema 为准,不要自己发明第三套字段名。
总结
2026 年 Agent 要自动支付,缺的不是又一个 checkout 按钮,而是可验证的授权。
AP2 用签名 Mandate 把用户意图钉在 JSON 契约上;Checkout 钉住买什么,Payment 钉住付多少、付给谁。
人在场就签封闭单,人不在场就先签约束再让 Agent 补封闭单。结构先用 JSON Schema 校验,再验 SD-JWT。调试 payload 时用 JSONNote 本地格式化、校验和 Diff——密钥和真实支付凭证不要离开你的机器。