> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# x402 稳定币收单

> 通过 x402 协议接收 AI Agent 的 USDC 稳定币付款：商户自持 402 与 Waffo 托管两种集成模式的完整接入指南。

x402 是基于 HTTP 402 状态码的开放支付协议：服务端对未付费的请求返回 402 challenge，付款方（通常是 AI Agent）用链上稳定币授权签名重试请求，完成支付后获得资源。Waffo 把 x402 封装为标准收单能力——订单、Webhook、对账与你现有的 Waffo 集成完全一致，链上校验与结算由 Waffo 完成。

本页面向两类读者：**商户开发者**（选择集成模式、调用 Waffo API、判定资源放行）为主；**AI Agent 开发者**可重点阅读 402 challenge 结构与 `PAYMENT-SIGNATURE` 提交方式，Agent 侧交互不需要商户 API Key。

## 两种集成模式

<CardGroup cols={2}>
  <Card title="模式一：商户自持 402" icon="server">
    你的服务端自己充当 x402 server：向 Agent 返回 402 challenge、接收签名，再通过 `order/create` 把签名转交 Waffo 结算。适合希望 Agent 全程停留在自己 API 上、愿意实现 x402 协议细节的商户。
  </Card>

  <Card title="模式二：Waffo 托管 402" icon="cloud">
    你只创建订单，把 Waffo 返回的托管地址交给 Agent；402 challenge、签名接收与结算全部由 Waffo 收银台完成。适合不想实现 x402 协议细节、快速上线的商户。
  </Card>
</CardGroup>

两种模式共用同一个 [`order/create`](/docs/api-reference/order-create/create-new-order) 接口，区分方式只有一个：请求的 `x402Info` 里**带不带 `paymentSignatureHeader`**——带签名走模式一，不带走模式二。

## 前提条件

<Note>
  x402 收单需要先通过 Waffo 对接团队完成两项开通：

  1. 商户合同开通 **CRYPTO / USDC 支付产品**
  2. Waffo 侧配置你的**链上收款参数**

  未完成配置时，`wallet/inquiry` 与 `order/create` 返回错误码 `A0010`（商户合同不允许此操作）。
</Note>

## 当前支持范围

<Warning>
  以下是当前版本的硬性边界，请按此开发，不要预设其他能力：

  * **币种**：仅 `USDC`；`orderCurrency` 必须为 `USDC`（同币种收付，不涉及换汇）
  * **网络**：仅 Base（生产为 `eip155:8453`；沙箱为 Base Sepolia `eip155:84532`）
  * **scheme**：仅 `exact`（按 challenge 中的金额精确结算）
  * **授权次数**：EIP-3009 授权在链上单次消费——一个签名只能结算一次，不支持「一次授权、多次扣款」
  * **幂等**：`paymentRequestId` 必填；同一单重复 `order/create` 会返回已有订单的真实状态，不会重复结算（参见[幂等机制](/docs/zh/developer-docs/core-concepts/idempotency)）
</Warning>

## 获取链上收款参数

模式一构造 402 challenge 前，先调用 [`POST /api/v1/wallet/inquiry`](/docs/api-reference/wallet-inquiry/wallet-inquiry) 获取收款参数。该接口只做查询：不创建订单、不校验金额。

<CodeGroup>
  ```bash 请求 theme={null}
  curl -X POST https://api-sandbox.waffo.com/api/v1/wallet/inquiry \
    -H "Content-Type: application/json" \
    -H "X-API-KEY: YOUR_API_KEY" \
    -H "X-SIGNATURE: YOUR_RSA_SIGNATURE" \
    -d '{
      "paymentRequestId": "x402-order-10001",
      "merchantInfo": { "merchantId": "M000001" },
      "orderCurrency": "USDC"
    }'
  ```

  ```json 响应 theme={null}
  {
    "code": "0",
    "msg": "Success",
    "data": {
      "network": "eip155:84532",
      "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "payTo": "0xc15Ea3D0b7A29c41F8b26aD5c30F49E20e510e71"
    }
  }
  ```
</CodeGroup>

| 字段        | 说明                                                                             |
| --------- | ------------------------------------------------------------------------------ |
| `network` | CAIP-2 网络标识。沙箱返回 Base Sepolia `eip155:84532`，生产返回 Base 主网 `eip155:8453`        |
| `asset`   | USDC 代币合约地址（随环境与网络变化，生产 Base 主网为 `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`） |
| `payTo`   | Waffo 平台收款地址。Waffo 链上收款后按合同结算给你                                                |

<Note>
  三个字段都来自 Waffo 配置，请原样用于构造 challenge：`payTo` 不能替换为你自己的钱包地址，Agent 签名中的收款地址与金额会在结算前被链上校验。
</Note>

## 模式一：商户自持 402

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant A as AI Agent
    participant M as 商户服务端
    participant W as Waffo
    participant B as Base 链

    A->>M: 请求付费资源
    M->>W: POST /api/v1/wallet/inquiry
    W-->>M: network / asset / payTo
    M-->>A: HTTP 402（challenge 在 JSON body）
    A->>A: 生成 EIP-3009 授权签名
    A->>M: 原请求重试，携带 PAYMENT-SIGNATURE
    M->>W: POST /api/v1/order/create（x402Info.paymentSignatureHeader）
    W->>B: verify + settle（链上转账）
    B-->>W: 交易结果（txHash）
    W-->>M: orderStatus（PAY_SUCCESS 时带 x402Response）
    alt orderStatus = PAY_SUCCESS
        M-->>A: 200 + 资源 + PAYMENT-RESPONSE
    else orderStatus = PAY_IN_PROGRESS
        M-->>A: 202 处理中，经 Webhook / inquiry 收敛后放行
    else orderStatus = ORDER_CLOSE
        M-->>A: 支付失败，不放行资源
    end
```

你需要做四件事：

1. 调 `wallet/inquiry` 取 `network` / `asset` / `payTo`，按定价构造 402 challenge（金额用原子单位，`scheme` 固定 `exact`）返回给 Agent
2. 从 Agent 的重试请求头 `PAYMENT-SIGNATURE` 中取出签名，**原样**放入 `order/create` 的 `x402Info.paymentSignatureHeader`（不要解码后重新组装）
3. 按同步响应的 `orderStatus` 决定放行：`PAY_SUCCESS` 放行，`PAY_IN_PROGRESS` 等 [Webhook](/docs/zh/developer-docs/webhook/overview) 或 [`order/inquiry`](/docs/api-reference/order-inquiry/order-inquiry) 终态，`ORDER_CLOSE` 拒绝
4. 放行时把响应中的 `x402Info.x402Response` 作为 `PAYMENT-RESPONSE` 头返回给 Agent，作为符合 x402 协议的结算回执

<CodeGroup>
  ```bash 请求 theme={null}
  curl -X POST https://api-sandbox.waffo.com/api/v1/order/create \
    -H "Content-Type: application/json" \
    -H "X-API-KEY: YOUR_API_KEY" \
    -H "X-SIGNATURE: YOUR_RSA_SIGNATURE" \
    -d '{
      "paymentRequestId": "x402-order-10001",
      "merchantOrderId": "x402-order-10001",
      "orderCurrency": "USDC",
      "orderAmount": "9.99",
      "orderDescription": "API usage credits",
      "notifyUrl": "https://merchant.example.com/webhook/waffo",
      "merchantInfo": { "merchantId": "M000001" },
      "userInfo": { "userId": "agent_7f3e", "userTerminal": "WEB" },
      "paymentInfo": { "productName": "ONE_TIME_PAYMENT", "payMethodName": "USDC" },
      "x402Info": {
        "x402Request": true,
        "paymentSignatureHeader": "eyJ4NDAyVmVyc2lvbiI6Miwic2NoZW1lIjoiZXhhY3QiLC4uLn0="
      }
    }'
  ```

  ```json 响应（结算成功） theme={null}
  {
    "code": "0",
    "msg": "Success",
    "data": {
      "paymentRequestId": "x402-order-10001",
      "merchantOrderId": "x402-order-10001",
      "acquiringOrderId": "A202607060001",
      "orderStatus": "PAY_SUCCESS",
      "x402Info": {
        "x402Request": true,
        "paymentSignatureHeader": "eyJ4NDAyVmVyc2lvbiI6Miwic2NoZW1lIjoiZXhhY3QiLC4uLn0=",
        "x402Response": "eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IjB4Li4uIn0="
      }
    }
  }
  ```
</CodeGroup>

其余必填字段（`goodsInfo`、`orderRequestedAt` 等）与普通一次性支付建单一致，以 [API Reference](/docs/api-reference/zh/introduction) 为准。

`paymentSignatureHeader` 是 base64 编码的 x402 PaymentPayload，解码后结构如下（由 Agent 侧 x402 SDK 生成，商户无需构造）：

```json theme={null}
{
  "x402Version": 2,
  "scheme": "exact",
  "network": "eip155:84532",
  "payload": {
    "signature": "0x<65 字节 EIP-712 签名>",
    "authorization": {
      "from": "0x<Agent 钱包地址>",
      "to": "0xc15Ea3D0b7A29c41F8b26aD5c30F49E20e510e71",
      "value": "9990000",
      "validAfter": "0",
      "validBefore": "1783340000",
      "nonce": "0x<32 字节随机数（防重放，非递增）>"
    }
  }
}
```

<Warning>
  签名中 `authorization.to` 必须等于 `wallet/inquiry` 返回的 `payTo`，`authorization.value` 必须等于 `orderAmount` 的原子单位表示（换算规则见下文「金额与小数位」）。任一不一致都会在结算前校验失败，订单进入 `ORDER_CLOSE`。因此你在 402 challenge 中给 Agent 的定价必须与 `order/create` 的 `orderAmount` 一致。
</Warning>

`x402Response` 是 base64 编码的结算回执（x402 SettlementResponse），仅在 `orderStatus = PAY_SUCCESS` 时返回，解码后：

```json theme={null}
{
  "success": true,
  "transaction": "0x8f4e2b7c9d1a4f6e8b3c5d7a9e1f2b4c6d8e0a2c4e6f8a0b2c4d6e8f0a1b3c5d",
  "network": "eip155:84532",
  "payer": "0x51E2aF03D0A5c3C7dF83Db9F4b0a2E51D8c19aC3"
}
```

`transaction` 是链上交易 hash，可用于对账与链上核验；`payer` 是 Agent 的付款钱包地址。

## 模式二：Waffo 托管 402

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant A as AI Agent
    participant M as 商户服务端
    participant W as Waffo API
    participant C as Waffo 收银台

    A->>M: 请求付费资源
    M->>W: POST /api/v1/order/create（x402Request=true，无签名）
    W-->>M: AUTHORIZATION_REQUIRED + orderAction.webUrl
    M-->>A: HTTP 302 Location: webUrl
    A->>C: GET webUrl（x402 托管端点）
    C-->>A: HTTP 402（challenge 在 JSON body）
    A->>A: 生成 EIP-3009 授权签名
    A->>C: 同一 URL 重试，携带 PAYMENT-SIGNATURE
    C->>W: 提交签名，触发链上 verify + settle
    W-->>C: orderStatus
    C-->>A: HTTP 302（successRedirectUrl / failedRedirectUrl）
    W--)M: Webhook 通知终态（PAY_SUCCESS 时带 x402Response）
    M-->>A: 确认 PAY_SUCCESS 后放行资源
```

你需要做三件事：

1. `order/create` 传 `x402Info: { "x402Request": true }`（不带签名），并带上 `successRedirectUrl` / `failedRedirectUrl`
2. 解析响应中的 `orderAction`（JSON 字符串）取出 `webUrl`，将 Agent 302 重定向过去；之后的 402 challenge、签名接收、结算全部发生在 Waffo 收银台
3. 以 [Webhook](/docs/zh/developer-docs/webhook/overview) 或 `order/inquiry` 返回的 `orderStatus` 为准放行资源

<CodeGroup>
  ```bash 请求 theme={null}
  curl -X POST https://api-sandbox.waffo.com/api/v1/order/create \
    -H "Content-Type: application/json" \
    -H "X-API-KEY: YOUR_API_KEY" \
    -H "X-SIGNATURE: YOUR_RSA_SIGNATURE" \
    -d '{
      "paymentRequestId": "x402-order-10002",
      "merchantOrderId": "x402-order-10002",
      "orderCurrency": "USDC",
      "orderAmount": "9.99",
      "orderDescription": "API usage credits",
      "notifyUrl": "https://merchant.example.com/webhook/waffo",
      "successRedirectUrl": "https://merchant.example.com/x402/return",
      "failedRedirectUrl": "https://merchant.example.com/x402/failed",
      "merchantInfo": { "merchantId": "M000001" },
      "userInfo": { "userId": "agent_7f3e", "userTerminal": "WEB" },
      "paymentInfo": { "productName": "ONE_TIME_PAYMENT", "payMethodName": "USDC" },
      "x402Info": { "x402Request": true }
    }'
  ```

  ```json 响应 theme={null}
  {
    "code": "0",
    "msg": "Success",
    "data": {
      "paymentRequestId": "x402-order-10002",
      "merchantOrderId": "x402-order-10002",
      "acquiringOrderId": "A202607060002",
      "orderStatus": "AUTHORIZATION_REQUIRED",
      "orderAction": "{\"actionType\":\"WEB\",\"webUrl\":\"https://cashier.waffo.com/cashier/api/v1/x402/7sKq9WfR2mXt\"}"
    }
  }
  ```
</CodeGroup>

Agent 访问 `webUrl` 收到 HTTP 402，challenge 在**响应体**中（x402 协议规定 challenge 位于 body，没有专门的响应头）：

```json theme={null}
{
  "x402Version": 2,
  "error": "PAYMENT-SIGNATURE header is required",
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:84532",
      "maxAmountRequired": "9990000",
      "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "payTo": "0xc15Ea3D0b7A29c41F8b26aD5c30F49E20e510e71",
      "maxTimeoutSeconds": 600,
      "extra": { "name": "USDC", "version": "2" }
    }
  ]
}
```

Agent 签名后，用**与首次访问相同的 HTTP 方法**重试同一 URL，把签名放在 `PAYMENT-SIGNATURE` 请求头（对应 x402 规范中的 `X-PAYMENT`），无需任何商户凭证：

```bash theme={null}
curl "https://cashier.waffo.com/cashier/api/v1/x402/7sKq9WfR2mXt" \
  -H "PAYMENT-SIGNATURE: eyJ4NDAyVmVyc2lvbiI6Miwic2NoZW1lIjoiZXhhY3QiLC4uLn0="
```

结算完成后收银台以 302 将 Agent 带回你的 `successRedirectUrl` 或 `failedRedirectUrl`。该托管地址同时兼容浏览器访问（渲染收银台页面）与 x402 client 访问（返回协议响应）。

<Warning>
  302 回跳只用于流程衔接，**不是支付凭证**。判定「已支付」只能依据 Webhook 通知或 `order/inquiry` 查询到的 `orderStatus = PAY_SUCCESS`——回跳可能伪造、可能丢失，且回跳时结算可能尚未落定。
</Warning>

支付成功后，Webhook 通知与 `order/inquiry` 响应会附带 `x402Info.x402Response`（字段结构与模式一相同），其余通知结构与普通订单一致，参见 [Webhook 事件类型](/docs/zh/developer-docs/webhook/event-types)。

## 模式对比

| 维度                         | 模式一：商户自持 402                             | 模式二：Waffo 托管 402                  |
| -------------------------- | ---------------------------------------- | --------------------------------- |
| 谁充当 x402 server（发 402、收签名） | 商户服务端                                    | Waffo 收银台                         |
| 是否需要实现 x402 协议细节           | 是（构造 challenge、解析签名头）                    | 否                                 |
| `order/create` 是否带签名       | 带（`x402Info.paymentSignatureHeader`）     | 不带                                |
| 建单响应                       | 直接返回终态或 `PAY_IN_PROGRESS`                | `AUTHORIZATION_REQUIRED` + 托管地址   |
| 跳转                         | 无（Agent 全程请求商户 API）                      | 商户 302 → 收银台 302 回跳               |
| 资源放行依据                     | 同步响应 / Webhook / inquiry 的 `orderStatus` | Webhook / inquiry 的 `orderStatus` |
| 适合                         | 自建 x402 服务、深度定制的商户                       | 快速上线、不碰协议细节的商户                    |

订单状态语义（`PAY_IN_PROGRESS`、`AUTHORIZATION_REQUIRED` 等）与其他支付方式一致，参见[支付生命周期](/docs/zh/developer-docs/core-concepts/payment-lifecycle)。

## 金额与小数位（两层单位）

同一笔交易中的金额有两层表示，不要混用：

| 层             | 字段                          | 表示方式                         | 示例（9.99 USDC） |
| ------------- | --------------------------- | ---------------------------- | ------------- |
| Waffo API 层   | `orderAmount`               | String，最多 2 位小数              | `"9.99"`      |
| 链上 / x402 协议层 | `value`、`maxAmountRequired` | String，原子单位整数（USDC 链上精度 6 位） | `"9990000"`   |

换算规则：原子单位 = 金额 × 10<sup>6</sup>。[币种与金额](/docs/zh/developer-docs/core-concepts/currency)中 USDC 的 2 位小数指 Waffo API 层的 `orderAmount`；402 challenge 与 EIP-3009 签名中的金额始终是原子单位。模式一中两层金额必须对应同一数值，否则结算校验失败。

## 错误码

x402 复用 Waffo 既有对外错误码，`msg` 会说明具体原因：

| 错误码     | 含义         | x402 场景下的常见触发                                           |
| ------- | ---------- | ------------------------------------------------------- |
| `A0003` | 参数校验失败     | challenge / 签名的 scheme 不是 `exact`；缺少 `paymentRequestId` |
| `A0007` | 不支持的交易币种   | `orderCurrency` 不是 `USDC`，或商户没有可用的同币种 USDC 合同           |
| `A0010` | 商户合同不允许此操作 | 未开通 CRYPTO/USDC 支付产品，或链上收款参数未配置                         |

完整错误码列表见[错误码参考](/docs/zh/developer-docs/tools-and-references/developer-tools/error-codes)。

## 常见问题

<AccordionGroup>
  <Accordion title="沙箱环境用的是哪条链？">
    沙箱走 Base Sepolia 测试网（`eip155:84532`），USDC 合约地址为 `0x036CbD53842c5426634e7929541eC2318f3dCF7e`；生产走 Base 主网（`eip155:8453`），USDC 合约地址为 `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`。两个环境的 `network` / `asset` / `payTo` 都以 `wallet/inquiry` 实际返回为准。
  </Accordion>

  <Accordion title="支持其他币种或其他网络吗？">
    当前仅支持 USDC + Base 网络，`orderCurrency` 传其他币种会返回 `A0007`。
  </Accordion>

  <Accordion title="一次授权可以多次扣款吗？">
    不可以。x402 的 `exact` scheme 基于 EIP-3009 `transferWithAuthorization`，其 nonce 在 USDC 合约侧单次消费：签名一旦结算即作废，再次提交会在链上直接失败。订阅式、按量多次扣款不属于 x402 能力范围。
  </Accordion>

  <Accordion title="orderStatus 是 PAY_IN_PROGRESS，可以先放行资源吗？">
    不可以。`PAY_IN_PROGRESS` 只表示链上处理中，最终可能成功也可能失败。只有 `orderStatus = PAY_SUCCESS` 才能放行资源，终态通过 Webhook 或 `order/inquiry` 收敛。
  </Accordion>

  <Accordion title="402 challenge 在响应头还是响应体里？">
    在响应体（JSON body）里，没有携带 challenge 的响应头。x402 交互中唯一的协议请求头是 Agent 提交签名用的 `PAYMENT-SIGNATURE`（对应 x402 规范的 `X-PAYMENT`）；结算回执通过 `x402Info.x402Response` 字段返回，对应规范的 `X-PAYMENT-RESPONSE`。
  </Accordion>

  <Accordion title="这和「AI 集成工具（waffo-integrate）」是一回事吗？">
    不是。[AI 集成工具](/docs/zh/developer-docs/integration/ai-integration)是用 AI 编码工具帮你生成 Waffo SDK 集成代码；本页是 AI Agent 作为**付款方**用稳定币购买你的服务。两者可以同时使用，但解决的问题不同。
  </Accordion>
</AccordionGroup>

## 延伸阅读

* [支付生命周期](/docs/zh/developer-docs/core-concepts/payment-lifecycle)：订单状态机与终态收敛
* [币种与金额](/docs/zh/developer-docs/core-concepts/currency)：金额格式与小数位规则
* [幂等机制](/docs/zh/developer-docs/core-concepts/idempotency)：`paymentRequestId` 的幂等语义
* [Webhook 概览](/docs/zh/developer-docs/webhook/overview)：签名验证与重试策略
* [API Reference](/docs/api-reference/zh/introduction)：[`order/create`](/docs/api-reference/order-create/create-new-order)、[`order/inquiry`](/docs/api-reference/order-inquiry/order-inquiry)、[`wallet/inquiry`](/docs/api-reference/wallet-inquiry/wallet-inquiry) 的完整字段定义
