Agent 端 API - 单次支付#
Buyer 钱包通过 transferWithAuthorization(EIP-3009)直接转账给 Seller 钱包,单笔即时上链。
- Base URL:
https://web3.okx.com - 路径前缀:
/api/v6/pay/a2a - Intent:
charge - Method:
evm - Network:X Layer(
chainId: 196)
鉴权#
Agent 服务的鉴权按接口区分:
| 接口 | 鉴权方式 |
|---|---|
POST /api/v6/pay/a2a/payment/create | 必须:API Key 鉴权(OK-ACCESS-* Header)或 OnchainOS 内部调用 |
GET /api/v6/pay/a2a/p/{paymentId} | 无需鉴权(公开接口) |
POST /api/v6/pay/a2a/p/{paymentId}/credential | 无需鉴权 |
GET /api/v6/pay/a2a/p/{paymentId}/status | 无需鉴权 |
Buyer 一侧(拉取详情、提交凭证、查询状态)不持有 Seller 的 API Key,因此对应接口公开访问;Smart-Account 内部依靠
paymentId 与 challenge 校验请求合法性。API Key 鉴权使用以下请求头:
| Header | 必传 | 描述 |
|---|---|---|
OK-ACCESS-KEY | 是 | API Key |
OK-ACCESS-SIGN | 是 | 请求签名 |
OK-ACCESS-PASSPHRASE | 是 | API 密码短语 |
OK-ACCESS-TIMESTAMP | 是 | ISO 8601 时间戳 |
Content-Type | 是 | POST 请求需设为 application/json |
所有响应统一使用业务包络:
json
{
"code": "0",
"msg": "success",
"data": { /* 业务字段 */ }
}
业务错误时 code 为非 "0",data 为 null,错误码集中见文末 错误码 章节。
1. /api/v6/pay/a2a/payment/create#
POST
/api/v6/pay/a2a/payment/create
由 Seller Agent 调用,生成 Charge 付款请求并取回付款分发物。
请求参数#
| 参数 | 类型 | 必传 | 描述 |
|---|---|---|---|
type | String | 是 | 固定 "charge" |
amount | String | 是 | 金额(面值十进制字符串,如 "0.1") |
symbol | String | 是 | 代币 symbol,如 "USD₮0" / "USDC" / "USDG" |
recipient | String | 是 | Seller 收款钱包地址 |
description | String | 否 | 付款描述 |
externalId | String | 否 | Seller 业务侧 ID,用于幂等 |
expiresIn | Integer | 否 | 付款有效期(秒),默认 1800 |
realm | String | 否 | 业务域,默认取 Seller 注册时绑定的 realm |
deliveries | Object | 否 | 分发物开关 |
deliveries.includeUrl | Boolean | 否 | 默认 true,生成付款 URL。一期仅支持 URL 分发 |
创建请求使用
symbol + 十进制 amount;服务端在响应中将其转换为标准 MPP challenge(含原子单位 amount 和合约地址 currency),供 Buyer 签名。一期 deliveries 仅支持 URL 类型,二维码 / 卡片等其他形式的分发暂不支持。请求示例#
bash
curl --location --request POST 'https://web3.okx.com/api/v6/pay/a2a/payment/create' \
--header 'Content-Type: application/json' \
--header 'OK-ACCESS-KEY: 37c541a1-****-****-****-10fe7a038418' \
--header 'OK-ACCESS-SIGN: leaV********3uw=' \
--header 'OK-ACCESS-PASSPHRASE: 1****6' \
--header 'OK-ACCESS-TIMESTAMP: 2023-10-18T12:21:41.274Z' \
--data '{
"type": "charge",
"amount": "0.1",
"symbol": "USD₮0",
"recipient": "0xSellerWalletAddress",
"description": "Task #5678 direct payment",
"externalId": "task-5678",
"expiresIn": 1800,
"realm": "provider.example.com",
"deliveries": {
"includeUrl": true
}
}'
响应参数#
| 参数 | 类型 | 描述 |
|---|---|---|
paymentId | String | 付款 ID,格式 a2a_<base58(uuidv7)> |
status | String | 初始固定 "pending" |
createdAt | String | 创建时间,RFC 3339 |
expiresAt | String | 过期时间,RFC 3339 |
challenge | Object | MPP challenge 结构,详见 Challenge |
deliveries | Array<Delivery> | 分发物列表,详见 Delivery |
响应示例#
json
{
"code": "0",
"msg": "success",
"data": {
"paymentId": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"status": "pending",
"createdAt": "2026-04-21T10:00:00Z",
"expiresAt": "2026-04-21T10:30:00Z",
"challenge": {
"type": "payment-challenge",
"data": {
"id": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"realm": "provider.example.com",
"method": "evm",
"intent": "charge",
"request": {
"amount": "100000",
"currency": "0x779ded0c9e1022225f8e0630b35a9b54be713736",
"recipient": "0xSellerWalletAddress",
"description": "Task #5678 direct payment",
"externalId": "task-5678",
"methodDetails": {
"chainId": 196,
"authorizationType": "eip-3009"
}
},
"expires": "2026-04-21T10:30:00Z"
}
},
"deliveries": [
{ "type": "url", "value": "https://pay.okx.com/p/a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB", "description": "通用付款链接" }
]
}
}
2. /api/v6/pay/a2a/p/{paymentId}#
GET
/api/v6/pay/a2a/p/{paymentId}
Buyer Agent 根据 paymentId 拉取完整 challenge。同一 URL 在浏览器中访问时返回 HTML 付款页;带 A2A Pay UA 或 Accept: application/json 时返回此 JSON。
请求参数#
| 参数 | 位置 | 类型 | 必传 | 描述 |
|---|---|---|---|---|
paymentId | path | String | 是 | 付款 ID |
响应参数#
| 参数 | 类型 | 描述 |
|---|---|---|
paymentId | String | 付款 ID |
status | String | 当前状态(详见 状态字典) |
createdAt | String | 创建时间 |
expiresAt | String | 过期时间 |
challenge | Object | MPP challenge 结构(同 create 接口) |
响应示例#
json
{
"code": "0",
"msg": "success",
"data": {
"paymentId": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"status": "pending",
"createdAt": "2026-04-21T10:00:00Z",
"expiresAt": "2026-04-21T10:30:00Z",
"challenge": { "type": "payment-challenge", "data": { "...同 create 响应..." } }
}
}
3. /api/v6/pay/a2a/p/{paymentId}/credential#
POST
/api/v6/pay/a2a/p/{paymentId}/credential
Buyer Agent 完成 EIP-3009 签名后提交凭证。Smart-Account 验签通过后代发链上交易。
请求体只包含
payload,不再回传 challenge——服务端按 paymentId 查询自己存储的 challenge 与传入的 payload.authorization 校验一致性。请求参数#
| 参数 | 位置 | 类型 | 必传 | 描述 |
|---|---|---|---|---|
paymentId | path | String | 是 | 付款 ID |
payload | body | Object | 是 | 签名数据 |
payload.type | body | String | 是 | 固定 "transaction" |
payload.signature | body | String | 是 | EIP-712 签名(65 字节,0x 前缀) |
payload.authorization | body | Object | 是 | EIP-3009 授权参数,详见 Authorization |
请求示例#
bash
curl --location --request POST 'https://web3.okx.com/api/v6/pay/a2a/p/a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB/credential' \
--header 'Content-Type: application/json' \
--data '{
"payload": {
"type": "transaction",
"signature": "0xabcdef...01",
"authorization": {
"type": "eip-3009",
"from": "0xBuyerWalletAddress",
"to": "0xSellerWalletAddress",
"value": "100000",
"validAfter": "0",
"validBefore": "1714521600",
"nonce": "0xf374661b1c7d5e7a8b3e2f1a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c"
}
}
}'
响应参数#
| 参数 | 类型 | 描述 |
|---|---|---|
paymentId | String | 付款 ID |
status | String | 通过校验后变为 "settling" |
acceptedAt | String | 凭证被接收的时间 |
trackingUrl | String | 状态追踪页 URL |
响应示例#
json
{
"code": "0",
"msg": "success",
"data": {
"paymentId": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"status": "settling",
"acceptedAt": "2026-04-21T10:05:00Z",
"trackingUrl": "https://pay.okx.com/status/a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB"
}
}
4. /api/v6/pay/a2a/p/{paymentId}/status#
GET
/api/v6/pay/a2a/p/{paymentId}/status
查询支付状态。Buyer 提交 credential 后,Seller / Buyer 通过此接口轮询结算结果。
请求参数#
| 参数 | 位置 | 类型 | 必传 | 描述 |
|---|---|---|---|---|
paymentId | path | String | 是 | 付款 ID |
响应参数#
| 参数 | 类型 | 描述 |
|---|---|---|
paymentId | String | 付款 ID |
status | String | 当前状态(详见 状态字典) |
executed | Object | 仅当 status = completed 时返回 |
executed.txHash | String | 链上交易哈希 |
executed.blockNumber | Integer | 区块高度 |
executed.blockTimestamp | String | 区块时间,RFC 3339 |
fee | Object | 平台费(如有) |
fee.amount | String | 平台费金额(原子单位) |
fee.bps | Integer | 费率 basis points(1 bps = 0.01%) |
failure | Object | 仅当 status = failed 时返回 |
failure.reason | String | 机器可读失败原因 |
failure.message | String | 人类可读失败说明 |
响应示例 — 已结算#
json
{
"code": "0",
"msg": "success",
"data": {
"paymentId": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"status": "completed",
"executed": {
"txHash": "0xabc...123",
"blockNumber": 12345678,
"blockTimestamp": "2026-04-21T10:05:15Z"
},
"fee": { "amount": "300", "bps": 30 }
}
}
响应示例 — 处理中#
json
{
"code": "0",
"msg": "success",
"data": {
"paymentId": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"status": "settling"
}
}
响应示例 — 失败#
json
{
"code": "0",
"msg": "success",
"data": {
"paymentId": "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB",
"status": "failed",
"failure": {
"reason": "transaction_reverted",
"message": "EIP-3009 transferWithAuthorization reverted on chain"
}
}
}
公共数据结构#
Challenge#
| 参数 | 类型 | 必传 | 描述 |
|---|---|---|---|
type | String | 是 | 固定 "payment-challenge" |
data | Object | 是 | 业务字段 |
data.id | String | 是 | 等于 paymentId |
data.realm | String | 是 | 业务域 |
data.method | String | 是 | 固定 "evm" |
data.intent | String | 是 | 固定 "charge" |
data.request | Object | 是 | 付款请求字段 |
data.request.amount | String | 是 | 金额(原子单位字符串) |
data.request.currency | String | 是 | ERC-20 合约地址 |
data.request.recipient | String | 是 | Seller 收款钱包地址 |
data.request.description | String | 否 | 付款描述 |
data.request.externalId | String | 否 | Seller 业务 ID |
data.request.methodDetails.chainId | Integer | 是 | EVM chainId(X Layer 为 196) |
data.request.methodDetails.authorizationType | String | 是 | Charge 固定 "eip-3009" |
data.expires | String | 是 | challenge 短期过期时间,RFC 3339 |
Authorization#
| 参数 | 类型 | 必传 | 描述 |
|---|---|---|---|
type | String | 是 | 固定 "eip-3009" |
from | String | 是 | Buyer 钱包地址(付款方身份由此字段经 ECDSA 恢复确定) |
to | String | 是 | 收款方钱包地址 |
value | String | 是 | 金额(原子单位) |
validAfter | String | 是 | 生效时间戳(Unix 秒) |
validBefore | String | 是 | 过期时间戳(Unix 秒) |
nonce | String | 是 | 32 字节随机 nonce(0x 前缀 hex) |
额外约束:payload.authorization.to 必须与 challenge 中的 request.recipient 完全一致;payload.authorization.value 必须等于 request.amount。否则签名校验失败。
Delivery#
| 参数 | 类型 | 必传 | 描述 |
|---|---|---|---|
type | String | 是 | 一期固定 "url" |
value | String | 是 | 付款链接,格式 https://pay.okx.com/p/{paymentId} |
description | String | 否 | 说明 |
状态字典#
| 状态 | 说明 |
|---|---|
pending | 已生成,等待 Buyer 提交 credential |
settling | 凭证已收,Smart-Account 正在代发链上交易 |
completed | 链上已确认,资金已到账 |
failed | 验签失败 / 链上 revert / 模拟失败 |
expired | 已过期 |
Payment ID 格式#
paymentId = "a2a_" + base58(uuidv7)
示例 = "a2a_01HZX8Q9RK3JWYV7M2N5T8P4AB"错误码#
错误响应统一使用包络 {"code": "<code>", "msg": "<message>", "data": null}。
1. 认证错误(HTTP 401,仅 payment/create)#
| 错误码 | 描述 |
|---|---|
| 50103 | 请求头 OK-ACCESS-KEY 不能为空 |
| 50104 | 请求头 OK-ACCESS-PASSPHRASE 不能为空 |
| 50105 | 请求头 OK-ACCESS-PASSPHRASE 错误 |
| 50106 | 请求头 OK-ACCESS-SIGN 不能为空 |
| 50107 | 请求头 OK-ACCESS-TIMESTAMP 不能为空 |
| 50111 | 无效的 OK-ACCESS-KEY |
| 50112 | 无效的 OK-ACCESS-TIMESTAMP |
| 50113 | 无效的签名 |
2. 请求错误#
| 错误码 | HTTP 状态 | 描述 |
|---|---|---|
| 50011 | 429 | 用户请求频率过快,超过该接口允许的限额 |
| 50014 | 400 | 必填参数 {param} 不能为空 |
3. 通用业务错误#
| 错误码 | HTTP 状态 | 描述 |
|---|---|---|
| 50026 | 500 | 系统错误,请稍后重试 |
| 81001 | 200 | {param} 参数错误 |
| 81004 | 200 | 不支持的链 |
| 80007 | 200 | 风险地址 |
4. MPP 业务错误#
| 错误码 | 错误标识 | 描述 |
|---|---|---|
| 70000 | invalid_params | 参数校验失败 |
| 70001 | unsupported_chain | 不支持的链 / chainId |
| 70002 | payer_blocked | 付款方地址被风控拦截 |
| 70003 | invalid_credential | credential 与服务端存储不一致 / 校验失败 |
| 70004 | invalid_signature | EIP-712 / EIP-3009 签名无效 |