{
  "lang": "ja",
  "ページ": "https://x402-catalog-history.ai-business-surface.workers.dev/ja/x402-implementation-example",
  "title": "x402 実装 例：Cloudflare Worker で 402 を返す最小構成（本文V1・ヘッダV2を実測）",
  "h1": "x402 実装 例 — Cloudflare Worker で 402 を返す（本文V1・ヘッダV2・実測）",
  "description": "x402 実装 例を探している人向けに、Cloudflare Worker で 402 を返す最小構成を、当方が本番で動かしている形から抜き出しました。本文は V1 形（maxAmountRequired）、PAYMENT-REQUIRED ヘッダは V2 形（amount）で、1つの応答から両方を読ませます。9本の有料路の実測（402・宣言価格・本文サイズ・応答時間）と、無料の形式検査が課金前に返ることも数字で示します。",
  "検索語": "x402 実装 例 cloudflare worker",
  "読者の問い": "x402 を Cloudflare Worker で実装したい。402 に何を入れれば、買い手のクライアントが読めるのか。",
  "実測日": "2026-10-19 JST",
  "実測": {
    "caption": "x402 実装の実測（無課金 GET・2026-10-19 JST・公開URL）",
    "columns": [
      "経路",
      "無課金GET",
      "宣言価格（USDC）",
      "402本文",
      "応答時間"
    ],
    "rows": [
      [
        "/gas",
        "402",
        "0.001",
        "20,883 B",
        "512 ms"
      ],
      [
        "/random",
        "402",
        "0.001",
        "15,201 B",
        "597 ms"
      ],
      [
        "/news",
        "402",
        "0.005",
        "19,676 B",
        "150 ms"
      ],
      [
        "/markdown",
        "402",
        "0.01",
        "17,085 B",
        "310 ms"
      ],
      [
        "/digest",
        "402",
        "0.01",
        "14,876 B",
        "157 ms"
      ],
      [
        "/history",
        "402",
        "0.02",
        "17,840 B",
        "170 ms"
      ],
      [
        "/contract",
        "402",
        "0.02",
        "24,269 B",
        "255 ms"
      ],
      [
        "/price",
        "402",
        "0.02",
        "26,809 B",
        "243 ms"
      ],
      [
        "/check",
        "402",
        "0.05",
        "26,249 B",
        "177 ms"
      ]
    ],
    "note": "9本すべてが 402 で、payment-required ヘッダを持ち、本文 accepts[0] は scheme / network / maxAmountRequired / resource / description / mimeType / payTo / maxTimeoutSeconds / asset / extra の10項目を宣言していました。金額は USDC の最小単位（小数6桁）なので 1000 は 0.001 USDC です。/gas のヘッダは 5,464 B（base64）で、x402Version=2・accepts[0] は7項目（amount を使用）でした。"
  },
  "見出し": [
    "結論",
    "実測",
    "実装の骨格（本文V1・ヘッダV2）",
    "数字から分かること",
    "落とし穴",
    "次の一歩"
  ],
  "本文": [
    {
      "見出し": "結論",
      "html": "<p>x402 の実装で書く本体は、決済処理ではなく<strong>402 の宣言</strong>です。Cloudflare Worker なら <code>export default { fetch }</code> の1関数で、支払い前の GET に 402 と <code>PAYMENT-REQUIRED</code> ヘッダを返すところから始まります。当方は同じ形を本番で動かしており、9本の有料路すべてが 402・ヘッダあり・本文 <code>accepts[0]</code> 10項目を返しました。宣言価格は <strong>0.001〜0.05 USDC</strong>、本文は <strong>14,876〜26,809 B</strong>、応答は <strong>150〜597 ms</strong> です。</p>"
    },
    {
      "見出し": "実測",
      "html": "<table>\n<thead><tr><th>経路</th><th>無課金GET</th><th>宣言価格（USDC）</th><th>402本文</th><th>応答時間</th></tr></thead>\n<tbody>\n<tr><td><code>/gas</code></td><td>402</td><td>0.001</td><td>20,883 B</td><td>512 ms</td></tr>\n<tr><td><code>/random</code></td><td>402</td><td>0.001</td><td>15,201 B</td><td>597 ms</td></tr>\n<tr><td><code>/news</code></td><td>402</td><td>0.005</td><td>19,676 B</td><td>150 ms</td></tr>\n<tr><td><code>/markdown</code></td><td>402</td><td>0.01</td><td>17,085 B</td><td>310 ms</td></tr>\n<tr><td><code>/digest</code></td><td>402</td><td>0.01</td><td>14,876 B</td><td>157 ms</td></tr>\n<tr><td><code>/history</code></td><td>402</td><td>0.02</td><td>17,840 B</td><td>170 ms</td></tr>\n<tr><td><code>/contract</code></td><td>402</td><td>0.02</td><td>24,269 B</td><td>255 ms</td></tr>\n<tr><td><code>/price</code></td><td>402</td><td>0.02</td><td>26,809 B</td><td>243 ms</td></tr>\n<tr><td><code>/check</code></td><td>402</td><td>0.05</td><td>26,249 B</td><td>177 ms</td></tr>\n</tbody>\n</table>\n<p>9本すべてが 402 で、<code>payment-required</code> ヘッダを持ち、本文 <code>accepts[0]</code> は <code>scheme / network / maxAmountRequired / resource / description / mimeType / payTo / maxTimeoutSeconds / asset / extra</code> の10項目を宣言していました。金額は USDC の最小単位（小数6桁）なので <code>1000</code> は 0.001 USDC です。同じ時刻の無料面は <code>/openapi.json</code> 200・<strong>44 paths</strong>・127,835 B・175 ms、<code>/guide/sample</code> 200・11,633 B・128 ms、<code>/ja</code> 200・21,597 B・127 ms でした。</p>"
    },
    {
      "見出し": "実装の骨格（本文V1・ヘッダV2）",
      "html": "<p>いちばん間違えやすいのは、<strong>本文とヘッダでキー名が違う</strong>ことです。V2 のクライアントは <code>PAYMENT-REQUIRED</code> ヘッダを先に読み、V1 のクライアントは本文を読みます。当方の 402 は、本文を V1 形（<code>x402Version:1</code>・<code>maxAmountRequired</code>・<code>network:'base'</code>）、ヘッダを V2 形（<code>x402Version:2</code>・<code>amount</code>・<code>network:'eip155:8453'</code>）にして、1つの応答から両方を読ませています。</p>\n<pre><code>const PRICE = '1000'; // 0.001 USDC（小数6桁）\nconst PAY_TO = '0x…受取アドレス…';\nconst ASSET = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // USDC on Base\n\nfunction accepts(origin, path) {\n  return {\n    scheme: 'exact',\n    network: 'base',                    // 本文は V1 の network 名\n    maxAmountRequired: PRICE,           // 本文は V1 のキー\n    resource: origin + path,\n    description: 'one measured result as JSON',\n    mimeType: 'application/json',\n    payTo: PAY_TO,\n    maxTimeoutSeconds: 60,\n    asset: ASSET,\n    extra: { name: 'USD Coin', version: '2' },\n  };\n}\n\nexport default {\n  async fetch(request) {\n    const url = new URL(request.url);\n    const a = accepts(url.origin, url.pathname);\n    const body = { x402Version: 1, error: 'payment_required', accepts: [a] };\n    const v2 = {\n      x402Version: 2,\n      error: 'payment_required',\n      resource: { url: a.resource, description: a.description, mimeType: a.mimeType },\n      accepts: [{\n        scheme: 'exact',\n        network: 'eip155:8453',           // ヘッダは CAIP-2\n        amount: PRICE,                    // ヘッダは V2 のキー\n        asset: ASSET, payTo: PAY_TO, maxTimeoutSeconds: 60, extra: a.extra,\n      }],\n    };\n    return new Response(JSON.stringify(body), {\n      status: 402,\n      headers: {\n        'content-type': 'application/json; charset=utf-8',\n        'payment-required': btoa(JSON.stringify(v2)),\n      },\n    });\n  },\n};</code></pre>\n<p>この骨格には、当方が本番で足している <code>extensions.bazaar</code>（掲載用の入出力宣言）・利用規約・無料プレビュー・納品処理を入れていません。<strong>抜粋そのものはデプロイしていない</strong>ので、貼れば動くという主張はしません。数字は、この骨格を含む本番の 402 を測った値です。</p>"
    },
    {
      "見出し": "数字から分かること",
      "html": "<ul>\n<li><strong>価格は50倍、宣言は1.8倍</strong>。0.001 の <code>/gas</code> と 0.05 の <code>/check</code> で価格は50倍違いますが、本文は 20,883 B と 26,249 B で1.3倍、最小の <code>/digest</code>（14,876 B）と最大の <code>/price</code>（26,809 B）でも1.8倍です。402 の大きさは価格ではなく、<strong>説明・入出力例・規約をどこまで書いたか</strong>で決まります。</li>\n<li><strong>初回だけ遅い</strong>。同じ <code>/gas</code> を続けて3回叩くと 175・189・146 ms でしたが、最初の1回は 818 ms でした。Cloudflare のコールドスタートか計測経路の差かは<strong>未確認</strong>です。買い手の最初の1回が遅い可能性は、実装時に見ておく価値があります。</li>\n<li><strong>無料の形式検査は課金前に返る</strong>。<code>/markdown</code> に無効な URL を渡すと、<code>http://127.0.0.1/</code> は 351 B・180 ms、<code>not-a-url</code> は 271 B・140 ms、<code>https://example.com:22/</code> は 269 B・175 ms で、いずれも <strong>400</strong>。402 より前に返り、取得も課金も起きません。実装では、この検査を課金ゲートの前に置くのが安全です。</li>\n</ul>"
    },
    {
      "見出し": "落とし穴",
      "html": "<ul>\n<li><strong>本文とヘッダの片方だけでは読めないクライアントが出る</strong>。キー名（<code>maxAmountRequired</code> / <code>amount</code>）と network（<code>base</code> / <code>eip155:8453</code>）が違います。両方に同じ条件を入れてください。</li>\n<li><strong>カタログ掲載は 402 を返すだけでは決まらない</strong>。当方の <code>/gas</code> のヘッダは 5,464 B で、その大半は <code>extensions.bazaar</code> の info と schema です。ただし掲載は宣言だけでは決まらず、<strong>署名つきの /verify が一度通った経路だけ</strong>が載りました（2026-10-17 実測）。</li>\n<li><strong>無料ページは掲載対象外</strong>。<code>/ja</code> や <code>/services</code> は 200 を返し 402 を返さないため、カタログには載りません。掲載したい面は有料化（402 を返す）が要ります。</li>\n<li><strong>402 を返すことと納品できることは別</strong>。支払い後の実行、失敗時の 502、返金の有無は経路ごとに宣言が違います。当方も決済後の挙動はこの記事では測っていません（<strong>決済は1回も実行していない</strong>）。</li>\n</ul>"
    },
    {
      "見出し": "次の一歩",
      "html": "<p>買い手側から見た確認手順は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/check-before-paying\"><code>/ja/check-before-paying</code></a>、相手の仕様変更の検出は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/schema-change\"><code>/ja/schema-change</code></a> に実測でまとめています。実装の全体像は無料の <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/openapi.json\"><code>/openapi.json</code></a>（44 paths）で読めます。</p>"
    }
  ],
  "一覧": "https://x402-catalog-history.ai-business-surface.workers.dev/ja"
}
