---
title: "x402 支付 2026 v2 實作與結算驗證"
locale: zh-hant
category: tutorial
category_name: "教學課程"
translation_status: reviewed
license: cc_by
author: "injoys"
source_url: https://injoys.com/en/articles/x402-payments-2026-v2-base-usdc-settlement-guide
published_at: 2026-10-28T19:20:55+09:00
---

# x402 支付 2026 v2 實作與結算驗證

> 透過 x402 v2 為 API 加入小額支付的 Node.js 實作教學。在 Base Sepolia 上選擇支付條件、簽署並重新發送請求，以及驗證結算，接著檢查重送與切換至主網的條件。

## Key Points

- 準備收款地址與測試用支付錢包，並安裝官方 x402 SDK。
- 串接適用於 Base Sepolia 的支付中介軟體，並確認未支付請求的 402 回應。
- 僅選擇符合客戶端允許的鏈、代幣、金額與收款人的條件，並進行簽署。
- 使用結算回應中的交易雜湊查詢 USDC Transfer 事件。
- 測試失敗時的阻擋機制與重複請求復原後，再檢視主網設定。

x402 付款透過在 API 的 402 回應中包含付款條件來實作。請準備 Node.js 和測試錢包。先在 Base Sepolia 驗證 v2 簽章與結算。請設定為結算成功後才傳送付費回應。

金額與鏈資訊以來源連結中的 x402、Base、Circle 官方文件為準。

## 實作準備與安裝

請準備可修改 API 的開發環境及測試錢包。範例以 Node.js 22 和 x402 SDK 2.28.0 為基礎。安裝結構遵循[官方賣方指南](https://docs.x402.org/getting-started/quickstart-for-sellers)。

1. 準備接收付款的 EVM 錢包地址。
2. 另外準備付款用的測試錢包。
3. 在付款錢包中取得 Base Sepolia 測試 USDC。
4. 使用下列指令建立實作專案。
5. 將後續的 TypeScript 檔案儲存在同一個資料夾中。

```bash
mkdir x402-demo
cd x402-demo
npm init -y
npm pkg set type=module
npm install --save-exact express@5.3.0 viem@2.57.12 @x402/core@2.28.0 @x402/express@2.28.0 @x402/evm@2.28.0 @x402/fetch@2.28.0
npm install --save-dev --save-exact typescript tsx @types/node @types/express
```

收款伺服器不需要收款錢包的私鑰。請設定為僅由用戶端程序讀取付款私鑰。錢包簽章方式以[官方買方指南](https://docs.x402.org/getting-started/quickstart-for-buyers)為準。

本範例的驗證範圍為型別檢查與模擬付款流程，並未完成實際測試網轉帳。請在下方執行步驟中自行確認鏈上結果。

## x402 v1 與 v2 比較

實作 v2 時，必須同時配合標頭和本文欄位。只更改標頭名稱，資料結構仍會不符。下表以[官方遷移指南](https://docs.x402.org/guides/migration-v1-to-v2)為準。

| 類別 | v1 | v2 |
|---|---|---|
| 協定版本 | `x402Version: 1` | `x402Version: 2` |
| 初始付款條件 | 402 回應的 JSON 本文 | `PAYMENT-REQUIRED` 回應標頭 |
| 已簽署的付款資料 | `X-PAYMENT` 請求標頭 | `PAYMENT-SIGNATURE` 請求標頭 |
| 結算結果 | `X-PAYMENT-RESPONSE` 回應標頭 | `PAYMENT-RESPONSE` 回應標頭 |
| Base 主網識別碼 | `base` | `eip155:8453` |
| Base Sepolia 識別碼 | `base-sepolia` | `eip155:84532` |
| 付款條件的金額欄位 | `maxAmountRequired` | `amount` |
| 資源描述 | 付款條件內的 `resource` 等 | 最上層的 `resource` 物件 |
| 付款酬載中的條件 | 最上層的 `scheme`、`network` 等 | 包含所選條件的 `accepted` 物件 |
| TypeScript 套件範例 | `x402-express` | `@x402/express` |

v1 付款條件的傳遞位置已載明於 [HTTP v1 規格](https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md)。v2 的標準傳遞位置是 `PAYMENT-REQUIRED` 標頭。實作也可能回傳本文，但請以標頭為準進行處理。

[HTTP v2 規格](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md)對狀態碼的說明如下。

> 伺服器使用 HTTP 402「需要付款」狀態碼表示需要付款。
>
> 來源：x402 HTTP v2 規格

v2 付款標頭是將 JSON 以 Base64 編碼後的值。Base64 並非加密方式。對外服務請使用 HTTPS。

## HTTP 402 請求與付款順序

本實作使用 EVM `exact` 方式的基本授權流程。`exact` 是支付指定金額的方式。順序遵循 [x402 v2 核心規格](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md)。

1. 用戶端在不附帶付款資訊的情況下請求付費 API。
2. 伺服器回傳 HTTP 402 和 `PAYMENT-REQUIRED`。
3. 用戶端從 `accepts` 中選擇允許的條件。
4. SDK 簽署符合所選條件的付款授權。
5. 用戶端附上 `PAYMENT-SIGNATURE` 再次發送請求。
6. 伺服器透過 facilitator 的 `/verify` 驗證授權。
7. 驗證通過後，伺服器執行資源處理。
8. 伺服器透過 `/settle` 請求結算。
9. 結算成功後，傳送付費本文和 `PAYMENT-RESPONSE`。

這個順序並非所有付款方式共用的固定順序。v2 也定義了結算時機不同的流程。下方程式碼僅允許基本的 `authorization` 流程。

### Resource server 與 facilitator 的角色

Resource server 決定價格與內容存取條件。Facilitator 負責付款驗證與結算。角色劃分以[官方 facilitator 文件](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md)為準。

| 元件 | 負責工作 | 不應視為成功的狀態 |
|---|---|---|
| 用戶端 | 選擇條件並簽署付款授權 | 僅完成簽章產生 |
| Resource server | 宣告價格並控管付費回應 | 用戶端聲稱成功 |
| Facilitator `/verify` | 確認簽章與付款條件的有效性 | 僅收到 `isValid: true` |
| Facilitator `/settle` | 在本實作中執行鏈上付款並回傳結果 | 已送出但尚未確認結果 |

`/verify` 是不會改變鏈上狀態的檢查。因此，驗證成功不代表款項已入帳。驗證後，餘額或授權狀態仍可能改變。

驗證或結算失敗時，請封鎖付費本文。無法確認成功時就封鎖的處理方式稱為 fail-closed。在[官方 Express 實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts)中也能確認這項行為。

## Base 主網與測試網比較

首次執行時，請僅使用 Base Sepolia。Circle 明確指出，測試網 USDC 不具有金融價值。地址以 [Circle 的 USDC 合約清單](https://developers.circle.com/stablecoins/usdc-contract-addresses)為準。

| 項目 | Base 主網 | Base Sepolia 測試網 |
|---|---|---|
| 用途 | 實際資產付款 | 測試實作與故障處理 |
| Chain ID | `8453` | `84532` |
| x402 v2 網路 | `eip155:8453` | `eip155:84532` |
| USDC 合約 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |
| 公開 RPC | `https://mainnet.base.org` | `https://sepolia.base.org` |
| 代幣的金融價值 | 具有實際金融價值的資產 | 無金融價值 |

請在 [Base 網路文件](https://docs.base.org/get-started/connect-to-base)中確認 Chain ID 和 RPC。即使錢包地址相同，只要鏈不同，餘額就是分開的。不可將測試網成功付款記錄為實際營收。

測試 USDC 可向 [Circle Testnet Faucet](https://faucet.circle.com/) 申請。網路請選擇 Base Sepolia，接收地址請填入付款用的測試錢包地址。

## Node.js 付費 API 實作

請在付費路由前掛上 `paymentMiddleware`。下方範例要求每次呼叫支付 **0.001 USDC**。金額採用官方賣方指南的範例價格。（確認值為每次呼叫 0.001 USDC · 來源 docs.x402.org · 2026-10-28 確認）

### 伺服器檔案

請將下列程式碼儲存為 `server.ts`。伺服器僅在本機介面接收請求。收款地址從 `PAY_TO` 環境變數讀取。

```typescript
import express from "express";
import { getAddress, zeroAddress } from "viem";
import { paymentMiddleware } from "@x402/express";
import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";

const payTo = getAddress(process.env.PAY_TO ?? "");
if (payTo === zeroAddress) throw new Error("Invalid payTo");
const network = "eip155:84532";
const resourceServer = new x402ResourceServer(
  new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" }),
).register(network, new ExactEvmScheme());

const app = express();
app.use((_req, res, next) => {
  res.setHeader("Cache-Control", "private, no-store");
  next();
});
app.use(paymentMiddleware({
  "GET /paid-data": {
    accepts: [{ scheme: "exact", price: "$0.001", network, payTo }],
    description: "Sample paid JSON",
    mimeType: "application/json",
  },
}, resourceServer));
app.get("/paid-data", (_req, res) => {
  res.json({ content: "Paid sample content" });
});
app.listen(4021, "127.0.0.1");
```

`https://x402.org/facilitator` 是官方指南中的測試用地址。本範例將其用於 Base Sepolia 結算。正式環境的 facilitator 選擇方式，請參閱[賣方指南的主網步驟](https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet)。

### 價格計算範例

範例價格換算為 USDC 最小單位是 `1000`。USDC 的小數位數為 6 位。SDK 的價格轉換以 [EVM 伺服器實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts)為準。

```text
0.001 USDC × 10^6 = 1000 최소 단위
```

| 要確認的值 | 本範例的預期值 |
|---|---|
| 伺服器設定中的 `price` | `"$0.001"` |
| 402 付款條件中的 `amount` | `"1000"` |
| 付款條件中的 `asset` | Base Sepolia USDC 合約 |
| 付款條件中的 `payTo` | 設定的收款地址 |
| 付款條件中的 `network` | `eip155:84532` |

`price` 是 SDK 設定值。實際 v2 付款條件傳遞的是 `amount`。請以字串或 `bigint` 比較整數金額。

### 執行伺服器並確認 402

請在第一個 Bash 終端機中執行伺服器。輸入的值是公開收款地址，而非私鑰。執行期間請保持此終端機開啟。

```bash
read -r -p '수취 지갑 주소: ' PAY_TO
export PAY_TO
npx tsx server.ts
```

請在第二個終端機發送未付款請求。下列指令不會簽署付款，只會輸出 HTTP 狀態與解碼後的付款條件。

```bash
node --input-type=module <<'JS'
const response = await fetch("http://127.0.0.1:4021/paid-data");
const header = response.headers.get("PAYMENT-REQUIRED");
console.log(response.status);
console.log(header && JSON.parse(
  Buffer.from(header, "base64").toString("utf8")
));
JS
```

正常的未付款回應是 HTTP 402。請將輸出的條件與上表比對。如果直接回傳付費內容，請先修正路由保護設定。

## 付款條件選擇與用戶端實作

請限制用戶端僅簽署允許的條件。本範例僅允許 Base Sepolia USDC 的指定價格。付款選項篩選使用[官方 x402Client 實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts)中的 `registerPolicy`。

1. 將下列程式碼儲存為 `client.ts`。
2. 也將下一節的 `check-transfer.ts` 儲存下來。
3. 準備好兩個檔案後，再進行執行步驟。

```typescript
import { writeFile } from "node:fs/promises";
import { getAddress, zeroAddress, type Hex, type Hash } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { decodePaymentResponseHeader } from "@x402/core/http";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { checkTransfer } from "./check-transfer.js";

const key = process.env.EVM_PRIVATE_KEY ?? "";
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) throw new Error("Invalid test key");
const signer = privateKeyToAccount(key as Hex);
const payTo = getAddress(process.env.PAY_TO ?? "");
if (payTo === zeroAddress) throw new Error("Invalid payTo");
const network = "eip155:84532";
const token = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
const client = new x402Client().register(network, new ExactEvmScheme(signer));
client.registerPolicy((version, options) => version === 2
  ? options.filter(r =>
      r.scheme === "exact" && r.network === network &&
      r.asset.toLowerCase() === token.toLowerCase() &&
      r.payTo.toLowerCase() === payTo.toLowerCase() && r.amount === "1000" &&
      (!r.extra?.assetTransferMethod || r.extra.assetTransferMethod === "eip3009") &&
      (!r.extra?.paymentFlow || r.extra.paymentFlow === "authorization"))
  : []);

const paidFetch = wrapFetchWithPayment(fetch, client);
const response = await paidFetch("http://127.0.0.1:4021/paid-data", {
  redirect: "error",
});
const raw = response.headers.get("PAYMENT-RESPONSE");
if (!raw) throw new Error(`No settlement receipt: HTTP ${response.status}`);
const settlement = decodePaymentResponseHeader(raw);
await writeFile("settlement.json", JSON.stringify(settlement, null, 2));
if (!response.ok || !settlement.success || settlement.network !== network) {
  throw new Error("Payment unresolved; inspect settlement.json before retrying");
}
const evidence = await checkTransfer(
  network, settlement.transaction as Hash, signer.address, payTo, 1000n,
);
await writeFile("transfer.json", JSON.stringify(evidence, null, 2));
console.log(await response.text());
```

`wrapFetchWithPayment` 負責處理 402 及附上簽章重新請求。使用方式遵循[官方 fetch 範例](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch)。若沒有允許的付款條件，就會停止建立付款。

AI 代理也可使用這個用戶端。不過，每次呼叫的價格上限不等於累計支出上限。請另外管理代理重複呼叫的預算。

## USDC Transfer 事件驗證

請使用結算結果中的交易雜湊，確認 USDC 轉帳日誌。僅憑交易成功狀態，無法確認收款人。`Transfer` 欄位以 [ERC-20 標準](https://eips.ethereum.org/EIPS/eip-20)為準。

驗證需要下列項目。

| 驗證項目 | 比對對象 |
|---|---|
| RPC 的 Chain ID | 伺服器允許的鏈 |
| 交易收據的 `status` | 成功狀態 |
| 發出事件的地址 | 該鏈的官方 USDC 合約 |
| `Transfer.from` | 已確認的付款人 |
| `Transfer.to` | 伺服器指定的收款地址 |
| `Transfer.value` | 伺服器要求的最小單位金額 |

請將下列程式碼儲存為 `check-transfer.ts`。查詢使用 viem 的 [getTransactionReceipt](https://viem.sh/docs/actions/public/getTransactionReceipt)。事件解析以 [parseEventLogs](https://viem.sh/docs/contract/parseEventLogs) 為準。

```typescript
import {
  createPublicClient, http, getAddress, parseEventLogs,
  erc20Abi, type Address, type Hash,
} from "viem";
import { base, baseSepolia } from "viem/chains";

const configs = {
  "eip155:84532": {
    chain: baseSepolia,
    rpc: "https://sepolia.base.org",
    token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
  },
  "eip155:8453": {
    chain: base,
    rpc: "https://mainnet.base.org",
    token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  },
} as const;

export async function checkTransfer(
  network: keyof typeof configs, hash: Hash,
  payer: Address, payTo: Address, amount: bigint,
) {
  const cfg = configs[network];
  const rpc = createPublicClient({ chain: cfg.chain, transport: http(cfg.rpc) });
  if (await rpc.getChainId() !== cfg.chain.id) throw new Error("Wrong chain");
  const receipt = await rpc.getTransactionReceipt({ hash });
  if (receipt.status !== "success") throw new Error("Transaction failed");
  const logs = parseEventLogs({
    abi: erc20Abi,
    eventName: "Transfer",
    logs: receipt.logs.filter(
      log => getAddress(log.address) === getAddress(cfg.token),
    ),
    strict: true,
  });
  const transfer = logs.find(log =>
    getAddress(log.args.from) === getAddress(payer) &&
    getAddress(log.args.to) === getAddress(payTo) &&
    log.args.value === amount,
  );
  if (!transfer) throw new Error("Matching USDC Transfer not found");
  return {
    network, transaction: hash, logIndex: transfer.logIndex,
    blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),
  };
}
```

此函式確認該筆交易確實發生 USDC 轉帳。是否歸屬於特定 API 訂單，仍須另外確認。正式環境的伺服器請使用已儲存的訂單條件作為比對值。

不可將用戶端上傳的 `transfer.json` 視為授予存取權的可信憑證。本範例的伺服器使用 facilitator 的驗證與結算結果。若要將獨立查詢作為授予存取權的條件，必須在伺服器端執行。

收據查詢失敗不代表付款失敗。如果是 RPC 錯誤，請使用已儲存的交易雜湊重新查詢。額外確認數與鏈重組的應對方式，應由營運政策決定。

## 執行測試付款與確認結果

儲存所有檔案後，請使用測試錢包執行。型別檢查不會進行簽章或轉帳。下列指令使用先前安裝的 TypeScript 工具。

1. 使用下列指令檢查型別。
2. 在第二個終端機輸入與伺服器相同的收款地址。
3. 以隱藏輸入方式輸入測試付款錢包的私鑰。
4. 執行用戶端一次。
5. 確認儲存的結算結果與轉帳日誌。

```bash
npx tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext server.ts client.ts check-transfer.ts
read -r -p '같은 수취 지갑 주소: ' PAY_TO
read -r -s -p '테스트 결제 지갑 개인키: ' EVM_PRIVATE_KEY
export PAY_TO EVM_PRIVATE_KEY
npx tsx client.ts
unset EVM_PRIVATE_KEY
```

| 輸出結果 | 意義 | 要確認的內容 |
|---|---|---|
| `settlement.json` | 伺服器回傳的結算結果 | `success`、`network`、`transaction` |
| `transfer.json` | RPC 查詢找到的轉帳紀錄 | 鏈、交易雜湊、日誌位置、區塊資訊 |
| 主控台中的付費本文 | 此用戶端驗證後輸出的資料 | 確認是否為請求的內容 |

重新執行用戶端可能產生新的付款。此最小範例沒有防止訂單重複處理的儲存機制。請在具備下一節的條件後，再加入重試功能。

## 各種驗證失敗條件的處理

進行失敗測試時，請確認付費本文不會外洩。若只檢查 HTTP 狀態，可能漏掉未封鎖的情況。基準行為請參考[官方 Express 中介軟體](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts)。

| 測試條件 | 預期處理 | 額外確認 |
|---|---|---|
| 無付款標頭 | 回傳 402 與付款條件 | 無付費本文 |
| 提供其他代幣或收款人 | 由用戶端政策拒絕 | 不產生簽章 |
| 錯誤簽章 | 因驗證失敗而封鎖 | 不執行付費處理函式 |
| 餘額不足 | 因驗證或結算失敗而封鎖 | 不記錄為結算成功 |
| 結算結果失敗 | 封鎖付費回應 | 已準備好的本文也不傳送 |
| facilitator 回應延遲 | 因尚未確認成功而維持待處理 | 禁止自動產生新授權 |
| RPC 收據查詢錯誤 | 保留交易雜湊並重新查詢 | 不可斷定付款失敗 |

基本授權流程會在結算前執行處理函式。結算失敗不會一併復原外部操作。請像本範例一樣，先從沒有副作用的查詢開始套用。

寄送電子郵件或建立外部訂單需要另外設計。請一併記錄付款與作業狀態。必須界定失敗時重新執行的範圍，才能減少重複作業。

## 結算後回應遺失與重傳復原

請將付款完成與內容傳送完成儲存為不同狀態。付款可能已完成，但回應連線卻中斷。處理這類情況的依據是 [Payment-Identifier 擴充文件](https://docs.x402.org/extensions/payment-identifier)。

再次請求同一項作業也不會重複處理的性質，稱為冪等性。`payment-identifier` 為此提供付款識別碼。這項功能並非只要加入識別碼就會自動完成。

### 重複付款與重傳比較

必須區分防止同一簽章重用與防止訂單重複處理。EIP-3009 會防止已使用的授權 nonce 再次使用。這項行為定義於 [ERC-3009 規格](https://eips.ethereum.org/EIPS/eip-3009)。

| 情況 | 鏈上授權角度 | API 營運角度 |
|---|---|---|
| 再次結算同一授權 | 須檢查是否為已使用的 nonce | 需要查詢既有結果 |
| 為同一訂單建立新授權 | 可能被視為獨立授權處理 | 需要防止重複付款 |
| 結算成功後回應遺失 | 資產移轉可能已完成 | 需要重新傳送內容 |
| 請求結算後逾時 | 結果仍不明確 | 需要待處理狀態與結算確認 |

以下步驟是將官方擴充連接至正式環境儲存系統的設計方案，並未包含在前面的最小程式碼中。若要用於正式環境，請加入持久化儲存與並行請求控制。

1. 在伺服器宣告支援 `payment-identifier` 擴充。
2. 在用戶端保留邏輯請求的識別碼。
3. 在伺服器將識別碼與付款人及請求內容連結。
4. 以原子操作記錄處理中狀態，防止同時執行。
5. 結算成功時，儲存交易憑證與回應結果。
6. 若再次請求的權限與內容相同，則回傳已儲存的結果。
7. 若結算結果不明確，先確認既有授權。

付款識別碼不是密碼或存取權杖。不可向僅知道識別碼的請求回傳付費快取。也請檢查是否被其他使用者或不同請求本文重用。

營運紀錄請一併保留鏈、交易雜湊與日誌位置。將這些紀錄與訂單連結，防止被其他訂單重用。僅有 `Transfer` 相符，無法證明訂單歸屬。

## 付款實作的常見錯誤

混淆版本欄位與成功訊號，會導致付款判定錯誤。請在部署審查時使用下表。版本差異以 [x402 遷移指南](https://docs.x402.org/guides/migration-v1-to-v2)為準。

| 常見錯誤 | 修正依據 |
|---|---|
| 將 `extra.version: "2"` 解讀為 x402 版本 | 透過 `x402Version` 確認協定版本 |
| 在 v2 使用 `maxAmountRequired` | 付款條件的金額使用 `amount` |
| 自行建立 `X-PAYMENT-REQUIRED` 標頭 | v1 使用本文，v2 使用 `PAYMENT-REQUIRED` |
| 將 `isValid: true` 視為款項已入帳 | 另外確認 `/settle` 結果 |
| 將交易最上層的 `to` 視為 USDC 收款人 | 確認 USDC `Transfer.to` |
| 假設簽署者與交易發送者相同 | 比對授權付款人與 `Transfer.from` |
| 將測試網收款金額計入營收 | 分開主網與測試網帳目 |
| 每次逾時都建立新付款 | 先復原既有訂單與授權狀態 |
| 將 SDK 套件版本與協定版本視為相同 | 分別管理套件版本與 `x402Version` |

USDC 簽章的網域資訊也包含版本字串。該值與 x402 協定版本的用途不同。簽章網域結構請參閱 [ERC-3009 規格](https://eips.ethereum.org/EIPS/eip-3009)。

## 安全檢查與外部服務的信任範圍

請由伺服器控制付款成功的判定。外部 facilitator 的回應也是明確納入信任的對象。[facilitator 文件](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md)說明了也可自行營運的架構。

- 不要依據用戶端的成功訊息開放內容。
- 請比對伺服器宣告的鏈、代幣、金額與收款人。
- 不要將私鑰與助記詞寫入日誌。
- 完整的授權簽章也應排除在一般存取日誌之外。
- 請限制付款標頭大小與請求處理時間。
- 請檢查付費回應是否會留在共用快取中。
- 請分開存放測試金鑰與正式環境金鑰。
- facilitator 故障時，不要建立免付款的繞過路徑。
- 請實際測試授權到期與重複請求。

本實作鎖定的相依套件仍有安全檢查警告。`npm audit` 回報了與 zod 相關的安全公告。相關內容請參閱 [GitHub 安全公告](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5)。

```bash
npm audit
```

正式部署前，請確認修正版與 SDK 的相容性。強制更換主要版本可能導致行為改變。不要將本實作當成已完成安全驗證的部署設定。

### 自有伺服器與 Cloudflare Gateway 比較

使用 Cloudflare Gateway 時，來源伺服器的驗證方式會改變。2026年9月30日的文件明確指出使用 x402 v2。下列區分以 [Cloudflare x402 文件](https://developers.cloudflare.com/monetization-gateway/x402/)為準。

| 類別 | 本文的 Express 方式 | Cloudflare Monetization Gateway |
|---|---|---|
| 用戶端付款處理 | Express 中介軟體 | Gateway |
| 來源伺服器的驗證點 | 與所選 facilitator 串接 | 驗證 `PAYMENT-CONTEXT` JWT |
| 結算結果傳遞 | 中介軟體的 `PAYMENT-RESPONSE` | Gateway 產生結算收據 |
| 額外確認事項 | facilitator 支援的鏈與身分驗證 | JWT 簽章驗證與來源存取保護 |

`PAYMENT-CONTEXT` 是 Gateway 與來源伺服器之間的標頭，不是一般 x402 用戶端的簽章標頭。來源驗證請遵循 [Cloudflare Payment validation 文件](https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/)。

即使經過 Gateway，也不能只將 JWT 解碼。請使用文件指定的金鑰驗證簽章。若缺少標頭或驗證失敗，就封鎖付費內容。

## 區分實際使用量與結算紀錄

僅憑鏈上轉帳筆數，無法證明內容已被使用。請將結算與回應傳送連結後，再彙整營運指標。這是根據付款流程與重傳行為提出的設計建議。

| 紀錄 | 可回答的問題 | 額外需要的紀錄 |
|---|---|---|
| 402 回應 | 付款條件被請求了多少次 | 是否實際付款 |
| 驗證成功 | 授權是否有效 | 結算結果 |
| USDC 轉帳 | 資產是否移轉 | 訂單歸屬 |
| 各訂單結算完成 | 付費請求是否已付款 | 回應傳送狀態 |
| 重新傳送紀錄 | 是否復原了已付款的請求 | 與新付款區分的識別碼 |

請在實際使用量統計中區分測試請求。同一訂單的重試也應另外標示。不可將交易量本身解釋為 API 需求或收益保證。

## Base 主網切換步驟

確認測試網的正常與失敗路徑後，再評估主網。切換並非只要更改網路字串就完成。標準步驟遵循[官方賣方指南](https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet)。

1. 確認所選 facilitator 支援 Base 主網。
2. 在 `/supported` 確認支援 v2、`exact`、`eip155:8453`。
3. 設定提供者要求的身分驗證與使用條件。
4. 同時更改伺服器與用戶端的網路。
5. 將用戶端允許的 USDC 地址改為主網地址。
6. 再次比對 402 回應的金額與實際收款地址。
7. 接上重複請求儲存機制與故障復原程序。
8. 完成正式環境相依套件的安全檢查。
9. 以設定的小額款項確認實際轉帳與內容傳送。

支援多鏈不代表支援所有組合。請同時確認 SDK 與 facilitator 的支援範圍。確認依據為[網路與代幣支援文件](https://docs.x402.org/core-concepts/network-and-token-support)。

## FAQ

### x402 與一般的 USDC 入帳確認有什麼不同？
在 HTTP 請求過程中傳遞付款條件，並以已簽署的付款授權重新發送請求。不同於事後核對入帳紀錄的方式，這種做法將付款流程與付費資源請求連結。

### x402 v2 的付款標頭有哪些？
付款條件透過 PAYMENT-REQUIRED 傳遞，付款酬載透過 PAYMENT-SIGNATURE 傳遞。結算結果透過 PAYMENT-RESPONSE 傳遞。

### v1 有 X-PAYMENT-REQUIRED 標頭嗎？
官方 HTTP v1 規格將最初的付款條件放在 JSON 回應本文中。付款酬載與結算結果則分別使用 X-PAYMENT 和 X-PAYMENT-RESPONSE。

### /verify 成功就代表付款完成了嗎？
/verify 成功表示付款授權有效。在本次實作中，必須另外確認 /settle 的成功結果。

### Base Sepolia 測試 USDC 可以視為實際收益嗎？
Circle 明確表示，測試網 USDC 不具金融價值。請將測試網結算與實際營收分開記錄。

### 需要在收款伺服器中放入私鑰嗎？
本範例的收款伺服器只設定公開的收款地址。付款授權使用的私鑰由付款用戶端讀取。

### 0.001 USDC 的 amount 值是多少？
依 USDC 的 6 位小數換算，以最小單位表示為 1000。v2 付款條件使用字串 "1000"。

### 交易收據顯示成功，就代表已確認收到 USDC 嗎？
僅憑交易成功狀態還不夠。請在官方 USDC 合約的 Transfer 事件中核對付款人、收款人與金額。

### 再次發送相同的付款請求安全嗎？
防止同一授權 nonce 被重複使用，與防止訂單重複是兩回事。重試前請確認既有付款的狀態，並針對每筆訂單實作冪等性處理。

### 沒有 PAYMENT-RESPONSE 時，重新付款就可以了嗎？
若回應遺失或逾時，結算結果可能不明確。請勿先建立新的授權，應先確認原請求的結算狀態。

### x402 必須使用特定公司的 facilitator 嗎？
官方架構允許使用外部 facilitator，也允許自行營運。請確認所選的實作支援所需的協定版本、付款方式與鏈。

### AI 代理的支出也會自動受到限制嗎？
本範例只限制每次請求的付款條件。請透過另外的預算政策管理重複呼叫所產生的累積支出。

### Cloudflare PAYMENT-CONTEXT 是標準的付款簽章標頭嗎？
PAYMENT-CONTEXT 是 Gateway 傳送給來源伺服器的 JWT，用途與用戶端的 PAYMENT-SIGNATURE 不同。

### 可以直接將範例部署到主網嗎？
這段程式碼是供測試使用的最小配置。正式部署前，請確認相依套件的安全警告、重複請求處理、facilitator 身分驗證與實際結算。

## Sources

- [x402 協定規格 v2](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md)
- [x402 HTTP 傳輸 v1](https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md)
- [x402 HTTP 傳輸 v2](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md)
- [x402 遷移指南：V1 至 V2](https://docs.x402.org/guides/migration-v1-to-v2)
- [x402 Facilitator 的角色與責任](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md)
- [x402 賣方快速入門](https://docs.x402.org/getting-started/quickstart-for-sellers)
- [x402 買方快速入門](https://docs.x402.org/getting-started/quickstart-for-buyers)
- [x402 官方 TypeScript fetch 用戶端範例](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch)
- [x402 Express 中介軟體實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts)
- [x402Client 付款條件選擇與政策實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts)
- [x402 ExactEvmScheme 伺服器端價格轉換實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts)
- [Circle USDC 合約地址](https://developers.circle.com/stablecoins/usdc-contract-addresses)
- [Base 主網與 Base Sepolia 網路資訊](https://docs.base.org/get-started/connect-to-base)
- [Circle 測試網水龍頭](https://faucet.circle.com/)
- [viem getTransactionReceipt](https://viem.sh/docs/actions/public/getTransactionReceipt)
- [viem parseEventLogs](https://viem.sh/docs/contract/parseEventLogs)
- [ERC-20 代幣標準](https://eips.ethereum.org/EIPS/eip-20)
- [ERC-3009 授權轉帳](https://eips.ethereum.org/EIPS/eip-3009)
- [x402 Payment-Identifier 冪等性擴充](https://docs.x402.org/extensions/payment-identifier)
- [Cloudflare Monetization Gateway x402 協定](https://developers.cloudflare.com/monetization-gateway/x402/)
- [Cloudflare Monetization Gateway 付款驗證](https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/)
- [x402 網路與代幣支援](https://docs.x402.org/core-concepts/network-and-token-support)
- [GitHub 安全公告：Zod 驗證大型集合所導致的記憶體耗盡](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5)

## Images

![一名穿著深灰色毛衣的男子正在查看伺服器機架層板上的平板電腦。](https://injoys.com/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzM4MDcsInB1ciI6ImJsb2JfaWQifX0=--49c502fd8da16158a617c3586dfa81ced4bc95df/ai-f0ae2b5c.webp)
![一名女子在窗邊操作完全攤平的筆記型電腦，螢幕顯示清單及兩條路徑匯合的流程圖。](https://injoys.com/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzM4MTMsInB1ciI6ImJsb2JfaWQifX0=--4e70727f132519277c68d1c6279d95585a936549/ai-3dbd1c62.webp)