{"content_id":"gyaevhk2bq","slug":"x402-payments-2026-v2-base-usdc-settlement-guide","locale":"zh-hant","schema_type":"HowTo","category":"tutorial","category_name":"教學課程","title":"x402 支付 2026 v2 實作與結算驗證","summary":"透過 x402 v2 為 API 加入小額支付的 Node.js 實作教學。在 Base Sepolia 上選擇支付條件、簽署並重新發送請求，以及驗證結算，接著檢查重送與切換至主網的條件。","sponsorship_disclosure":null,"affiliate_disclosure":null,"commerce_disclosure":null,"author":{"name":"injoys","url":"https://injoys.com/ko/about"},"key_points":["準備收款地址與測試用支付錢包，並安裝官方 x402 SDK。","串接適用於 Base Sepolia 的支付中介軟體，並確認未支付請求的 402 回應。","僅選擇符合客戶端允許的鏈、代幣、金額與收款人的條件，並進行簽署。","使用結算回應中的交易雜湊查詢 USDC Transfer 事件。","測試失敗時的阻擋機制與重複請求復原後，再檢視主網設定。"],"content_markdown":"x402 付款透過在 API 的 402 回應中包含付款條件來實作。請準備 Node.js 和測試錢包。先在 Base Sepolia 驗證 v2 簽章與結算。請設定為結算成功後才傳送付費回應。\n\n金額與鏈資訊以來源連結中的 x402、Base、Circle 官方文件為準。\n\n## 實作準備與安裝\n\n請準備可修改 API 的開發環境及測試錢包。範例以 Node.js 22 和 x402 SDK 2.28.0 為基礎。安裝結構遵循[官方賣方指南](https://docs.x402.org/getting-started/quickstart-for-sellers)。\n\n1. 準備接收付款的 EVM 錢包地址。\n2. 另外準備付款用的測試錢包。\n3. 在付款錢包中取得 Base Sepolia 測試 USDC。\n4. 使用下列指令建立實作專案。\n5. 將後續的 TypeScript 檔案儲存在同一個資料夾中。\n\n```bash\nmkdir x402-demo\ncd x402-demo\nnpm init -y\nnpm pkg set type=module\nnpm 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\nnpm install --save-dev --save-exact typescript tsx @types/node @types/express\n```\n\n收款伺服器不需要收款錢包的私鑰。請設定為僅由用戶端程序讀取付款私鑰。錢包簽章方式以[官方買方指南](https://docs.x402.org/getting-started/quickstart-for-buyers)為準。\n\n本範例的驗證範圍為型別檢查與模擬付款流程，並未完成實際測試網轉帳。請在下方執行步驟中自行確認鏈上結果。\n\n## x402 v1 與 v2 比較\n\n實作 v2 時，必須同時配合標頭和本文欄位。只更改標頭名稱，資料結構仍會不符。下表以[官方遷移指南](https://docs.x402.org/guides/migration-v1-to-v2)為準。\n\n| 類別 | v1 | v2 |\n|---|---|---|\n| 協定版本 | `x402Version: 1` | `x402Version: 2` |\n| 初始付款條件 | 402 回應的 JSON 本文 | `PAYMENT-REQUIRED` 回應標頭 |\n| 已簽署的付款資料 | `X-PAYMENT` 請求標頭 | `PAYMENT-SIGNATURE` 請求標頭 |\n| 結算結果 | `X-PAYMENT-RESPONSE` 回應標頭 | `PAYMENT-RESPONSE` 回應標頭 |\n| Base 主網識別碼 | `base` | `eip155:8453` |\n| Base Sepolia 識別碼 | `base-sepolia` | `eip155:84532` |\n| 付款條件的金額欄位 | `maxAmountRequired` | `amount` |\n| 資源描述 | 付款條件內的 `resource` 等 | 最上層的 `resource` 物件 |\n| 付款酬載中的條件 | 最上層的 `scheme`、`network` 等 | 包含所選條件的 `accepted` 物件 |\n| TypeScript 套件範例 | `x402-express` | `@x402/express` |\n\nv1 付款條件的傳遞位置已載明於 [HTTP v1 規格](https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md)。v2 的標準傳遞位置是 `PAYMENT-REQUIRED` 標頭。實作也可能回傳本文，但請以標頭為準進行處理。\n\n[HTTP v2 規格](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md)對狀態碼的說明如下。\n\n\u003e 伺服器使用 HTTP 402「需要付款」狀態碼表示需要付款。\n\u003e\n\u003e 來源：x402 HTTP v2 規格\n\nv2 付款標頭是將 JSON 以 Base64 編碼後的值。Base64 並非加密方式。對外服務請使用 HTTPS。\n\n## HTTP 402 請求與付款順序\n\n本實作使用 EVM `exact` 方式的基本授權流程。`exact` 是支付指定金額的方式。順序遵循 [x402 v2 核心規格](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md)。\n\n1. 用戶端在不附帶付款資訊的情況下請求付費 API。\n2. 伺服器回傳 HTTP 402 和 `PAYMENT-REQUIRED`。\n3. 用戶端從 `accepts` 中選擇允許的條件。\n4. SDK 簽署符合所選條件的付款授權。\n5. 用戶端附上 `PAYMENT-SIGNATURE` 再次發送請求。\n6. 伺服器透過 facilitator 的 `/verify` 驗證授權。\n7. 驗證通過後，伺服器執行資源處理。\n8. 伺服器透過 `/settle` 請求結算。\n9. 結算成功後，傳送付費本文和 `PAYMENT-RESPONSE`。\n\n這個順序並非所有付款方式共用的固定順序。v2 也定義了結算時機不同的流程。下方程式碼僅允許基本的 `authorization` 流程。\n\n### Resource server 與 facilitator 的角色\n\nResource server 決定價格與內容存取條件。Facilitator 負責付款驗證與結算。角色劃分以[官方 facilitator 文件](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md)為準。\n\n| 元件 | 負責工作 | 不應視為成功的狀態 |\n|---|---|---|\n| 用戶端 | 選擇條件並簽署付款授權 | 僅完成簽章產生 |\n| Resource server | 宣告價格並控管付費回應 | 用戶端聲稱成功 |\n| Facilitator `/verify` | 確認簽章與付款條件的有效性 | 僅收到 `isValid: true` |\n| Facilitator `/settle` | 在本實作中執行鏈上付款並回傳結果 | 已送出但尚未確認結果 |\n\n`/verify` 是不會改變鏈上狀態的檢查。因此，驗證成功不代表款項已入帳。驗證後，餘額或授權狀態仍可能改變。\n\n驗證或結算失敗時，請封鎖付費本文。無法確認成功時就封鎖的處理方式稱為 fail-closed。在[官方 Express 實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts)中也能確認這項行為。\n\n## Base 主網與測試網比較\n\n首次執行時，請僅使用 Base Sepolia。Circle 明確指出，測試網 USDC 不具有金融價值。地址以 [Circle 的 USDC 合約清單](https://developers.circle.com/stablecoins/usdc-contract-addresses)為準。\n\n| 項目 | Base 主網 | Base Sepolia 測試網 |\n|---|---|---|\n| 用途 | 實際資產付款 | 測試實作與故障處理 |\n| Chain ID | `8453` | `84532` |\n| x402 v2 網路 | `eip155:8453` | `eip155:84532` |\n| USDC 合約 | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |\n| 公開 RPC | `https://mainnet.base.org` | `https://sepolia.base.org` |\n| 代幣的金融價值 | 具有實際金融價值的資產 | 無金融價值 |\n\n請在 [Base 網路文件](https://docs.base.org/get-started/connect-to-base)中確認 Chain ID 和 RPC。即使錢包地址相同，只要鏈不同，餘額就是分開的。不可將測試網成功付款記錄為實際營收。\n\n測試 USDC 可向 [Circle Testnet Faucet](https://faucet.circle.com/) 申請。網路請選擇 Base Sepolia，接收地址請填入付款用的測試錢包地址。\n\n## Node.js 付費 API 實作\n\n請在付費路由前掛上 `paymentMiddleware`。下方範例要求每次呼叫支付 **0.001 USDC**。金額採用官方賣方指南的範例價格。（確認值為每次呼叫 0.001 USDC · 來源 docs.x402.org · 2026-10-28 確認）\n\n### 伺服器檔案\n\n請將下列程式碼儲存為 `server.ts`。伺服器僅在本機介面接收請求。收款地址從 `PAY_TO` 環境變數讀取。\n\n```typescript\nimport express from \"express\";\nimport { getAddress, zeroAddress } from \"viem\";\nimport { paymentMiddleware } from \"@x402/express\";\nimport { HTTPFacilitatorClient, x402ResourceServer } from \"@x402/core/server\";\nimport { ExactEvmScheme } from \"@x402/evm/exact/server\";\n\nconst payTo = getAddress(process.env.PAY_TO ?? \"\");\nif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\nconst network = \"eip155:84532\";\nconst resourceServer = new x402ResourceServer(\n  new HTTPFacilitatorClient({ url: \"https://x402.org/facilitator\" }),\n).register(network, new ExactEvmScheme());\n\nconst app = express();\napp.use((_req, res, next) =\u003e {\n  res.setHeader(\"Cache-Control\", \"private, no-store\");\n  next();\n});\napp.use(paymentMiddleware({\n  \"GET /paid-data\": {\n    accepts: [{ scheme: \"exact\", price: \"$0.001\", network, payTo }],\n    description: \"Sample paid JSON\",\n    mimeType: \"application/json\",\n  },\n}, resourceServer));\napp.get(\"/paid-data\", (_req, res) =\u003e {\n  res.json({ content: \"Paid sample content\" });\n});\napp.listen(4021, \"127.0.0.1\");\n```\n\n`https://x402.org/facilitator` 是官方指南中的測試用地址。本範例將其用於 Base Sepolia 結算。正式環境的 facilitator 選擇方式，請參閱[賣方指南的主網步驟](https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet)。\n\n### 價格計算範例\n\n範例價格換算為 USDC 最小單位是 `1000`。USDC 的小數位數為 6 位。SDK 的價格轉換以 [EVM 伺服器實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts)為準。\n\n```text\n0.001 USDC × 10^6 = 1000 최소 단위\n```\n\n| 要確認的值 | 本範例的預期值 |\n|---|---|\n| 伺服器設定中的 `price` | `\"$0.001\"` |\n| 402 付款條件中的 `amount` | `\"1000\"` |\n| 付款條件中的 `asset` | Base Sepolia USDC 合約 |\n| 付款條件中的 `payTo` | 設定的收款地址 |\n| 付款條件中的 `network` | `eip155:84532` |\n\n`price` 是 SDK 設定值。實際 v2 付款條件傳遞的是 `amount`。請以字串或 `bigint` 比較整數金額。\n\n### 執行伺服器並確認 402\n\n請在第一個 Bash 終端機中執行伺服器。輸入的值是公開收款地址，而非私鑰。執行期間請保持此終端機開啟。\n\n```bash\nread -r -p '수취 지갑 주소: ' PAY_TO\nexport PAY_TO\nnpx tsx server.ts\n```\n\n請在第二個終端機發送未付款請求。下列指令不會簽署付款，只會輸出 HTTP 狀態與解碼後的付款條件。\n\n```bash\nnode --input-type=module \u003c\u003c'JS'\nconst response = await fetch(\"http://127.0.0.1:4021/paid-data\");\nconst header = response.headers.get(\"PAYMENT-REQUIRED\");\nconsole.log(response.status);\nconsole.log(header \u0026\u0026 JSON.parse(\n  Buffer.from(header, \"base64\").toString(\"utf8\")\n));\nJS\n```\n\n正常的未付款回應是 HTTP 402。請將輸出的條件與上表比對。如果直接回傳付費內容，請先修正路由保護設定。\n\n## 付款條件選擇與用戶端實作\n\n請限制用戶端僅簽署允許的條件。本範例僅允許 Base Sepolia USDC 的指定價格。付款選項篩選使用[官方 x402Client 實作](https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts)中的 `registerPolicy`。\n\n1. 將下列程式碼儲存為 `client.ts`。\n2. 也將下一節的 `check-transfer.ts` 儲存下來。\n3. 準備好兩個檔案後，再進行執行步驟。\n\n```typescript\nimport { writeFile } from \"node:fs/promises\";\nimport { getAddress, zeroAddress, type Hex, type Hash } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { x402Client, wrapFetchWithPayment } from \"@x402/fetch\";\nimport { decodePaymentResponseHeader } from \"@x402/core/http\";\nimport { ExactEvmScheme } from \"@x402/evm/exact/client\";\nimport { checkTransfer } from \"./check-transfer.js\";\n\nconst key = process.env.EVM_PRIVATE_KEY ?? \"\";\nif (!/^0x[0-9a-fA-F]{64}$/.test(key)) throw new Error(\"Invalid test key\");\nconst signer = privateKeyToAccount(key as Hex);\nconst payTo = getAddress(process.env.PAY_TO ?? \"\");\nif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\nconst network = \"eip155:84532\";\nconst token = \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\";\nconst client = new x402Client().register(network, new ExactEvmScheme(signer));\nclient.registerPolicy((version, options) =\u003e version === 2\n  ? options.filter(r =\u003e\n      r.scheme === \"exact\" \u0026\u0026 r.network === network \u0026\u0026\n      r.asset.toLowerCase() === token.toLowerCase() \u0026\u0026\n      r.payTo.toLowerCase() === payTo.toLowerCase() \u0026\u0026 r.amount === \"1000\" \u0026\u0026\n      (!r.extra?.assetTransferMethod || r.extra.assetTransferMethod === \"eip3009\") \u0026\u0026\n      (!r.extra?.paymentFlow || r.extra.paymentFlow === \"authorization\"))\n  : []);\n\nconst paidFetch = wrapFetchWithPayment(fetch, client);\nconst response = await paidFetch(\"http://127.0.0.1:4021/paid-data\", {\n  redirect: \"error\",\n});\nconst raw = response.headers.get(\"PAYMENT-RESPONSE\");\nif (!raw) throw new Error(`No settlement receipt: HTTP ${response.status}`);\nconst settlement = decodePaymentResponseHeader(raw);\nawait writeFile(\"settlement.json\", JSON.stringify(settlement, null, 2));\nif (!response.ok || !settlement.success || settlement.network !== network) {\n  throw new Error(\"Payment unresolved; inspect settlement.json before retrying\");\n}\nconst evidence = await checkTransfer(\n  network, settlement.transaction as Hash, signer.address, payTo, 1000n,\n);\nawait writeFile(\"transfer.json\", JSON.stringify(evidence, null, 2));\nconsole.log(await response.text());\n```\n\n`wrapFetchWithPayment` 負責處理 402 及附上簽章重新請求。使用方式遵循[官方 fetch 範例](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch)。若沒有允許的付款條件，就會停止建立付款。\n\nAI 代理也可使用這個用戶端。不過，每次呼叫的價格上限不等於累計支出上限。請另外管理代理重複呼叫的預算。\n\n## USDC Transfer 事件驗證\n\n請使用結算結果中的交易雜湊，確認 USDC 轉帳日誌。僅憑交易成功狀態，無法確認收款人。`Transfer` 欄位以 [ERC-20 標準](https://eips.ethereum.org/EIPS/eip-20)為準。\n\n驗證需要下列項目。\n\n| 驗證項目 | 比對對象 |\n|---|---|\n| RPC 的 Chain ID | 伺服器允許的鏈 |\n| 交易收據的 `status` | 成功狀態 |\n| 發出事件的地址 | 該鏈的官方 USDC 合約 |\n| `Transfer.from` | 已確認的付款人 |\n| `Transfer.to` | 伺服器指定的收款地址 |\n| `Transfer.value` | 伺服器要求的最小單位金額 |\n\n請將下列程式碼儲存為 `check-transfer.ts`。查詢使用 viem 的 [getTransactionReceipt](https://viem.sh/docs/actions/public/getTransactionReceipt)。事件解析以 [parseEventLogs](https://viem.sh/docs/contract/parseEventLogs) 為準。\n\n```typescript\nimport {\n  createPublicClient, http, getAddress, parseEventLogs,\n  erc20Abi, type Address, type Hash,\n} from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\n\nconst configs = {\n  \"eip155:84532\": {\n    chain: baseSepolia,\n    rpc: \"https://sepolia.base.org\",\n    token: \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\",\n  },\n  \"eip155:8453\": {\n    chain: base,\n    rpc: \"https://mainnet.base.org\",\n    token: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n  },\n} as const;\n\nexport async function checkTransfer(\n  network: keyof typeof configs, hash: Hash,\n  payer: Address, payTo: Address, amount: bigint,\n) {\n  const cfg = configs[network];\n  const rpc = createPublicClient({ chain: cfg.chain, transport: http(cfg.rpc) });\n  if (await rpc.getChainId() !== cfg.chain.id) throw new Error(\"Wrong chain\");\n  const receipt = await rpc.getTransactionReceipt({ hash });\n  if (receipt.status !== \"success\") throw new Error(\"Transaction failed\");\n  const logs = parseEventLogs({\n    abi: erc20Abi,\n    eventName: \"Transfer\",\n    logs: receipt.logs.filter(\n      log =\u003e getAddress(log.address) === getAddress(cfg.token),\n    ),\n    strict: true,\n  });\n  const transfer = logs.find(log =\u003e\n    getAddress(log.args.from) === getAddress(payer) \u0026\u0026\n    getAddress(log.args.to) === getAddress(payTo) \u0026\u0026\n    log.args.value === amount,\n  );\n  if (!transfer) throw new Error(\"Matching USDC Transfer not found\");\n  return {\n    network, transaction: hash, logIndex: transfer.logIndex,\n    blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),\n  };\n}\n```\n\n此函式確認該筆交易確實發生 USDC 轉帳。是否歸屬於特定 API 訂單，仍須另外確認。正式環境的伺服器請使用已儲存的訂單條件作為比對值。\n\n不可將用戶端上傳的 `transfer.json` 視為授予存取權的可信憑證。本範例的伺服器使用 facilitator 的驗證與結算結果。若要將獨立查詢作為授予存取權的條件，必須在伺服器端執行。\n\n收據查詢失敗不代表付款失敗。如果是 RPC 錯誤，請使用已儲存的交易雜湊重新查詢。額外確認數與鏈重組的應對方式，應由營運政策決定。\n\n## 執行測試付款與確認結果\n\n儲存所有檔案後，請使用測試錢包執行。型別檢查不會進行簽章或轉帳。下列指令使用先前安裝的 TypeScript 工具。\n\n1. 使用下列指令檢查型別。\n2. 在第二個終端機輸入與伺服器相同的收款地址。\n3. 以隱藏輸入方式輸入測試付款錢包的私鑰。\n4. 執行用戶端一次。\n5. 確認儲存的結算結果與轉帳日誌。\n\n```bash\nnpx tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext server.ts client.ts check-transfer.ts\nread -r -p '같은 수취 지갑 주소: ' PAY_TO\nread -r -s -p '테스트 결제 지갑 개인키: ' EVM_PRIVATE_KEY\nexport PAY_TO EVM_PRIVATE_KEY\nnpx tsx client.ts\nunset EVM_PRIVATE_KEY\n```\n\n| 輸出結果 | 意義 | 要確認的內容 |\n|---|---|---|\n| `settlement.json` | 伺服器回傳的結算結果 | `success`、`network`、`transaction` |\n| `transfer.json` | RPC 查詢找到的轉帳紀錄 | 鏈、交易雜湊、日誌位置、區塊資訊 |\n| 主控台中的付費本文 | 此用戶端驗證後輸出的資料 | 確認是否為請求的內容 |\n\n重新執行用戶端可能產生新的付款。此最小範例沒有防止訂單重複處理的儲存機制。請在具備下一節的條件後，再加入重試功能。\n\n## 各種驗證失敗條件的處理\n\n進行失敗測試時，請確認付費本文不會外洩。若只檢查 HTTP 狀態，可能漏掉未封鎖的情況。基準行為請參考[官方 Express 中介軟體](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts)。\n\n| 測試條件 | 預期處理 | 額外確認 |\n|---|---|---|\n| 無付款標頭 | 回傳 402 與付款條件 | 無付費本文 |\n| 提供其他代幣或收款人 | 由用戶端政策拒絕 | 不產生簽章 |\n| 錯誤簽章 | 因驗證失敗而封鎖 | 不執行付費處理函式 |\n| 餘額不足 | 因驗證或結算失敗而封鎖 | 不記錄為結算成功 |\n| 結算結果失敗 | 封鎖付費回應 | 已準備好的本文也不傳送 |\n| facilitator 回應延遲 | 因尚未確認成功而維持待處理 | 禁止自動產生新授權 |\n| RPC 收據查詢錯誤 | 保留交易雜湊並重新查詢 | 不可斷定付款失敗 |\n\n基本授權流程會在結算前執行處理函式。結算失敗不會一併復原外部操作。請像本範例一樣，先從沒有副作用的查詢開始套用。\n\n寄送電子郵件或建立外部訂單需要另外設計。請一併記錄付款與作業狀態。必須界定失敗時重新執行的範圍，才能減少重複作業。\n\n## 結算後回應遺失與重傳復原\n\n請將付款完成與內容傳送完成儲存為不同狀態。付款可能已完成，但回應連線卻中斷。處理這類情況的依據是 [Payment-Identifier 擴充文件](https://docs.x402.org/extensions/payment-identifier)。\n\n再次請求同一項作業也不會重複處理的性質，稱為冪等性。`payment-identifier` 為此提供付款識別碼。這項功能並非只要加入識別碼就會自動完成。\n\n### 重複付款與重傳比較\n\n必須區分防止同一簽章重用與防止訂單重複處理。EIP-3009 會防止已使用的授權 nonce 再次使用。這項行為定義於 [ERC-3009 規格](https://eips.ethereum.org/EIPS/eip-3009)。\n\n| 情況 | 鏈上授權角度 | API 營運角度 |\n|---|---|---|\n| 再次結算同一授權 | 須檢查是否為已使用的 nonce | 需要查詢既有結果 |\n| 為同一訂單建立新授權 | 可能被視為獨立授權處理 | 需要防止重複付款 |\n| 結算成功後回應遺失 | 資產移轉可能已完成 | 需要重新傳送內容 |\n| 請求結算後逾時 | 結果仍不明確 | 需要待處理狀態與結算確認 |\n\n以下步驟是將官方擴充連接至正式環境儲存系統的設計方案，並未包含在前面的最小程式碼中。若要用於正式環境，請加入持久化儲存與並行請求控制。\n\n1. 在伺服器宣告支援 `payment-identifier` 擴充。\n2. 在用戶端保留邏輯請求的識別碼。\n3. 在伺服器將識別碼與付款人及請求內容連結。\n4. 以原子操作記錄處理中狀態，防止同時執行。\n5. 結算成功時，儲存交易憑證與回應結果。\n6. 若再次請求的權限與內容相同，則回傳已儲存的結果。\n7. 若結算結果不明確，先確認既有授權。\n\n付款識別碼不是密碼或存取權杖。不可向僅知道識別碼的請求回傳付費快取。也請檢查是否被其他使用者或不同請求本文重用。\n\n營運紀錄請一併保留鏈、交易雜湊與日誌位置。將這些紀錄與訂單連結，防止被其他訂單重用。僅有 `Transfer` 相符，無法證明訂單歸屬。\n\n## 付款實作的常見錯誤\n\n混淆版本欄位與成功訊號，會導致付款判定錯誤。請在部署審查時使用下表。版本差異以 [x402 遷移指南](https://docs.x402.org/guides/migration-v1-to-v2)為準。\n\n| 常見錯誤 | 修正依據 |\n|---|---|\n| 將 `extra.version: \"2\"` 解讀為 x402 版本 | 透過 `x402Version` 確認協定版本 |\n| 在 v2 使用 `maxAmountRequired` | 付款條件的金額使用 `amount` |\n| 自行建立 `X-PAYMENT-REQUIRED` 標頭 | v1 使用本文，v2 使用 `PAYMENT-REQUIRED` |\n| 將 `isValid: true` 視為款項已入帳 | 另外確認 `/settle` 結果 |\n| 將交易最上層的 `to` 視為 USDC 收款人 | 確認 USDC `Transfer.to` |\n| 假設簽署者與交易發送者相同 | 比對授權付款人與 `Transfer.from` |\n| 將測試網收款金額計入營收 | 分開主網與測試網帳目 |\n| 每次逾時都建立新付款 | 先復原既有訂單與授權狀態 |\n| 將 SDK 套件版本與協定版本視為相同 | 分別管理套件版本與 `x402Version` |\n\nUSDC 簽章的網域資訊也包含版本字串。該值與 x402 協定版本的用途不同。簽章網域結構請參閱 [ERC-3009 規格](https://eips.ethereum.org/EIPS/eip-3009)。\n\n## 安全檢查與外部服務的信任範圍\n\n請由伺服器控制付款成功的判定。外部 facilitator 的回應也是明確納入信任的對象。[facilitator 文件](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md)說明了也可自行營運的架構。\n\n- 不要依據用戶端的成功訊息開放內容。\n- 請比對伺服器宣告的鏈、代幣、金額與收款人。\n- 不要將私鑰與助記詞寫入日誌。\n- 完整的授權簽章也應排除在一般存取日誌之外。\n- 請限制付款標頭大小與請求處理時間。\n- 請檢查付費回應是否會留在共用快取中。\n- 請分開存放測試金鑰與正式環境金鑰。\n- facilitator 故障時，不要建立免付款的繞過路徑。\n- 請實際測試授權到期與重複請求。\n\n本實作鎖定的相依套件仍有安全檢查警告。`npm audit` 回報了與 zod 相關的安全公告。相關內容請參閱 [GitHub 安全公告](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5)。\n\n```bash\nnpm audit\n```\n\n正式部署前，請確認修正版與 SDK 的相容性。強制更換主要版本可能導致行為改變。不要將本實作當成已完成安全驗證的部署設定。\n\n### 自有伺服器與 Cloudflare Gateway 比較\n\n使用 Cloudflare Gateway 時，來源伺服器的驗證方式會改變。2026年9月30日的文件明確指出使用 x402 v2。下列區分以 [Cloudflare x402 文件](https://developers.cloudflare.com/monetization-gateway/x402/)為準。\n\n| 類別 | 本文的 Express 方式 | Cloudflare Monetization Gateway |\n|---|---|---|\n| 用戶端付款處理 | Express 中介軟體 | Gateway |\n| 來源伺服器的驗證點 | 與所選 facilitator 串接 | 驗證 `PAYMENT-CONTEXT` JWT |\n| 結算結果傳遞 | 中介軟體的 `PAYMENT-RESPONSE` | Gateway 產生結算收據 |\n| 額外確認事項 | facilitator 支援的鏈與身分驗證 | JWT 簽章驗證與來源存取保護 |\n\n`PAYMENT-CONTEXT` 是 Gateway 與來源伺服器之間的標頭，不是一般 x402 用戶端的簽章標頭。來源驗證請遵循 [Cloudflare Payment validation 文件](https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/)。\n\n即使經過 Gateway，也不能只將 JWT 解碼。請使用文件指定的金鑰驗證簽章。若缺少標頭或驗證失敗，就封鎖付費內容。\n\n## 區分實際使用量與結算紀錄\n\n僅憑鏈上轉帳筆數，無法證明內容已被使用。請將結算與回應傳送連結後，再彙整營運指標。這是根據付款流程與重傳行為提出的設計建議。\n\n| 紀錄 | 可回答的問題 | 額外需要的紀錄 |\n|---|---|---|\n| 402 回應 | 付款條件被請求了多少次 | 是否實際付款 |\n| 驗證成功 | 授權是否有效 | 結算結果 |\n| USDC 轉帳 | 資產是否移轉 | 訂單歸屬 |\n| 各訂單結算完成 | 付費請求是否已付款 | 回應傳送狀態 |\n| 重新傳送紀錄 | 是否復原了已付款的請求 | 與新付款區分的識別碼 |\n\n請在實際使用量統計中區分測試請求。同一訂單的重試也應另外標示。不可將交易量本身解釋為 API 需求或收益保證。\n\n## Base 主網切換步驟\n\n確認測試網的正常與失敗路徑後，再評估主網。切換並非只要更改網路字串就完成。標準步驟遵循[官方賣方指南](https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet)。\n\n1. 確認所選 facilitator 支援 Base 主網。\n2. 在 `/supported` 確認支援 v2、`exact`、`eip155:8453`。\n3. 設定提供者要求的身分驗證與使用條件。\n4. 同時更改伺服器與用戶端的網路。\n5. 將用戶端允許的 USDC 地址改為主網地址。\n6. 再次比對 402 回應的金額與實際收款地址。\n7. 接上重複請求儲存機制與故障復原程序。\n8. 完成正式環境相依套件的安全檢查。\n9. 以設定的小額款項確認實際轉帳與內容傳送。\n\n支援多鏈不代表支援所有組合。請同時確認 SDK 與 facilitator 的支援範圍。確認依據為[網路與代幣支援文件](https://docs.x402.org/core-concepts/network-and-token-support)。","content_html":"\u003cp\u003ex402 付款透過在 API 的 402 回應中包含付款條件來實作。請準備 Node.js 和測試錢包。先在 Base Sepolia 驗證 v2 簽章與結算。請設定為結算成功後才傳送付費回應。\u003c/p\u003e\n\u003cp\u003e金額與鏈資訊以來源連結中的 x402、Base、Circle 官方文件為準。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E5%AF%A6%E4%BD%9C%E6%BA%96%E5%82%99%E8%88%87%E5%AE%89%E8%A3%9D\" class=\"anchor\" id=\"實作準備與安裝\"\u003e\u003c/a\u003e實作準備與安裝\u003c/h2\u003e\n\u003cp\u003e請準備可修改 API 的開發環境及測試錢包。範例以 Node.js 22 和 x402 SDK 2.28.0 為基礎。安裝結構遵循\u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-sellers\"\u003e官方賣方指南\u003c/a\u003e。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e準備接收付款的 EVM 錢包地址。\u003c/li\u003e\n\u003cli\u003e另外準備付款用的測試錢包。\u003c/li\u003e\n\u003cli\u003e在付款錢包中取得 Base Sepolia 測試 USDC。\u003c/li\u003e\n\u003cli\u003e使用下列指令建立實作專案。\u003c/li\u003e\n\u003cli\u003e將後續的 TypeScript 檔案儲存在同一個資料夾中。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003emkdir\u003c/span\u003e\u003cspan\u003e x402-demo\n\u003c/span\u003e\u003cspan\u003ecd\u003c/span\u003e\u003cspan\u003e x402-demo\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e init\u003c/span\u003e\u003cspan\u003e -y\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e pkg set type=module\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e install\u003c/span\u003e\u003cspan\u003e --save-exact\u003c/span\u003e\u003cspan\u003e 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\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e install\u003c/span\u003e\u003cspan\u003e --save-dev --save-exact\u003c/span\u003e\u003cspan\u003e typescript tsx @types/node @types/express\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e收款伺服器不需要收款錢包的私鑰。請設定為僅由用戶端程序讀取付款私鑰。錢包簽章方式以\u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-buyers\"\u003e官方買方指南\u003c/a\u003e為準。\u003c/p\u003e\n\u003cp\u003e本範例的驗證範圍為型別檢查與模擬付款流程，並未完成實際測試網轉帳。請在下方執行步驟中自行確認鏈上結果。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#x402-v1-%E8%88%87-v2-%E6%AF%94%E8%BC%83\" class=\"anchor\" id=\"x402-v1-與-v2-比較\"\u003e\u003c/a\u003ex402 v1 與 v2 比較\u003c/h2\u003e\n\u003cp\u003e實作 v2 時，必須同時配合標頭和本文欄位。只更改標頭名稱，資料結構仍會不符。下表以\u003ca href=\"https://docs.x402.org/guides/migration-v1-to-v2\"\u003e官方遷移指南\u003c/a\u003e為準。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e類別\u003c/th\u003e\n\u003cth\u003ev1\u003c/th\u003e\n\u003cth\u003ev2\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e協定版本\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ex402Version: 1\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003ex402Version: 2\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e初始付款條件\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e402 回應的 JSON 本文\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\n\u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e 回應標頭\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e已簽署的付款資料\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\n\u003ccode\u003eX-PAYMENT\u003c/code\u003e 請求標頭\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\n\u003ccode\u003ePAYMENT-SIGNATURE\u003c/code\u003e 請求標頭\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e結算結果\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\n\u003ccode\u003eX-PAYMENT-RESPONSE\u003c/code\u003e 回應標頭\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\n\u003ccode\u003ePAYMENT-RESPONSE\u003c/code\u003e 回應標頭\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003eBase 主網識別碼\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ebase\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003eeip155:8453\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003eBase Sepolia 識別碼\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ebase-sepolia\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003eeip155:84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e付款條件的金額欄位\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003emaxAmountRequired\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003eamount\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e資源描述\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e付款條件內的 \u003ccode\u003eresource\u003c/code\u003e 等\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e最上層的 \u003ccode\u003eresource\u003c/code\u003e 物件\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e付款酬載中的條件\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e最上層的 \u003ccode\u003escheme\u003c/code\u003e、\u003ccode\u003enetwork\u003c/code\u003e 等\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e包含所選條件的 \u003ccode\u003eaccepted\u003c/code\u003e 物件\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003eTypeScript 套件範例\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ex402-express\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003e@x402/express\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003ev1 付款條件的傳遞位置已載明於 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md\"\u003eHTTP v1 規格\u003c/a\u003e。v2 的標準傳遞位置是 \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e 標頭。實作也可能回傳本文，但請以標頭為準進行處理。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md\"\u003eHTTP v2 規格\u003c/a\u003e對狀態碼的說明如下。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e伺服器使用 HTTP 402「需要付款」狀態碼表示需要付款。\u003c/p\u003e\n\u003cp\u003e來源：x402 HTTP v2 規格\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003ev2 付款標頭是將 JSON 以 Base64 編碼後的值。Base64 並非加密方式。對外服務請使用 HTTPS。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#http-402-%E8%AB%8B%E6%B1%82%E8%88%87%E4%BB%98%E6%AC%BE%E9%A0%86%E5%BA%8F\" class=\"anchor\" id=\"http-402-請求與付款順序\"\u003e\u003c/a\u003eHTTP 402 請求與付款順序\u003c/h2\u003e\n\u003cp\u003e本實作使用 EVM \u003ccode\u003eexact\u003c/code\u003e 方式的基本授權流程。\u003ccode\u003eexact\u003c/code\u003e 是支付指定金額的方式。順序遵循 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md\"\u003ex402 v2 核心規格\u003c/a\u003e。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e用戶端在不附帶付款資訊的情況下請求付費 API。\u003c/li\u003e\n\u003cli\u003e伺服器回傳 HTTP 402 和 \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e用戶端從 \u003ccode\u003eaccepts\u003c/code\u003e 中選擇允許的條件。\u003c/li\u003e\n\u003cli\u003eSDK 簽署符合所選條件的付款授權。\u003c/li\u003e\n\u003cli\u003e用戶端附上 \u003ccode\u003ePAYMENT-SIGNATURE\u003c/code\u003e 再次發送請求。\u003c/li\u003e\n\u003cli\u003e伺服器透過 facilitator 的 \u003ccode\u003e/verify\u003c/code\u003e 驗證授權。\u003c/li\u003e\n\u003cli\u003e驗證通過後，伺服器執行資源處理。\u003c/li\u003e\n\u003cli\u003e伺服器透過 \u003ccode\u003e/settle\u003c/code\u003e 請求結算。\u003c/li\u003e\n\u003cli\u003e結算成功後，傳送付費本文和 \u003ccode\u003ePAYMENT-RESPONSE\u003c/code\u003e。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e這個順序並非所有付款方式共用的固定順序。v2 也定義了結算時機不同的流程。下方程式碼僅允許基本的 \u003ccode\u003eauthorization\u003c/code\u003e 流程。\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#resource-server-%E8%88%87-facilitator-%E7%9A%84%E8%A7%92%E8%89%B2\" class=\"anchor\" id=\"resource-server-與-facilitator-的角色\"\u003e\u003c/a\u003eResource server 與 facilitator 的角色\u003c/h3\u003e\n\u003cp\u003eResource server 決定價格與內容存取條件。Facilitator 負責付款驗證與結算。角色劃分以\u003ca href=\"https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md\"\u003e官方 facilitator 文件\u003c/a\u003e為準。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e元件\u003c/th\u003e\n\u003cth\u003e負責工作\u003c/th\u003e\n\u003cth\u003e不應視為成功的狀態\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"元件\"\u003e用戶端\u003c/td\u003e\n\u003ctd data-label=\"負責工作\"\u003e選擇條件並簽署付款授權\u003c/td\u003e\n\u003ctd data-label=\"不應視為成功的狀態\"\u003e僅完成簽章產生\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"元件\"\u003eResource server\u003c/td\u003e\n\u003ctd data-label=\"負責工作\"\u003e宣告價格並控管付費回應\u003c/td\u003e\n\u003ctd data-label=\"不應視為成功的狀態\"\u003e用戶端聲稱成功\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"元件\"\u003eFacilitator \u003ccode\u003e/verify\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"負責工作\"\u003e確認簽章與付款條件的有效性\u003c/td\u003e\n\u003ctd data-label=\"不應視為成功的狀態\"\u003e僅收到 \u003ccode\u003eisValid: true\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"元件\"\u003eFacilitator \u003ccode\u003e/settle\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"負責工作\"\u003e在本實作中執行鏈上付款並回傳結果\u003c/td\u003e\n\u003ctd data-label=\"不應視為成功的狀態\"\u003e已送出但尚未確認結果\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003e/verify\u003c/code\u003e 是不會改變鏈上狀態的檢查。因此，驗證成功不代表款項已入帳。驗證後，餘額或授權狀態仍可能改變。\u003c/p\u003e\n\u003cp\u003e驗證或結算失敗時，請封鎖付費本文。無法確認成功時就封鎖的處理方式稱為 fail-closed。在\u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts\"\u003e官方 Express 實作\u003c/a\u003e中也能確認這項行為。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#base-%E4%B8%BB%E7%B6%B2%E8%88%87%E6%B8%AC%E8%A9%A6%E7%B6%B2%E6%AF%94%E8%BC%83\" class=\"anchor\" id=\"base-主網與測試網比較\"\u003e\u003c/a\u003eBase 主網與測試網比較\u003c/h2\u003e\n\u003cp\u003e首次執行時，請僅使用 Base Sepolia。Circle 明確指出，測試網 USDC 不具有金融價值。地址以 \u003ca href=\"https://developers.circle.com/stablecoins/usdc-contract-addresses\"\u003eCircle 的 USDC 合約清單\u003c/a\u003e為準。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e項目\u003c/th\u003e\n\u003cth\u003eBase 主網\u003c/th\u003e\n\u003cth\u003eBase Sepolia 測試網\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"項目\"\u003e用途\u003c/td\u003e\n\u003ctd data-label=\"Base 主網\"\u003e實際資產付款\u003c/td\u003e\n\u003ctd data-label=\"Base Sepolia 測試網\"\u003e測試實作與故障處理\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"項目\"\u003eChain ID\u003c/td\u003e\n\u003ctd data-label=\"Base 主網\"\u003e\u003ccode\u003e8453\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Base Sepolia 測試網\"\u003e\u003ccode\u003e84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"項目\"\u003ex402 v2 網路\u003c/td\u003e\n\u003ctd data-label=\"Base 主網\"\u003e\u003ccode\u003eeip155:8453\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Base Sepolia 測試網\"\u003e\u003ccode\u003eeip155:84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"項目\"\u003eUSDC 合約\u003c/td\u003e\n\u003ctd data-label=\"Base 主網\"\u003e\u003ccode\u003e0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Base Sepolia 測試網\"\u003e\u003ccode\u003e0x036CbD53842c5426634e7929541eC2318f3dCF7e\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"項目\"\u003e公開 RPC\u003c/td\u003e\n\u003ctd data-label=\"Base 主網\"\u003e\u003ccode\u003ehttps://mainnet.base.org\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Base Sepolia 測試網\"\u003e\u003ccode\u003ehttps://sepolia.base.org\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"項目\"\u003e代幣的金融價值\u003c/td\u003e\n\u003ctd data-label=\"Base 主網\"\u003e具有實際金融價值的資產\u003c/td\u003e\n\u003ctd data-label=\"Base Sepolia 測試網\"\u003e無金融價值\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e請在 \u003ca href=\"https://docs.base.org/get-started/connect-to-base\"\u003eBase 網路文件\u003c/a\u003e中確認 Chain ID 和 RPC。即使錢包地址相同，只要鏈不同，餘額就是分開的。不可將測試網成功付款記錄為實際營收。\u003c/p\u003e\n\u003cp\u003e測試 USDC 可向 \u003ca href=\"https://faucet.circle.com/\"\u003eCircle Testnet Faucet\u003c/a\u003e 申請。網路請選擇 Base Sepolia，接收地址請填入付款用的測試錢包地址。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#nodejs-%E4%BB%98%E8%B2%BB-api-%E5%AF%A6%E4%BD%9C\" class=\"anchor\" id=\"nodejs-付費-api-實作\"\u003e\u003c/a\u003eNode.js 付費 API 實作\u003c/h2\u003e\n\u003cp\u003e請在付費路由前掛上 \u003ccode\u003epaymentMiddleware\u003c/code\u003e。下方範例要求每次呼叫支付 \u003cstrong\u003e0.001 USDC\u003c/strong\u003e。金額採用官方賣方指南的範例價格。（確認值為每次呼叫 0.001 USDC · 來源 docs.x402.org · 2026-10-28 確認）\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#%E4%BC%BA%E6%9C%8D%E5%99%A8%E6%AA%94%E6%A1%88\" class=\"anchor\" id=\"伺服器檔案\"\u003e\u003c/a\u003e伺服器檔案\u003c/h3\u003e\n\u003cp\u003e請將下列程式碼儲存為 \u003ccode\u003eserver.ts\u003c/code\u003e。伺服器僅在本機介面接收請求。收款地址從 \u003ccode\u003ePAY_TO\u003c/code\u003e 環境變數讀取。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eimport express from \"express\";\n\u003c/span\u003e\u003cspan\u003eimport { getAddress, zeroAddress } from \"viem\";\n\u003c/span\u003e\u003cspan\u003eimport { paymentMiddleware } from \"@x402/express\";\n\u003c/span\u003e\u003cspan\u003eimport { HTTPFacilitatorClient, x402ResourceServer } from \"@x402/core/server\";\n\u003c/span\u003e\u003cspan\u003eimport { ExactEvmScheme } from \"@x402/evm/exact/server\";\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst payTo = getAddress(process.env.PAY_TO ?? \"\");\n\u003c/span\u003e\u003cspan\u003eif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\n\u003c/span\u003e\u003cspan\u003econst network = \"eip155:84532\";\n\u003c/span\u003e\u003cspan\u003econst resourceServer = new x402ResourceServer(\n\u003c/span\u003e\u003cspan\u003e  new HTTPFacilitatorClient({ url: \"https://x402.org/facilitator\" }),\n\u003c/span\u003e\u003cspan\u003e).register(network, new ExactEvmScheme());\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst app = express();\n\u003c/span\u003e\u003cspan\u003eapp.use((_req, res, next) =\u0026gt; {\n\u003c/span\u003e\u003cspan\u003e  res.setHeader(\"Cache-Control\", \"private, no-store\");\n\u003c/span\u003e\u003cspan\u003e  next();\n\u003c/span\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003cspan\u003eapp.use(paymentMiddleware({\n\u003c/span\u003e\u003cspan\u003e  \"GET /paid-data\": {\n\u003c/span\u003e\u003cspan\u003e    accepts: [{ scheme: \"exact\", price: \"$0.001\", network, payTo }],\n\u003c/span\u003e\u003cspan\u003e    description: \"Sample paid JSON\",\n\u003c/span\u003e\u003cspan\u003e    mimeType: \"application/json\",\n\u003c/span\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003cspan\u003e}, resourceServer));\n\u003c/span\u003e\u003cspan\u003eapp.get(\"/paid-data\", (_req, res) =\u0026gt; {\n\u003c/span\u003e\u003cspan\u003e  res.json({ content: \"Paid sample content\" });\n\u003c/span\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003cspan\u003eapp.listen(4021, \"127.0.0.1\");\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ehttps://x402.org/facilitator\u003c/code\u003e 是官方指南中的測試用地址。本範例將其用於 Base Sepolia 結算。正式環境的 facilitator 選擇方式，請參閱\u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet\"\u003e賣方指南的主網步驟\u003c/a\u003e。\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#%E5%83%B9%E6%A0%BC%E8%A8%88%E7%AE%97%E7%AF%84%E4%BE%8B\" class=\"anchor\" id=\"價格計算範例\"\u003e\u003c/a\u003e價格計算範例\u003c/h3\u003e\n\u003cp\u003e範例價格換算為 USDC 最小單位是 \u003ccode\u003e1000\u003c/code\u003e。USDC 的小數位數為 6 位。SDK 的價格轉換以 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts\"\u003eEVM 伺服器實作\u003c/a\u003e為準。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003e0.001 USDC × 10^6 = 1000 최소 단위\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e要確認的值\u003c/th\u003e\n\u003cth\u003e本範例的預期值\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"要確認的值\"\u003e伺服器設定中的 \u003ccode\u003eprice\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"本範例的預期值\"\u003e\u003ccode\u003e\"$0.001\"\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"要確認的值\"\u003e402 付款條件中的 \u003ccode\u003eamount\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"本範例的預期值\"\u003e\u003ccode\u003e\"1000\"\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"要確認的值\"\u003e付款條件中的 \u003ccode\u003easset\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"本範例的預期值\"\u003eBase Sepolia USDC 合約\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"要確認的值\"\u003e付款條件中的 \u003ccode\u003epayTo\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"本範例的預期值\"\u003e設定的收款地址\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"要確認的值\"\u003e付款條件中的 \u003ccode\u003enetwork\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"本範例的預期值\"\u003e\u003ccode\u003eeip155:84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003eprice\u003c/code\u003e 是 SDK 設定值。實際 v2 付款條件傳遞的是 \u003ccode\u003eamount\u003c/code\u003e。請以字串或 \u003ccode\u003ebigint\u003c/code\u003e 比較整數金額。\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#%E5%9F%B7%E8%A1%8C%E4%BC%BA%E6%9C%8D%E5%99%A8%E4%B8%A6%E7%A2%BA%E8%AA%8D-402\" class=\"anchor\" id=\"執行伺服器並確認-402\"\u003e\u003c/a\u003e執行伺服器並確認 402\u003c/h3\u003e\n\u003cp\u003e請在第一個 Bash 終端機中執行伺服器。輸入的值是公開收款地址，而非私鑰。執行期間請保持此終端機開啟。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eread \u003c/span\u003e\u003cspan\u003e-r -p \u003c/span\u003e\u003cspan\u003e'\u003c/span\u003e\u003cspan\u003e수취 지갑 주소: \u003c/span\u003e\u003cspan\u003e' PAY_TO\n\u003c/span\u003e\u003cspan\u003eexport \u003c/span\u003e\u003cspan\u003ePAY_TO\n\u003c/span\u003e\u003cspan\u003enpx\u003c/span\u003e\u003cspan\u003e tsx server.ts\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e請在第二個終端機發送未付款請求。下列指令不會簽署付款，只會輸出 HTTP 狀態與解碼後的付款條件。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003enode\u003c/span\u003e\u003cspan\u003e --input-type\u003c/span\u003e\u003cspan\u003e=module \u0026lt;\u0026lt;'\u003c/span\u003e\u003cspan\u003eJS\u003c/span\u003e\u003cspan\u003e'\n\u003c/span\u003e\u003cspan\u003econst response = await fetch(\"http://127.0.0.1:4021/paid-data\");\n\u003c/span\u003e\u003cspan\u003econst header = response.headers.get(\"PAYMENT-REQUIRED\");\n\u003c/span\u003e\u003cspan\u003econsole.log(response.status);\n\u003c/span\u003e\u003cspan\u003econsole.log(header \u0026amp;\u0026amp; JSON.parse(\n\u003c/span\u003e\u003cspan\u003e  Buffer.from(header, \"base64\").toString(\"utf8\")\n\u003c/span\u003e\u003cspan\u003e));\n\u003c/span\u003e\u003cspan\u003eJS\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e正常的未付款回應是 HTTP 402。請將輸出的條件與上表比對。如果直接回傳付費內容，請先修正路由保護設定。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E4%BB%98%E6%AC%BE%E6%A2%9D%E4%BB%B6%E9%81%B8%E6%93%87%E8%88%87%E7%94%A8%E6%88%B6%E7%AB%AF%E5%AF%A6%E4%BD%9C\" class=\"anchor\" id=\"付款條件選擇與用戶端實作\"\u003e\u003c/a\u003e付款條件選擇與用戶端實作\u003c/h2\u003e\n\u003cp\u003e請限制用戶端僅簽署允許的條件。本範例僅允許 Base Sepolia USDC 的指定價格。付款選項篩選使用\u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts\"\u003e官方 x402Client 實作\u003c/a\u003e中的 \u003ccode\u003eregisterPolicy\u003c/code\u003e。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e將下列程式碼儲存為 \u003ccode\u003eclient.ts\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e也將下一節的 \u003ccode\u003echeck-transfer.ts\u003c/code\u003e 儲存下來。\u003c/li\u003e\n\u003cli\u003e準備好兩個檔案後，再進行執行步驟。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eimport { writeFile } from \"node:fs/promises\";\n\u003c/span\u003e\u003cspan\u003eimport { getAddress, zeroAddress, type Hex, type Hash } from \"viem\";\n\u003c/span\u003e\u003cspan\u003eimport { privateKeyToAccount } from \"viem/accounts\";\n\u003c/span\u003e\u003cspan\u003eimport { x402Client, wrapFetchWithPayment } from \"@x402/fetch\";\n\u003c/span\u003e\u003cspan\u003eimport { decodePaymentResponseHeader } from \"@x402/core/http\";\n\u003c/span\u003e\u003cspan\u003eimport { ExactEvmScheme } from \"@x402/evm/exact/client\";\n\u003c/span\u003e\u003cspan\u003eimport { checkTransfer } from \"./check-transfer.js\";\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst key = process.env.EVM_PRIVATE_KEY ?? \"\";\n\u003c/span\u003e\u003cspan\u003eif (!/^0x[0-9a-fA-F]{64}$/.test(key)) throw new Error(\"Invalid test key\");\n\u003c/span\u003e\u003cspan\u003econst signer = privateKeyToAccount(key as Hex);\n\u003c/span\u003e\u003cspan\u003econst payTo = getAddress(process.env.PAY_TO ?? \"\");\n\u003c/span\u003e\u003cspan\u003eif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\n\u003c/span\u003e\u003cspan\u003econst network = \"eip155:84532\";\n\u003c/span\u003e\u003cspan\u003econst token = \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\";\n\u003c/span\u003e\u003cspan\u003econst client = new x402Client().register(network, new ExactEvmScheme(signer));\n\u003c/span\u003e\u003cspan\u003eclient.registerPolicy((version, options) =\u0026gt; version === 2\n\u003c/span\u003e\u003cspan\u003e  ? options.filter(r =\u0026gt;\n\u003c/span\u003e\u003cspan\u003e      r.scheme === \"exact\" \u0026amp;\u0026amp; r.network === network \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      r.asset.toLowerCase() === token.toLowerCase() \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      r.payTo.toLowerCase() === payTo.toLowerCase() \u0026amp;\u0026amp; r.amount === \"1000\" \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      (!r.extra?.assetTransferMethod || r.extra.assetTransferMethod === \"eip3009\") \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      (!r.extra?.paymentFlow || r.extra.paymentFlow === \"authorization\"))\n\u003c/span\u003e\u003cspan\u003e  : []);\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst paidFetch = wrapFetchWithPayment(fetch, client);\n\u003c/span\u003e\u003cspan\u003econst response = await paidFetch(\"http://127.0.0.1:4021/paid-data\", {\n\u003c/span\u003e\u003cspan\u003e  redirect: \"error\",\n\u003c/span\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003cspan\u003econst raw = response.headers.get(\"PAYMENT-RESPONSE\");\n\u003c/span\u003e\u003cspan\u003eif (!raw) throw new Error(`No settlement receipt: HTTP ${response.status}`);\n\u003c/span\u003e\u003cspan\u003econst settlement = decodePaymentResponseHeader(raw);\n\u003c/span\u003e\u003cspan\u003eawait writeFile(\"settlement.json\", JSON.stringify(settlement, null, 2));\n\u003c/span\u003e\u003cspan\u003eif (!response.ok || !settlement.success || settlement.network !== network) {\n\u003c/span\u003e\u003cspan\u003e  throw new Error(\"Payment unresolved; inspect settlement.json before retrying\");\n\u003c/span\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003cspan\u003econst evidence = await checkTransfer(\n\u003c/span\u003e\u003cspan\u003e  network, settlement.transaction as Hash, signer.address, payTo, 1000n,\n\u003c/span\u003e\u003cspan\u003e);\n\u003c/span\u003e\u003cspan\u003eawait writeFile(\"transfer.json\", JSON.stringify(evidence, null, 2));\n\u003c/span\u003e\u003cspan\u003econsole.log(await response.text());\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ewrapFetchWithPayment\u003c/code\u003e 負責處理 402 及附上簽章重新請求。使用方式遵循\u003ca href=\"https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch\"\u003e官方 fetch 範例\u003c/a\u003e。若沒有允許的付款條件，就會停止建立付款。\u003c/p\u003e\n\u003cp\u003eAI 代理也可使用這個用戶端。不過，每次呼叫的價格上限不等於累計支出上限。請另外管理代理重複呼叫的預算。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#usdc-transfer-%E4%BA%8B%E4%BB%B6%E9%A9%97%E8%AD%89\" class=\"anchor\" id=\"usdc-transfer-事件驗證\"\u003e\u003c/a\u003eUSDC Transfer 事件驗證\u003c/h2\u003e\n\u003cp\u003e請使用結算結果中的交易雜湊，確認 USDC 轉帳日誌。僅憑交易成功狀態，無法確認收款人。\u003ccode\u003eTransfer\u003c/code\u003e 欄位以 \u003ca href=\"https://eips.ethereum.org/EIPS/eip-20\"\u003eERC-20 標準\u003c/a\u003e為準。\u003c/p\u003e\n\u003cp\u003e驗證需要下列項目。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e驗證項目\u003c/th\u003e\n\u003cth\u003e比對對象\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"驗證項目\"\u003eRPC 的 Chain ID\u003c/td\u003e\n\u003ctd data-label=\"比對對象\"\u003e伺服器允許的鏈\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"驗證項目\"\u003e交易收據的 \u003ccode\u003estatus\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"比對對象\"\u003e成功狀態\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"驗證項目\"\u003e發出事件的地址\u003c/td\u003e\n\u003ctd data-label=\"比對對象\"\u003e該鏈的官方 USDC 合約\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"驗證項目\"\u003e\u003ccode\u003eTransfer.from\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"比對對象\"\u003e已確認的付款人\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"驗證項目\"\u003e\u003ccode\u003eTransfer.to\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"比對對象\"\u003e伺服器指定的收款地址\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"驗證項目\"\u003e\u003ccode\u003eTransfer.value\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"比對對象\"\u003e伺服器要求的最小單位金額\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e請將下列程式碼儲存為 \u003ccode\u003echeck-transfer.ts\u003c/code\u003e。查詢使用 viem 的 \u003ca href=\"https://viem.sh/docs/actions/public/getTransactionReceipt\"\u003egetTransactionReceipt\u003c/a\u003e。事件解析以 \u003ca href=\"https://viem.sh/docs/contract/parseEventLogs\"\u003eparseEventLogs\u003c/a\u003e 為準。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eimport {\n\u003c/span\u003e\u003cspan\u003e  createPublicClient, http, getAddress, parseEventLogs,\n\u003c/span\u003e\u003cspan\u003e  erc20Abi, type Address, type Hash,\n\u003c/span\u003e\u003cspan\u003e} from \"viem\";\n\u003c/span\u003e\u003cspan\u003eimport { base, baseSepolia } from \"viem/chains\";\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst configs = {\n\u003c/span\u003e\u003cspan\u003e  \"eip155:84532\": {\n\u003c/span\u003e\u003cspan\u003e    chain: baseSepolia,\n\u003c/span\u003e\u003cspan\u003e    rpc: \"https://sepolia.base.org\",\n\u003c/span\u003e\u003cspan\u003e    token: \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\",\n\u003c/span\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003cspan\u003e  \"eip155:8453\": {\n\u003c/span\u003e\u003cspan\u003e    chain: base,\n\u003c/span\u003e\u003cspan\u003e    rpc: \"https://mainnet.base.org\",\n\u003c/span\u003e\u003cspan\u003e    token: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n\u003c/span\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003cspan\u003e} as const;\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003eexport async function checkTransfer(\n\u003c/span\u003e\u003cspan\u003e  network: keyof typeof configs, hash: Hash,\n\u003c/span\u003e\u003cspan\u003e  payer: Address, payTo: Address, amount: bigint,\n\u003c/span\u003e\u003cspan\u003e) {\n\u003c/span\u003e\u003cspan\u003e  const cfg = configs[network];\n\u003c/span\u003e\u003cspan\u003e  const rpc = createPublicClient({ chain: cfg.chain, transport: http(cfg.rpc) });\n\u003c/span\u003e\u003cspan\u003e  if (await rpc.getChainId() !== cfg.chain.id) throw new Error(\"Wrong chain\");\n\u003c/span\u003e\u003cspan\u003e  const receipt = await rpc.getTransactionReceipt({ hash });\n\u003c/span\u003e\u003cspan\u003e  if (receipt.status !== \"success\") throw new Error(\"Transaction failed\");\n\u003c/span\u003e\u003cspan\u003e  const logs = parseEventLogs({\n\u003c/span\u003e\u003cspan\u003e    abi: erc20Abi,\n\u003c/span\u003e\u003cspan\u003e    eventName: \"Transfer\",\n\u003c/span\u003e\u003cspan\u003e    logs: receipt.logs.filter(\n\u003c/span\u003e\u003cspan\u003e      log =\u0026gt; getAddress(log.address) === getAddress(cfg.token),\n\u003c/span\u003e\u003cspan\u003e    ),\n\u003c/span\u003e\u003cspan\u003e    strict: true,\n\u003c/span\u003e\u003cspan\u003e  });\n\u003c/span\u003e\u003cspan\u003e  const transfer = logs.find(log =\u0026gt;\n\u003c/span\u003e\u003cspan\u003e    getAddress(log.args.from) === getAddress(payer) \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e    getAddress(log.args.to) === getAddress(payTo) \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e    log.args.value === amount,\n\u003c/span\u003e\u003cspan\u003e  );\n\u003c/span\u003e\u003cspan\u003e  if (!transfer) throw new Error(\"Matching USDC Transfer not found\");\n\u003c/span\u003e\u003cspan\u003e  return {\n\u003c/span\u003e\u003cspan\u003e    network, transaction: hash, logIndex: transfer.logIndex,\n\u003c/span\u003e\u003cspan\u003e    blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),\n\u003c/span\u003e\u003cspan\u003e  };\n\u003c/span\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e此函式確認該筆交易確實發生 USDC 轉帳。是否歸屬於特定 API 訂單，仍須另外確認。正式環境的伺服器請使用已儲存的訂單條件作為比對值。\u003c/p\u003e\n\u003cp\u003e不可將用戶端上傳的 \u003ccode\u003etransfer.json\u003c/code\u003e 視為授予存取權的可信憑證。本範例的伺服器使用 facilitator 的驗證與結算結果。若要將獨立查詢作為授予存取權的條件，必須在伺服器端執行。\u003c/p\u003e\n\u003cp\u003e收據查詢失敗不代表付款失敗。如果是 RPC 錯誤，請使用已儲存的交易雜湊重新查詢。額外確認數與鏈重組的應對方式，應由營運政策決定。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E5%9F%B7%E8%A1%8C%E6%B8%AC%E8%A9%A6%E4%BB%98%E6%AC%BE%E8%88%87%E7%A2%BA%E8%AA%8D%E7%B5%90%E6%9E%9C\" class=\"anchor\" id=\"執行測試付款與確認結果\"\u003e\u003c/a\u003e執行測試付款與確認結果\u003c/h2\u003e\n\u003cp\u003e儲存所有檔案後，請使用測試錢包執行。型別檢查不會進行簽章或轉帳。下列指令使用先前安裝的 TypeScript 工具。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e使用下列指令檢查型別。\u003c/li\u003e\n\u003cli\u003e在第二個終端機輸入與伺服器相同的收款地址。\u003c/li\u003e\n\u003cli\u003e以隱藏輸入方式輸入測試付款錢包的私鑰。\u003c/li\u003e\n\u003cli\u003e執行用戶端一次。\u003c/li\u003e\n\u003cli\u003e確認儲存的結算結果與轉帳日誌。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003enpx\u003c/span\u003e\u003cspan\u003e tsc\u003c/span\u003e\u003cspan\u003e --noEmit --strict --skipLibCheck --target\u003c/span\u003e\u003cspan\u003e ES2022\u003c/span\u003e\u003cspan\u003e --module\u003c/span\u003e\u003cspan\u003e NodeNext\u003c/span\u003e\u003cspan\u003e --moduleResolution\u003c/span\u003e\u003cspan\u003e NodeNext server.ts client.ts check-transfer.ts\n\u003c/span\u003e\u003cspan\u003eread \u003c/span\u003e\u003cspan\u003e-r -p \u003c/span\u003e\u003cspan\u003e'\u003c/span\u003e\u003cspan\u003e같은 수취 지갑 주소: \u003c/span\u003e\u003cspan\u003e' PAY_TO\n\u003c/span\u003e\u003cspan\u003eread \u003c/span\u003e\u003cspan\u003e-r -s -p \u003c/span\u003e\u003cspan\u003e'\u003c/span\u003e\u003cspan\u003e테스트 결제 지갑 개인키: \u003c/span\u003e\u003cspan\u003e' EVM_PRIVATE_KEY\n\u003c/span\u003e\u003cspan\u003eexport \u003c/span\u003e\u003cspan\u003ePAY_TO EVM_PRIVATE_KEY\n\u003c/span\u003e\u003cspan\u003enpx\u003c/span\u003e\u003cspan\u003e tsx client.ts\n\u003c/span\u003e\u003cspan\u003eunset\u003c/span\u003e\u003cspan\u003e EVM_PRIVATE_KEY\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e輸出結果\u003c/th\u003e\n\u003cth\u003e意義\u003c/th\u003e\n\u003cth\u003e要確認的內容\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"輸出結果\"\u003e\u003ccode\u003esettlement.json\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"意義\"\u003e伺服器回傳的結算結果\u003c/td\u003e\n\u003ctd data-label=\"要確認的內容\"\u003e\n\u003ccode\u003esuccess\u003c/code\u003e、\u003ccode\u003enetwork\u003c/code\u003e、\u003ccode\u003etransaction\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"輸出結果\"\u003e\u003ccode\u003etransfer.json\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"意義\"\u003eRPC 查詢找到的轉帳紀錄\u003c/td\u003e\n\u003ctd data-label=\"要確認的內容\"\u003e鏈、交易雜湊、日誌位置、區塊資訊\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"輸出結果\"\u003e主控台中的付費本文\u003c/td\u003e\n\u003ctd data-label=\"意義\"\u003e此用戶端驗證後輸出的資料\u003c/td\u003e\n\u003ctd data-label=\"要確認的內容\"\u003e確認是否為請求的內容\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e重新執行用戶端可能產生新的付款。此最小範例沒有防止訂單重複處理的儲存機制。請在具備下一節的條件後，再加入重試功能。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E5%90%84%E7%A8%AE%E9%A9%97%E8%AD%89%E5%A4%B1%E6%95%97%E6%A2%9D%E4%BB%B6%E7%9A%84%E8%99%95%E7%90%86\" class=\"anchor\" id=\"各種驗證失敗條件的處理\"\u003e\u003c/a\u003e各種驗證失敗條件的處理\u003c/h2\u003e\n\u003cp\u003e進行失敗測試時，請確認付費本文不會外洩。若只檢查 HTTP 狀態，可能漏掉未封鎖的情況。基準行為請參考\u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts\"\u003e官方 Express 中介軟體\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e測試條件\u003c/th\u003e\n\u003cth\u003e預期處理\u003c/th\u003e\n\u003cth\u003e額外確認\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003e無付款標頭\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e回傳 402 與付款條件\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e無付費本文\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003e提供其他代幣或收款人\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e由用戶端政策拒絕\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e不產生簽章\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003e錯誤簽章\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e因驗證失敗而封鎖\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e不執行付費處理函式\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003e餘額不足\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e因驗證或結算失敗而封鎖\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e不記錄為結算成功\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003e結算結果失敗\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e封鎖付費回應\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e已準備好的本文也不傳送\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003efacilitator 回應延遲\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e因尚未確認成功而維持待處理\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e禁止自動產生新授權\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"測試條件\"\u003eRPC 收據查詢錯誤\u003c/td\u003e\n\u003ctd data-label=\"預期處理\"\u003e保留交易雜湊並重新查詢\u003c/td\u003e\n\u003ctd data-label=\"額外確認\"\u003e不可斷定付款失敗\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e基本授權流程會在結算前執行處理函式。結算失敗不會一併復原外部操作。請像本範例一樣，先從沒有副作用的查詢開始套用。\u003c/p\u003e\n\u003cp\u003e寄送電子郵件或建立外部訂單需要另外設計。請一併記錄付款與作業狀態。必須界定失敗時重新執行的範圍，才能減少重複作業。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E7%B5%90%E7%AE%97%E5%BE%8C%E5%9B%9E%E6%87%89%E9%81%BA%E5%A4%B1%E8%88%87%E9%87%8D%E5%82%B3%E5%BE%A9%E5%8E%9F\" class=\"anchor\" id=\"結算後回應遺失與重傳復原\"\u003e\u003c/a\u003e結算後回應遺失與重傳復原\u003c/h2\u003e\n\u003cp\u003e請將付款完成與內容傳送完成儲存為不同狀態。付款可能已完成，但回應連線卻中斷。處理這類情況的依據是 \u003ca href=\"https://docs.x402.org/extensions/payment-identifier\"\u003ePayment-Identifier 擴充文件\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e再次請求同一項作業也不會重複處理的性質，稱為冪等性。\u003ccode\u003epayment-identifier\u003c/code\u003e 為此提供付款識別碼。這項功能並非只要加入識別碼就會自動完成。\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#%E9%87%8D%E8%A4%87%E4%BB%98%E6%AC%BE%E8%88%87%E9%87%8D%E5%82%B3%E6%AF%94%E8%BC%83\" class=\"anchor\" id=\"重複付款與重傳比較\"\u003e\u003c/a\u003e重複付款與重傳比較\u003c/h3\u003e\n\u003cp\u003e必須區分防止同一簽章重用與防止訂單重複處理。EIP-3009 會防止已使用的授權 nonce 再次使用。這項行為定義於 \u003ca href=\"https://eips.ethereum.org/EIPS/eip-3009\"\u003eERC-3009 規格\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e情況\u003c/th\u003e\n\u003cth\u003e鏈上授權角度\u003c/th\u003e\n\u003cth\u003eAPI 營運角度\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"情況\"\u003e再次結算同一授權\u003c/td\u003e\n\u003ctd data-label=\"鏈上授權角度\"\u003e須檢查是否為已使用的 nonce\u003c/td\u003e\n\u003ctd data-label=\"API 營運角度\"\u003e需要查詢既有結果\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"情況\"\u003e為同一訂單建立新授權\u003c/td\u003e\n\u003ctd data-label=\"鏈上授權角度\"\u003e可能被視為獨立授權處理\u003c/td\u003e\n\u003ctd data-label=\"API 營運角度\"\u003e需要防止重複付款\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"情況\"\u003e結算成功後回應遺失\u003c/td\u003e\n\u003ctd data-label=\"鏈上授權角度\"\u003e資產移轉可能已完成\u003c/td\u003e\n\u003ctd data-label=\"API 營運角度\"\u003e需要重新傳送內容\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"情況\"\u003e請求結算後逾時\u003c/td\u003e\n\u003ctd data-label=\"鏈上授權角度\"\u003e結果仍不明確\u003c/td\u003e\n\u003ctd data-label=\"API 營運角度\"\u003e需要待處理狀態與結算確認\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e以下步驟是將官方擴充連接至正式環境儲存系統的設計方案，並未包含在前面的最小程式碼中。若要用於正式環境，請加入持久化儲存與並行請求控制。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e在伺服器宣告支援 \u003ccode\u003epayment-identifier\u003c/code\u003e 擴充。\u003c/li\u003e\n\u003cli\u003e在用戶端保留邏輯請求的識別碼。\u003c/li\u003e\n\u003cli\u003e在伺服器將識別碼與付款人及請求內容連結。\u003c/li\u003e\n\u003cli\u003e以原子操作記錄處理中狀態，防止同時執行。\u003c/li\u003e\n\u003cli\u003e結算成功時，儲存交易憑證與回應結果。\u003c/li\u003e\n\u003cli\u003e若再次請求的權限與內容相同，則回傳已儲存的結果。\u003c/li\u003e\n\u003cli\u003e若結算結果不明確，先確認既有授權。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e付款識別碼不是密碼或存取權杖。不可向僅知道識別碼的請求回傳付費快取。也請檢查是否被其他使用者或不同請求本文重用。\u003c/p\u003e\n\u003cp\u003e營運紀錄請一併保留鏈、交易雜湊與日誌位置。將這些紀錄與訂單連結，防止被其他訂單重用。僅有 \u003ccode\u003eTransfer\u003c/code\u003e 相符，無法證明訂單歸屬。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E4%BB%98%E6%AC%BE%E5%AF%A6%E4%BD%9C%E7%9A%84%E5%B8%B8%E8%A6%8B%E9%8C%AF%E8%AA%A4\" class=\"anchor\" id=\"付款實作的常見錯誤\"\u003e\u003c/a\u003e付款實作的常見錯誤\u003c/h2\u003e\n\u003cp\u003e混淆版本欄位與成功訊號，會導致付款判定錯誤。請在部署審查時使用下表。版本差異以 \u003ca href=\"https://docs.x402.org/guides/migration-v1-to-v2\"\u003ex402 遷移指南\u003c/a\u003e為準。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e常見錯誤\u003c/th\u003e\n\u003cth\u003e修正依據\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e將 \u003ccode\u003eextra.version: \"2\"\u003c/code\u003e 解讀為 x402 版本\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e透過 \u003ccode\u003ex402Version\u003c/code\u003e 確認協定版本\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e在 v2 使用 \u003ccode\u003emaxAmountRequired\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e付款條件的金額使用 \u003ccode\u003eamount\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e自行建立 \u003ccode\u003eX-PAYMENT-REQUIRED\u003c/code\u003e 標頭\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003ev1 使用本文，v2 使用 \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e將 \u003ccode\u003eisValid: true\u003c/code\u003e 視為款項已入帳\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e另外確認 \u003ccode\u003e/settle\u003c/code\u003e 結果\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e將交易最上層的 \u003ccode\u003eto\u003c/code\u003e 視為 USDC 收款人\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e確認 USDC \u003ccode\u003eTransfer.to\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e假設簽署者與交易發送者相同\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e比對授權付款人與 \u003ccode\u003eTransfer.from\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e將測試網收款金額計入營收\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e分開主網與測試網帳目\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e每次逾時都建立新付款\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e先復原既有訂單與授權狀態\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"常見錯誤\"\u003e將 SDK 套件版本與協定版本視為相同\u003c/td\u003e\n\u003ctd data-label=\"修正依據\"\u003e分別管理套件版本與 \u003ccode\u003ex402Version\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eUSDC 簽章的網域資訊也包含版本字串。該值與 x402 協定版本的用途不同。簽章網域結構請參閱 \u003ca href=\"https://eips.ethereum.org/EIPS/eip-3009\"\u003eERC-3009 規格\u003c/a\u003e。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E5%AE%89%E5%85%A8%E6%AA%A2%E6%9F%A5%E8%88%87%E5%A4%96%E9%83%A8%E6%9C%8D%E5%8B%99%E7%9A%84%E4%BF%A1%E4%BB%BB%E7%AF%84%E5%9C%8D\" class=\"anchor\" id=\"安全檢查與外部服務的信任範圍\"\u003e\u003c/a\u003e安全檢查與外部服務的信任範圍\u003c/h2\u003e\n\u003cp\u003e請由伺服器控制付款成功的判定。外部 facilitator 的回應也是明確納入信任的對象。\u003ca href=\"https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md\"\u003efacilitator 文件\u003c/a\u003e說明了也可自行營運的架構。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不要依據用戶端的成功訊息開放內容。\u003c/li\u003e\n\u003cli\u003e請比對伺服器宣告的鏈、代幣、金額與收款人。\u003c/li\u003e\n\u003cli\u003e不要將私鑰與助記詞寫入日誌。\u003c/li\u003e\n\u003cli\u003e完整的授權簽章也應排除在一般存取日誌之外。\u003c/li\u003e\n\u003cli\u003e請限制付款標頭大小與請求處理時間。\u003c/li\u003e\n\u003cli\u003e請檢查付費回應是否會留在共用快取中。\u003c/li\u003e\n\u003cli\u003e請分開存放測試金鑰與正式環境金鑰。\u003c/li\u003e\n\u003cli\u003efacilitator 故障時，不要建立免付款的繞過路徑。\u003c/li\u003e\n\u003cli\u003e請實際測試授權到期與重複請求。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e本實作鎖定的相依套件仍有安全檢查警告。\u003ccode\u003enpm audit\u003c/code\u003e 回報了與 zod 相關的安全公告。相關內容請參閱 \u003ca href=\"https://github.com/advisories/GHSA-mrhx-c7xc-m3w5\"\u003eGitHub 安全公告\u003c/a\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e audit\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e正式部署前，請確認修正版與 SDK 的相容性。強制更換主要版本可能導致行為改變。不要將本實作當成已完成安全驗證的部署設定。\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#%E8%87%AA%E6%9C%89%E4%BC%BA%E6%9C%8D%E5%99%A8%E8%88%87-cloudflare-gateway-%E6%AF%94%E8%BC%83\" class=\"anchor\" id=\"自有伺服器與-cloudflare-gateway-比較\"\u003e\u003c/a\u003e自有伺服器與 Cloudflare Gateway 比較\u003c/h3\u003e\n\u003cp\u003e使用 Cloudflare Gateway 時，來源伺服器的驗證方式會改變。2026年9月30日的文件明確指出使用 x402 v2。下列區分以 \u003ca href=\"https://developers.cloudflare.com/monetization-gateway/x402/\"\u003eCloudflare x402 文件\u003c/a\u003e為準。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e類別\u003c/th\u003e\n\u003cth\u003e本文的 Express 方式\u003c/th\u003e\n\u003cth\u003eCloudflare Monetization Gateway\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e用戶端付款處理\u003c/td\u003e\n\u003ctd data-label=\"本文的 Express 方式\"\u003eExpress 中介軟體\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eGateway\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e來源伺服器的驗證點\u003c/td\u003e\n\u003ctd data-label=\"本文的 Express 方式\"\u003e與所選 facilitator 串接\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003e驗證 \u003ccode\u003ePAYMENT-CONTEXT\u003c/code\u003e JWT\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e結算結果傳遞\u003c/td\u003e\n\u003ctd data-label=\"本文的 Express 方式\"\u003e中介軟體的 \u003ccode\u003ePAYMENT-RESPONSE\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eGateway 產生結算收據\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"類別\"\u003e額外確認事項\u003c/td\u003e\n\u003ctd data-label=\"本文的 Express 方式\"\u003efacilitator 支援的鏈與身分驗證\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eJWT 簽章驗證與來源存取保護\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003ePAYMENT-CONTEXT\u003c/code\u003e 是 Gateway 與來源伺服器之間的標頭，不是一般 x402 用戶端的簽章標頭。來源驗證請遵循 \u003ca href=\"https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/\"\u003eCloudflare Payment validation 文件\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e即使經過 Gateway，也不能只將 JWT 解碼。請使用文件指定的金鑰驗證簽章。若缺少標頭或驗證失敗，就封鎖付費內容。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#%E5%8D%80%E5%88%86%E5%AF%A6%E9%9A%9B%E4%BD%BF%E7%94%A8%E9%87%8F%E8%88%87%E7%B5%90%E7%AE%97%E7%B4%80%E9%8C%84\" class=\"anchor\" id=\"區分實際使用量與結算紀錄\"\u003e\u003c/a\u003e區分實際使用量與結算紀錄\u003c/h2\u003e\n\u003cp\u003e僅憑鏈上轉帳筆數，無法證明內容已被使用。請將結算與回應傳送連結後，再彙整營運指標。這是根據付款流程與重傳行為提出的設計建議。\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e紀錄\u003c/th\u003e\n\u003cth\u003e可回答的問題\u003c/th\u003e\n\u003cth\u003e額外需要的紀錄\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"紀錄\"\u003e402 回應\u003c/td\u003e\n\u003ctd data-label=\"可回答的問題\"\u003e付款條件被請求了多少次\u003c/td\u003e\n\u003ctd data-label=\"額外需要的紀錄\"\u003e是否實際付款\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"紀錄\"\u003e驗證成功\u003c/td\u003e\n\u003ctd data-label=\"可回答的問題\"\u003e授權是否有效\u003c/td\u003e\n\u003ctd data-label=\"額外需要的紀錄\"\u003e結算結果\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"紀錄\"\u003eUSDC 轉帳\u003c/td\u003e\n\u003ctd data-label=\"可回答的問題\"\u003e資產是否移轉\u003c/td\u003e\n\u003ctd data-label=\"額外需要的紀錄\"\u003e訂單歸屬\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"紀錄\"\u003e各訂單結算完成\u003c/td\u003e\n\u003ctd data-label=\"可回答的問題\"\u003e付費請求是否已付款\u003c/td\u003e\n\u003ctd data-label=\"額外需要的紀錄\"\u003e回應傳送狀態\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"紀錄\"\u003e重新傳送紀錄\u003c/td\u003e\n\u003ctd data-label=\"可回答的問題\"\u003e是否復原了已付款的請求\u003c/td\u003e\n\u003ctd data-label=\"額外需要的紀錄\"\u003e與新付款區分的識別碼\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e請在實際使用量統計中區分測試請求。同一訂單的重試也應另外標示。不可將交易量本身解釋為 API 需求或收益保證。\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#base-%E4%B8%BB%E7%B6%B2%E5%88%87%E6%8F%9B%E6%AD%A5%E9%A9%9F\" class=\"anchor\" id=\"base-主網切換步驟\"\u003e\u003c/a\u003eBase 主網切換步驟\u003c/h2\u003e\n\u003cp\u003e確認測試網的正常與失敗路徑後，再評估主網。切換並非只要更改網路字串就完成。標準步驟遵循\u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet\"\u003e官方賣方指南\u003c/a\u003e。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e確認所選 facilitator 支援 Base 主網。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e/supported\u003c/code\u003e 確認支援 v2、\u003ccode\u003eexact\u003c/code\u003e、\u003ccode\u003eeip155:8453\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e設定提供者要求的身分驗證與使用條件。\u003c/li\u003e\n\u003cli\u003e同時更改伺服器與用戶端的網路。\u003c/li\u003e\n\u003cli\u003e將用戶端允許的 USDC 地址改為主網地址。\u003c/li\u003e\n\u003cli\u003e再次比對 402 回應的金額與實際收款地址。\u003c/li\u003e\n\u003cli\u003e接上重複請求儲存機制與故障復原程序。\u003c/li\u003e\n\u003cli\u003e完成正式環境相依套件的安全檢查。\u003c/li\u003e\n\u003cli\u003e以設定的小額款項確認實際轉帳與內容傳送。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e支援多鏈不代表支援所有組合。請同時確認 SDK 與 facilitator 的支援範圍。確認依據為\u003ca href=\"https://docs.x402.org/core-concepts/network-and-token-support\"\u003e網路與代幣支援文件\u003c/a\u003e。\u003c/p\u003e\n","tags":["穩定幣","AI 代理人","AI 開發","內容變現","開發工具"],"faqs":[{"question":"x402 與一般的 USDC 入帳確認有什麼不同？","answer":"在 HTTP 請求過程中傳遞付款條件，並以已簽署的付款授權重新發送請求。不同於事後核對入帳紀錄的方式，這種做法將付款流程與付費資源請求連結。"},{"question":"x402 v2 的付款標頭有哪些？","answer":"付款條件透過 PAYMENT-REQUIRED 傳遞，付款酬載透過 PAYMENT-SIGNATURE 傳遞。結算結果透過 PAYMENT-RESPONSE 傳遞。"},{"question":"v1 有 X-PAYMENT-REQUIRED 標頭嗎？","answer":"官方 HTTP v1 規格將最初的付款條件放在 JSON 回應本文中。付款酬載與結算結果則分別使用 X-PAYMENT 和 X-PAYMENT-RESPONSE。"},{"question":"/verify 成功就代表付款完成了嗎？","answer":"/verify 成功表示付款授權有效。在本次實作中，必須另外確認 /settle 的成功結果。"},{"question":"Base Sepolia 測試 USDC 可以視為實際收益嗎？","answer":"Circle 明確表示，測試網 USDC 不具金融價值。請將測試網結算與實際營收分開記錄。"},{"question":"需要在收款伺服器中放入私鑰嗎？","answer":"本範例的收款伺服器只設定公開的收款地址。付款授權使用的私鑰由付款用戶端讀取。"},{"question":"0.001 USDC 的 amount 值是多少？","answer":"依 USDC 的 6 位小數換算，以最小單位表示為 1000。v2 付款條件使用字串 \"1000\"。"},{"question":"交易收據顯示成功，就代表已確認收到 USDC 嗎？","answer":"僅憑交易成功狀態還不夠。請在官方 USDC 合約的 Transfer 事件中核對付款人、收款人與金額。"},{"question":"再次發送相同的付款請求安全嗎？","answer":"防止同一授權 nonce 被重複使用，與防止訂單重複是兩回事。重試前請確認既有付款的狀態，並針對每筆訂單實作冪等性處理。"},{"question":"沒有 PAYMENT-RESPONSE 時，重新付款就可以了嗎？","answer":"若回應遺失或逾時，結算結果可能不明確。請勿先建立新的授權，應先確認原請求的結算狀態。"},{"question":"x402 必須使用特定公司的 facilitator 嗎？","answer":"官方架構允許使用外部 facilitator，也允許自行營運。請確認所選的實作支援所需的協定版本、付款方式與鏈。"},{"question":"AI 代理的支出也會自動受到限制嗎？","answer":"本範例只限制每次請求的付款條件。請透過另外的預算政策管理重複呼叫所產生的累積支出。"},{"question":"Cloudflare PAYMENT-CONTEXT 是標準的付款簽章標頭嗎？","answer":"PAYMENT-CONTEXT 是 Gateway 傳送給來源伺服器的 JWT，用途與用戶端的 PAYMENT-SIGNATURE 不同。"},{"question":"可以直接將範例部署到主網嗎？","answer":"這段程式碼是供測試使用的最小配置。正式部署前，請確認相依套件的安全警告、重複請求處理、facilitator 身分驗證與實際結算。"}],"sources":[{"url":"https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md","title":"x402 協定規格 v2","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md","title":"x402 HTTP 傳輸 v1","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md","title":"x402 HTTP 傳輸 v2","type":"source"},{"url":"https://docs.x402.org/guides/migration-v1-to-v2","title":"x402 遷移指南：V1 至 V2","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md","title":"x402 Facilitator 的角色與責任","type":"source"},{"url":"https://docs.x402.org/getting-started/quickstart-for-sellers","title":"x402 賣方快速入門","type":"source"},{"url":"https://docs.x402.org/getting-started/quickstart-for-buyers","title":"x402 買方快速入門","type":"source"},{"url":"https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch","title":"x402 官方 TypeScript fetch 用戶端範例","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts","title":"x402 Express 中介軟體實作","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts","title":"x402Client 付款條件選擇與政策實作","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts","title":"x402 ExactEvmScheme 伺服器端價格轉換實作","type":"source"},{"url":"https://developers.circle.com/stablecoins/usdc-contract-addresses","title":"Circle USDC 合約地址","type":"data_point"},{"url":"https://docs.base.org/get-started/connect-to-base","title":"Base 主網與 Base Sepolia 網路資訊","type":"data_point"},{"url":"https://faucet.circle.com/","title":"Circle 測試網水龍頭","type":"source"},{"url":"https://viem.sh/docs/actions/public/getTransactionReceipt","title":"viem getTransactionReceipt","type":"source"},{"url":"https://viem.sh/docs/contract/parseEventLogs","title":"viem parseEventLogs","type":"source"},{"url":"https://eips.ethereum.org/EIPS/eip-20","title":"ERC-20 代幣標準","type":"source"},{"url":"https://eips.ethereum.org/EIPS/eip-3009","title":"ERC-3009 授權轉帳","type":"source"},{"url":"https://docs.x402.org/extensions/payment-identifier","title":"x402 Payment-Identifier 冪等性擴充","type":"source"},{"url":"https://developers.cloudflare.com/monetization-gateway/x402/","title":"Cloudflare Monetization Gateway x402 協定","type":"source"},{"url":"https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/","title":"Cloudflare Monetization Gateway 付款驗證","type":"source"},{"url":"https://docs.x402.org/core-concepts/network-and-token-support","title":"x402 網路與代幣支援","type":"source"},{"url":"https://github.com/advisories/GHSA-mrhx-c7xc-m3w5","title":"GitHub 安全公告：Zod 驗證大型集合所導致的記憶體耗盡","type":"source"}],"images":[{"id":2199,"url":"https://injoys.com/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzM4MDcsInB1ciI6ImJsb2JfaWQifX0=--49c502fd8da16158a617c3586dfa81ced4bc95df/ai-f0ae2b5c.webp","is_representative":true,"generation_method":"ai_photo","license":"ai_generated","mime_type":"image/webp","width":1536,"height":1024,"translations":{"ko":{"alt":"짙은 회색 스웨터를 입은 남성이 서버 랙 선반에 놓인 태블릿 화면을 살펴보고 있다.","caption":"메인넷으로 전환하기 전에 테스트 환경에서 x402 결제 연동을 검증하세요.","description":null},"en":{"alt":"A man in a dark gray sweater examines a tablet resting on a server rack shelf.","caption":"Validate the x402 payment integration in a test environment before switching to mainnet.","description":null},"ja":{"alt":"濃いグレーのセーターを着た男性が、サーバーラックの棚に置かれたタブレットを確認している。","caption":"メインネットへ移行する前に、テスト環境でx402の決済連携を検証しましょう。","description":null},"es":{"alt":"Un hombre con un suéter gris oscuro revisa una tableta sobre la bandeja de un rack de servidores.","caption":"Valida la integración de pagos x402 en un entorno de prueba antes de pasar a la red principal.","description":null},"id":{"alt":"Seorang pria bersweater abu-abu gelap memeriksa tablet di atas ambalan rak server.","caption":"Validasi integrasi pembayaran x402 di lingkungan uji sebelum beralih ke mainnet.","description":null},"pt":{"alt":"Um homem de suéter cinza-escuro examina um tablet apoiado na prateleira de um rack de servidores.","caption":"Valide a integração de pagamentos x402 em um ambiente de teste antes de migrar para a rede principal.","description":null},"zh-hant":{"alt":"一名穿著深灰色毛衣的男子正在查看伺服器機架層板上的平板電腦。","caption":"切換至主網前，先在測試環境中驗證 x402 支付整合。","description":null},"de":{"alt":"Ein Mann im dunkelgrauen Pullover prüft ein Tablet auf der Ablage eines Serverracks.","caption":"Prüfen Sie die x402-Zahlungsintegration in einer Testumgebung, bevor Sie ins Mainnet wechseln.","description":null}}},{"id":2200,"url":"https://injoys.com/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzM4MTMsInB1ciI6ImJsb2JfaWQifX0=--4e70727f132519277c68d1c6279d95585a936549/ai-3dbd1c62.webp","is_representative":false,"generation_method":"ai_semi","license":"ai_generated","mime_type":"image/webp","width":1536,"height":1024,"translations":{"ko":{"alt":"창가에서 여성이 평평하게 펼친 노트북으로 입력하고 있으며, 화면에는 목록과 두 경로가 합쳐지는 흐름도가 보인다.","caption":"중복 요청 복구를 시험해 결제 재시도가 이중 정산으로 이어지지 않는지 확인하세요.","description":null},"en":{"alt":"A woman types on a laptop opened flat, with a list and two paths converging on one endpoint on its screen.","caption":"Test duplicate-request recovery to ensure payment retries do not cause a second settlement.","description":null},"ja":{"alt":"窓辺で女性が平らに開いたノートパソコンを操作し、画面には一覧と2本の経路が合流するフロー図が表示されている。","caption":"重複リクエストの復旧をテストし、決済の再試行で二重精算が起きないことを確認しましょう。","description":null},"es":{"alt":"Una mujer teclea en un portátil abierto en plano; la pantalla muestra una lista y dos rutas que convergen.","caption":"Prueba la recuperación de solicitudes duplicadas para evitar una segunda liquidación al reintentar el pago.","description":null},"id":{"alt":"Seorang perempuan mengetik di laptop yang dibuka rata, dengan daftar dan diagram dua jalur yang menyatu di layar.","caption":"Uji pemulihan permintaan duplikat untuk memastikan percobaan ulang pembayaran tidak memicu penyelesaian ganda.","description":null},"pt":{"alt":"Uma mulher digita num notebook aberto na horizontal, com uma lista e duas rotas convergentes na tela.","caption":"Teste a recuperação de solicitações duplicadas para garantir que novas tentativas de pagamento não gerem liquidação dupla.","description":null},"zh-hant":{"alt":"一名女子在窗邊操作完全攤平的筆記型電腦，螢幕顯示清單及兩條路徑匯合的流程圖。","caption":"測試重複請求的復原流程，確認付款重試不會造成重複結算。","description":null},"de":{"alt":"Eine Frau tippt auf einem flach aufgeklappten Laptop; das Display zeigt eine Liste und zwei zusammenlaufende Pfade.","caption":"Testen Sie die Wiederherstellung bei doppelten Anfragen, damit Zahlungswiederholungen keine zweite Abrechnung auslösen.","description":null}}}],"published_at":"2026-10-28T19:20:55+09:00","updated_at":"2026-10-28T19:20:55+09:00","license":"cc_by","translation_status":"reviewed","available_locales":["ko","en","ja","es"],"data_locales":["ko","en","ja","es","id","pt","zh-hant","de"],"url":"https://injoys.com/en/articles/x402-payments-2026-v2-base-usdc-settlement-guide"}