メインコンテンツへスキップ
x402 は HTTP 402 ステータスコードに基づくオープンな決済プロトコルです。サーバーは未決済のリクエストに対して 402 challenge を返し、支払い側(通常は AI エージェント)はオンチェーンのステーブルコイン承認署名を付けてリクエストを再送し、決済完了後にリソースを取得します。Waffo は x402 を標準的な決済受け入れ機能として提供しており、注文・Webhook・照合は既存の Waffo 統合と完全に同一で、オンチェーンの検証と決済は Waffo が行います。 本ページは 2 種類の読者を対象としています。主対象は加盟店開発者(統合モードの選択、Waffo API の呼び出し、リソース提供の判定)です。AI エージェント開発者は 402 challenge の構造と PAYMENT-SIGNATURE の送信方法を中心にお読みください。エージェント側のやり取りに加盟店の API キーは不要です。

2 つの統合モード

モード 1:加盟店ホスト型 402

加盟店サーバー自身が x402 server として動作します。エージェントに 402 challenge を返し、署名を受け取り、order/create で署名を Waffo に引き渡して決済します。エージェントを自社 API 上に留めたい、x402 プロトコルの詳細を自前で実装できる加盟店に適しています。

モード 2:Waffo ホスト型 402

加盟店は注文を作成し、Waffo が返すホスト型 URL をエージェントに渡すだけです。402 challenge、署名の受け取り、決済はすべて Waffo キャッシャーが行います。x402 プロトコルの詳細に触れず迅速にリリースしたい加盟店に適しています。
両モードは同一の order/create エンドポイントを共用します。区別はただ一つ、リクエストの x402InfopaymentSignatureHeader を含むかどうかです。署名ありはモード 1、署名なしはモード 2 になります。

前提条件

x402 決済の受け入れには、Waffo 導入チームを通じて以下 2 点の開通が必要です。
  1. 加盟店契約で CRYPTO / USDC 決済プロダクトを有効化する
  2. Waffo 側でオンチェーン受取パラメータを設定する
設定が完了していない場合、wallet/inquiryorder/create はエラーコード A0010(加盟店契約で許可されていない操作)を返します。

現在のサポート範囲

以下は現行バージョンの確定した境界です。この前提で開発し、他の機能を想定しないでください。
  • 通貨USDC のみ。orderCurrency は必ず USDC(同一通貨での受け入れ、為替換算なし)
  • ネットワーク:Base のみ(本番は eip155:8453、サンドボックスは Base Sepolia eip155:84532
  • schemeexact のみ(challenge の金額どおりに決済)
  • 承認回数:EIP-3009 の承認はオンチェーンで 1 回のみ消費されます。1 つの署名で決済できるのは 1 回だけで、「1 回の承認で複数回請求」はサポートされません
  • 冪等性paymentRequestId は必須です。同一注文への order/create 再実行は既存注文の実際のステータスを返し、再決済は行われません(冪等性を参照)

オンチェーン受取パラメータの取得

モード 1 で 402 challenge を構築する前に、POST /api/v1/wallet/inquiry で受取パラメータを取得します。このエンドポイントは照会のみで、注文の作成も金額の検証も行いません。
curl -X POST https://api-sandbox.waffo.com/api/v1/wallet/inquiry \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-SIGNATURE: YOUR_RSA_SIGNATURE" \
  -d '{
    "paymentRequestId": "x402-order-10001",
    "merchantInfo": { "merchantId": "M000001" },
    "orderCurrency": "USDC"
  }'
{
  "code": "0",
  "msg": "Success",
  "data": {
    "network": "eip155:84532",
    "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "payTo": "0xc15Ea3D0b7A29c41F8b26aD5c30F49E20e510e71"
  }
}
フィールド説明
networkCAIP-2 ネットワーク識別子。サンドボックスは Base Sepolia eip155:84532、本番は Base メインネット eip155:8453 を返します
assetUSDC トークンのコントラクトアドレス(環境とネットワークにより異なり、本番の Base メインネットは 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
payToWaffo プラットフォームの受取アドレス。Waffo がオンチェーンで受け取り、契約に基づいて加盟店に精算します
3 つのフィールドはいずれも Waffo の設定値です。challenge の構築にはそのまま使用してください。payTo を自社のウォレットアドレスに置き換えてはいけません。エージェントの署名内の受取アドレスと金額は、決済前にオンチェーンで厳密に検証されます。

モード 1:加盟店ホスト型 402

加盟店側で行うことは 4 つです。
  1. wallet/inquirynetwork / asset / payTo を取得し、価格設定に基づいて 402 challenge を構築(金額はアトミック単位、schemeexact 固定)してエージェントに返す
  2. エージェントの再送リクエストヘッダー PAYMENT-SIGNATURE から署名を取り出し、そのまま order/createx402Info.paymentSignatureHeader に設定する(デコードして再構築しない)
  3. 同期レスポンスの orderStatus で提供可否を判定する:PAY_SUCCESS は提供、PAY_IN_PROGRESSWebhook または order/inquiry の最終ステータスを待つ、ORDER_CLOSE は拒否
  4. 提供時にレスポンスの x402Info.x402ResponsePAYMENT-RESPONSE ヘッダーとしてエージェントに返す。これが x402 準拠の決済レシートです
curl -X POST https://api-sandbox.waffo.com/api/v1/order/create \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-SIGNATURE: YOUR_RSA_SIGNATURE" \
  -d '{
    "paymentRequestId": "x402-order-10001",
    "merchantOrderId": "x402-order-10001",
    "orderCurrency": "USDC",
    "orderAmount": "9.99",
    "orderDescription": "API usage credits",
    "notifyUrl": "https://merchant.example.com/webhook/waffo",
    "merchantInfo": { "merchantId": "M000001" },
    "userInfo": { "userId": "agent_7f3e", "userTerminal": "WEB" },
    "paymentInfo": { "productName": "ONE_TIME_PAYMENT", "payMethodName": "USDC" },
    "x402Info": {
      "x402Request": true,
      "paymentSignatureHeader": "eyJ4NDAyVmVyc2lvbiI6Miwic2NoZW1lIjoiZXhhY3QiLC4uLn0="
    }
  }'
{
  "code": "0",
  "msg": "Success",
  "data": {
    "paymentRequestId": "x402-order-10001",
    "merchantOrderId": "x402-order-10001",
    "acquiringOrderId": "A202607060001",
    "orderStatus": "PAY_SUCCESS",
    "x402Info": {
      "x402Request": true,
      "paymentSignatureHeader": "eyJ4NDAyVmVyc2lvbiI6Miwic2NoZW1lIjoiZXhhY3QiLC4uLn0=",
      "x402Response": "eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IjB4Li4uIn0="
    }
  }
}
その他の必須フィールド(goodsInfoorderRequestedAt など)は通常のワンタイム決済の注文作成と同一です。API Reference を参照してください。 paymentSignatureHeader は base64 エンコードされた x402 PaymentPayload です。デコード後の構造は以下のとおりです(エージェント側の x402 SDK が生成するため、加盟店が構築する必要はありません)。
{
  "x402Version": 2,
  "scheme": "exact",
  "network": "eip155:84532",
  "payload": {
    "signature": "0x<65 バイトの EIP-712 署名>",
    "authorization": {
      "from": "0x<エージェントのウォレットアドレス>",
      "to": "0xc15Ea3D0b7A29c41F8b26aD5c30F49E20e510e71",
      "value": "9990000",
      "validAfter": "0",
      "validBefore": "1783340000",
      "nonce": "0x<32 バイトのランダム nonce(リプレイ防止、非連番)>"
    }
  }
}
署名内の authorization.towallet/inquiry が返した payTo と一致し、authorization.valueorderAmount のアトミック単位表現と一致しなければなりません(換算ルールは後述の「金額と小数位」を参照)。いずれかが不一致の場合、決済前の検証で失敗し、注文は ORDER_CLOSE になります。したがって 402 challenge でエージェントに提示する価格は order/createorderAmount と一致している必要があります。
x402Response は base64 エンコードされた決済レシート(x402 SettlementResponse)で、orderStatus = PAY_SUCCESS の場合のみ返されます。デコード後:
{
  "success": true,
  "transaction": "0x8f4e2b7c9d1a4f6e8b3c5d7a9e1f2b4c6d8e0a2c4e6f8a0b2c4d6e8f0a1b3c5d",
  "network": "eip155:84532",
  "payer": "0x51E2aF03D0A5c3C7dF83Db9F4b0a2E51D8c19aC3"
}
transaction はオンチェーンのトランザクションハッシュで、照合とオンチェーン検証に使用できます。payer はエージェントの支払いウォレットアドレスです。

モード 2:Waffo ホスト型 402

加盟店側で行うことは 3 つです。
  1. order/createx402Info: { "x402Request": true }(署名なし)と successRedirectUrl / failedRedirectUrl を設定する
  2. レスポンスの orderAction(JSON 文字列)を解析して webUrl を取り出し、エージェントを 302 リダイレクトする。以降の 402 challenge、署名の受け取り、決済はすべて Waffo キャッシャー側で行われます
  3. Webhook または order/inquiry が返す orderStatus に基づいてリソースを提供する
curl -X POST https://api-sandbox.waffo.com/api/v1/order/create \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-SIGNATURE: YOUR_RSA_SIGNATURE" \
  -d '{
    "paymentRequestId": "x402-order-10002",
    "merchantOrderId": "x402-order-10002",
    "orderCurrency": "USDC",
    "orderAmount": "9.99",
    "orderDescription": "API usage credits",
    "notifyUrl": "https://merchant.example.com/webhook/waffo",
    "successRedirectUrl": "https://merchant.example.com/x402/return",
    "failedRedirectUrl": "https://merchant.example.com/x402/failed",
    "merchantInfo": { "merchantId": "M000001" },
    "userInfo": { "userId": "agent_7f3e", "userTerminal": "WEB" },
    "paymentInfo": { "productName": "ONE_TIME_PAYMENT", "payMethodName": "USDC" },
    "x402Info": { "x402Request": true }
  }'
{
  "code": "0",
  "msg": "Success",
  "data": {
    "paymentRequestId": "x402-order-10002",
    "merchantOrderId": "x402-order-10002",
    "acquiringOrderId": "A202607060002",
    "orderStatus": "AUTHORIZATION_REQUIRED",
    "orderAction": "{\"actionType\":\"WEB\",\"webUrl\":\"https://cashier.waffo.com/cashier/api/v1/x402/7sKq9WfR2mXt\"}"
  }
}
エージェントが webUrl にアクセスすると HTTP 402 を受け取ります。challenge はレスポンスボディにあります(x402 プロトコルでは challenge はボディに置かれ、専用のレスポンスヘッダーはありません)。
{
  "x402Version": 2,
  "error": "PAYMENT-SIGNATURE header is required",
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:84532",
      "maxAmountRequired": "9990000",
      "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "payTo": "0xc15Ea3D0b7A29c41F8b26aD5c30F49E20e510e71",
      "maxTimeoutSeconds": 600,
      "extra": { "name": "USDC", "version": "2" }
    }
  ]
}
署名後、エージェントは初回アクセスと同じ HTTP メソッドで同一 URL に再送し、署名を PAYMENT-SIGNATURE リクエストヘッダー(x402 仕様の X-PAYMENT に相当)に設定します。加盟店の認証情報は一切不要です。
curl "https://cashier.waffo.com/cashier/api/v1/x402/7sKq9WfR2mXt" \
  -H "PAYMENT-SIGNATURE: eyJ4NDAyVmVyc2lvbiI6Miwic2NoZW1lIjoiZXhhY3QiLC4uLn0="
決済完了後、キャッシャーは 302 でエージェントを加盟店の successRedirectUrl または failedRedirectUrl に戻します。ホスト型 URL はブラウザアクセス(チェックアウトページを表示)と x402 クライアントアクセス(プロトコルレスポンスを返す)の両方に対応しています。
302 リダイレクトはフローの接続のためだけのもので、支払いの証明ではありません。「支払い済み」の判定は、Webhook 通知または order/inquiry で確認した orderStatus = PAY_SUCCESS のみに基づいてください。リダイレクトは偽造・消失の可能性があり、リダイレクト時点では決済が確定していないこともあります。
決済成功後、Webhook 通知と order/inquiry レスポンスには x402Info.x402Response(構造はモード 1 と同一)が付加されます。それ以外の通知構造は通常の注文と同じです。Webhook イベントタイプを参照してください。

モード比較

項目モード 1:加盟店ホスト型 402モード 2:Waffo ホスト型 402
x402 server の役割(402 の発行、署名の受領)加盟店サーバーWaffo キャッシャー
x402 プロトコル詳細の実装が必要か必要(challenge 構築、署名ヘッダーの解析)不要
order/create に署名を含むか含む(x402Info.paymentSignatureHeader含まない
注文作成レスポンス最終ステータスまたは PAY_IN_PROGRESS を直接返すAUTHORIZATION_REQUIRED + ホスト型 URL
リダイレクトなし(エージェントは終始加盟店 API と通信)加盟店 302 → キャッシャー 302 で戻る
リソース提供の判定基準同期レスポンス / Webhook / inquiry の orderStatusWebhook / inquiry の orderStatus
適した加盟店x402 サービスを自前で構築し深くカスタマイズしたい場合プロトコル詳細に触れず迅速にリリースしたい場合
注文ステータスの意味(PAY_IN_PROGRESSAUTHORIZATION_REQUIRED など)は他の決済手段と共通です。決済ライフサイクルを参照してください。

金額と小数位(2 層の単位)

同一の取引に 2 層の金額表現があります。混同しないでください。
フィールド表現方式例(9.99 USDC)
Waffo API 層orderAmountString、小数 2 桁まで"9.99"
オンチェーン / x402 プロトコル層valuemaxAmountRequiredString、アトミック単位の整数(USDC のオンチェーン精度は 6 桁)"9990000"
換算ルール:アトミック単位 = 金額 × 106通貨と金額における USDC の小数 2 桁は Waffo API 層の orderAmount を指します。402 challenge と EIP-3009 署名内の金額は常にアトミック単位です。モード 1 では両層の金額が同一の値を表す必要があり、不一致の場合は決済検証で失敗します。

エラーコード

x402 は Waffo の既存の外部エラーコードを再利用します。msg に具体的な理由が示されます。
コード意味x402 での主な発生原因
A0003パラメータ検証失敗challenge / 署名の scheme が exact でない。paymentRequestId の欠落
A0007サポートされない取引通貨orderCurrencyUSDC でない。または利用可能な同一通貨 USDC 契約がない
A0010加盟店契約で許可されていない操作CRYPTO/USDC 決済プロダクトが未開通、またはオンチェーン受取パラメータが未設定
完全な一覧はエラーコードリファレンスを参照してください。

よくある質問

サンドボックスは Base Sepolia テストネット(eip155:84532)で、USDC コントラクトアドレスは 0x036CbD53842c5426634e7929541eC2318f3dCF7e です。本番は Base メインネット(eip155:8453)で、USDC コントラクトアドレスは 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 です。どちらの環境でも network / asset / payTowallet/inquiry の実際の返り値に従ってください。
現在は USDC + Base ネットワークのみです。orderCurrency に他の通貨を指定すると A0007 が返ります。
できません。x402 の exact scheme は EIP-3009 transferWithAuthorization に基づいており、その nonce は USDC コントラクト側で 1 回のみ消費されます。署名は一度決済されると無効になり、再送信はオンチェーンで直接失敗します。サブスクリプション型や従量制の複数回請求は x402 の対象範囲外です。
いけません。PAY_IN_PROGRESS はオンチェーン処理中を意味するだけで、最終的に成功も失敗もあり得ます。リソースを提供できるのは orderStatus = PAY_SUCCESS のみで、最終ステータスは Webhook または order/inquiry で確定します。
レスポンスボディ(JSON)にあります。challenge を運ぶヘッダーはありません。x402 のやり取りにおける唯一のプロトコルリクエストヘッダーは、エージェントが署名を送信する PAYMENT-SIGNATURE(x402 仕様の X-PAYMENT に相当)です。決済レシートは x402Info.x402Response フィールドで返され、仕様の X-PAYMENT-RESPONSE に相当します。
違います。AI 統合ツールは AI コーディングツールで Waffo SDK の統合コードを生成するものです。本ページは AI エージェントが支払い側としてステーブルコインで加盟店のサービスを購入する仕組みです。併用できますが、解決する課題は異なります。

関連ドキュメント