{
  "lang": "ja",
  "ページ": "https://x402-catalog-history.ai-business-surface.workers.dev/ja/x402-check-before-paying",
  "title": "x402 check before paying — 第三者の10本を2回GET、7本は402本文が2バイト「{}」で条件はヘッダだけ（実測）",
  "h1": "x402 check before paying：払う前に読むのは402の本文ではなく payment-required ヘッダ — 10本×2回の実測",
  "description": "x402 の相手を払う前に確かめるとき、402 の本文だけを読むと条件を見落とします。discovery の先頭100件から別ホストの10本を選び、支払わずに2回ずつ GET すると、9本が402・1本が404で、402のうち7本は本文が2バイトの「{}」でした。価格・network・受取先・timeout は payment-required ヘッダ（2,108〜3,996 B）にだけ入り、復号するとトップレベル5キー・accepts 7キー・amount 形式でした。9本の宣言価格は合計0.143 USDC（0.001〜0.08）、受取先は4個で、6本が同じ 0xFC24…eBB3 を Base 本番と Base Sepolia の2本立てで指定しています。404の1本は discovery に載っていても現在の経路が無い例です。当方 /check は本文33,510 Bに accepts を持ち、不正URLは課金前の400（271 B）で止まりました。",
  "検索語": "x402 check before paying",
  "読者の問い": "x402 の相手を払う前に、1回の GET で何を読めばよいのか。402 の本文が空に見えるとき、価格・受取先・ネットワークはどこにあり、どこまでを「確認できた」と言えるのか。",
  "実測日": "2026-10-21 JST",
  "実測": {
    "caption": "第三者の x402 10本を無課金GETで測った結果（2026-10-21 JST・各2回）",
    "columns": [
      "相手（経路）",
      "応答",
      "本文",
      "payment-required",
      "宣言価格",
      "network",
      "受取先"
    ],
    "rows": [
      [
        "sol.blockrun.ai/api/v1/chat/completions",
        "402 ×2",
        "2,994〜2,995 B",
        "3,992〜3,996 B",
        "0.001 USDC",
        "Solana",
        "AQqn…EeKA"
      ],
      [
        "intel.rallylive.ca/data/crypto",
        "402 ×2",
        "2 B（{}）",
        "2,244 B",
        "0.01 USDC",
        "Base + Sepolia",
        "0xFC24…eBB3"
      ],
      [
        "email.intel.rallylive.ca/email/hosted-by/startmail",
        "402 ×2",
        "2 B（{}）",
        "2,284 B",
        "0.01 USDC",
        "Base + Sepolia",
        "0xFC24…eBB3"
      ],
      [
        "data.intel.rallylive.ca/data/weather/bristol",
        "402 ×2",
        "2 B（{}）",
        "2,480 B",
        "0.01 USDC",
        "Base + Sepolia",
        "0xFC24…eBB3"
      ],
      [
        "dns.intel.rallylive.ca/dns/host/community/aaaa",
        "402 ×2",
        "2 B（{}）",
        "2,268 B",
        "0.01 USDC",
        "Base + Sepolia",
        "0xFC24…eBB3"
      ],
      [
        "apiv2.laevitas.ch/api/v1/options/:var1",
        "404 ×2",
        "83 B",
        "なし",
        "—",
        "—",
        "—"
      ],
      [
        "site.intel.rallylive.ca/site/uses/make",
        "402 ×2",
        "2 B（{}）",
        "2,372 B",
        "0.01 USDC",
        "Base + Sepolia",
        "0xFC24…eBB3"
      ],
      [
        "api.chaink9.com/feed",
        "402 ×2",
        "2 B（{}）",
        "2,548 B",
        "0.002 USDC",
        "Base",
        "0x4724…ec07"
      ],
      [
        "dev.intel.rallylive.ca/dev/pypi/aiohttp",
        "402 ×2",
        "2 B（{}）",
        "2,108 B",
        "0.01 USDC",
        "Base + Sepolia",
        "0xFC24…eBB3"
      ],
      [
        "mpp.hyreagent.fun/trenches/new-tokens",
        "402 ×2",
        "1,535 B",
        "832 B",
        "0.08 USDC",
        "Solana",
        "7G73…yGgC"
      ]
    ],
    "note": "本文とヘッダのバイト数は2回の実測値。価格はヘッダの amount を USDC（6桁）として読んだ値で、実際に支払って200本文は取得していません。Base は eip155:8453、Sepolia は eip155:84532。同じ相手の2回の応答は、sol の本文が2,994 Bと2,995 Bで1 Bだけ違った以外は同一 SHA-256 でした（7本の「{}」は全て 44136fa3…）。"
  },
  "見出し": [
    "結論",
    "実測：10本のうち7本は本文が「{}」",
    "本文が空でも、ヘッダには全部書いてある",
    "価格と受取先：9本で0.143 USDC・受取先は4個",
    "404が1本：一覧に載っている＝今も売っている、ではない",
    "当方 /check は本文に条件を返す（比較）",
    "払う前のチェック手順（これを順に）",
    "できないこと・未確認",
    "次の一歩"
  ],
  "本文": [
    {
      "見出し": "結論",
      "html": "<p><strong>x402 の相手を払う前に見るべきは、402 の本文ではなく <code>payment-required</code> ヘッダです。</strong>discovery から別ホストの10本を選び、支払わずに2回ずつ GET したところ、<strong>9本が402・1本が404</strong>。402 のうち<strong>7本は本文がわずか2バイトの <code>{}</code></strong> で、<code>JSON.parse</code> は成功するのに <code>accepts</code> がありません。</p><p>価格・network・受取先・timeout は、<strong>ヘッダ（2,108〜3,996 B）を Base64 復号した JSON にだけ</strong>入っていました。7本の「空の本文」に対してヘッダは合計 <strong>16,304 B</strong>、本文は合計 <strong>14 B</strong>。本文だけを読む買い手は、<strong>生きている相手を「価格が読めない」と誤判定する</strong>か、逆に条件を確かめずに払うことになります。</p><p>確認の最小手順は、<strong>①同じ URL を2回 GET する ②status が402なら本文とヘッダの両方を保存する ③ヘッダを復号して amount・network・payTo・maxTimeoutSeconds を読む ④本文の accepts と食い違わないか比べる ⑤404/5xx は「一覧に載っている＝今も売っている」とみなさない</strong>の5つです。</p>"
    },
    {
      "見出し": "実測：10本のうち7本は本文が「{}」",
      "html": "<table>\n<thead><tr><th>相手（経路）</th><th>応答</th><th>本文</th><th>ヘッダ</th><th>宣言価格</th><th>network</th><th>受取先</th></tr></thead>\n<tbody>\n<tr><td><code>sol.blockrun.ai/api/v1/chat/completions</code></td><td>402 ×2</td><td>2,994〜2,995 B</td><td>3,992〜3,996 B</td><td>0.001 USDC</td><td>Solana</td><td><code>AQqn…EeKA</code></td></tr>\n<tr><td><code>intel.rallylive.ca/data/crypto</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,244 B</td><td>0.01 USDC</td><td>Base + Sepolia</td><td><code>0xFC24…eBB3</code></td></tr>\n<tr><td><code>email.intel.rallylive.ca/email/hosted-by/startmail</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,284 B</td><td>0.01 USDC</td><td>Base + Sepolia</td><td><code>0xFC24…eBB3</code></td></tr>\n<tr><td><code>data.intel.rallylive.ca/data/weather/bristol</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,480 B</td><td>0.01 USDC</td><td>Base + Sepolia</td><td><code>0xFC24…eBB3</code></td></tr>\n<tr><td><code>dns.intel.rallylive.ca/dns/host/community/aaaa</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,268 B</td><td>0.01 USDC</td><td>Base + Sepolia</td><td><code>0xFC24…eBB3</code></td></tr>\n<tr><td><code>apiv2.laevitas.ch/api/v1/options/:var1</code></td><td>404 ×2</td><td>83 B</td><td>なし</td><td>—</td><td>—</td><td>—</td></tr>\n<tr><td><code>site.intel.rallylive.ca/site/uses/make</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,372 B</td><td>0.01 USDC</td><td>Base + Sepolia</td><td><code>0xFC24…eBB3</code></td></tr>\n<tr><td><code>api.chaink9.com/feed</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,548 B</td><td>0.002 USDC</td><td>Base</td><td><code>0x4724…ec07</code></td></tr>\n<tr><td><code>dev.intel.rallylive.ca/dev/pypi/aiohttp</code></td><td>402 ×2</td><td>2 B（<code>{}</code>）</td><td>2,108 B</td><td>0.01 USDC</td><td>Base + Sepolia</td><td><code>0xFC24…eBB3</code></td></tr>\n<tr><td><code>mpp.hyreagent.fun/trenches/new-tokens</code></td><td>402 ×2</td><td>1,535 B</td><td>832 B</td><td>0.08 USDC</td><td>Solana</td><td><code>7G73…yGgC</code></td></tr>\n</tbody>\n</table>\n<p>10本の本文合計は <strong>4,627 B</strong>、ヘッダ合計は <strong>21,132 B</strong>（404の0 Bを含む）。402だけに絞ると、<strong>本文4,544 B・ヘッダ21,132 Bで、ヘッダは本文の約4.6倍</strong>あります。とくに本文が <code>{}</code> の7本は、<strong>本文14 Bに対してヘッダ16,304 B</strong>で、条件のほぼ全部がヘッダ側です。</p><p>discovery の先頭100件は <strong>200・255,055 B・1,162 ms・total 21,917</strong>。この10本は先頭から<strong>別ホスト</strong>を順に拾っただけで、無作為抽出ではありません。同じドメイン系列（<code>*.intel.rallylive.ca</code>）が6本含まれます。</p>"
    },
    {
      "見出し": "本文が空でも、ヘッダには全部書いてある",
      "html": "<p>本文 <code>{}</code> の1本（<code>intel.rallylive.ca/data/crypto</code>）の <code>payment-required</code> を復号すると、次の形でした。</p>\n<pre><code>トップレベル5キー: x402Version, error, resource, accepts, extensions\naccepts[0] の7キー: scheme, network, amount, asset, payTo, maxTimeoutSeconds, extra\namount=10000 / network=eip155:8453 / scheme=exact / maxTimeoutSeconds=120\n2つ目の accepts: 同額・同 payTo で network=eip155:84532（Base Sepolia）</code></pre>\n<p><strong>本文の <code>{}</code> は「壊れている」のではなく、「条件をヘッダにだけ置く」実装です。</strong>この場合、<code>fetch(...).json()</code> の結果に <code>accepts</code> が無いからといって相手を死んでいる扱いにすると、実際には買える経路を捨てます。逆に、本文だけ見て「価格が無い＝無料」と解釈するのはもっと危険です。</p>\n<p>9本の402はすべて <code>x402Version=2</code> で、<code>accepts</code> は<strong>7キー</strong>、価格は <code>maxAmountRequired</code> ではなく <code>amount</code> でした。当方の402本文は V1 の <code>accepts</code>（<code>maxAmountRequired</code>）なので、<strong>同じ「402」でも読むキーが違います</strong>。買い手側は V1 と V2 の両方を受ける前提でなければなりません。</p>"
    },
    {
      "見出し": "価格と受取先：9本で0.143 USDC・受取先は4個",
      "html": "<p>9本の宣言価格を合計すると <strong>0.143 USDC</strong>（0.001〜0.08）。内訳は <strong>0.01が6本</strong>、0.002・0.001・0.08が各1本です。0.01の6本は<strong>すべて同じ受取先 <code>0xFC24FD34da9e49A0110DCaEe3Ad30eC54175eBB3</code></strong>で、Base 本番と Base Sepolia の2つの accepts を持っていました。9本の受取先は<strong>4個だけ</strong>で、6本（66.7%）が1個に集中しています。</p>\n<p>Solana の2本は <code>amount</code> がそれぞれ 1,000 と 80,000。USDC の6桁精度で読むと <strong>0.001 USDC と 0.08 USDC</strong> です。EVM の Base と Solana では network 表記も asset も違うため、<strong>「金額が同じか」ではなく「どの network の何枚か」まで確認しないと、支払い先を間違えます</strong>。</p>\n<p>timeout もばらばらでした。<code>maxTimeoutSeconds</code> は 60（mpp）、120（intel 系列6本）、300（chaink9）、300と3,600（sol の2 accepts）です。<strong>3,600秒の batch-settlement は exact とは別の支払い方</strong>なので、同じ <code>accepts[0]</code> だけを見て判断すると取りこぼします。</p>"
    },
    {
      "見出し": "404が1本：一覧に載っている＝今も売っている、ではない",
      "html": "<p>10本のうち1本、<code>apiv2.laevitas.ch/api/v1/options/:var1</code> は <strong>2回とも404・83 B</strong> で、本文は <code>Cannot GET /api/v1/options/:var1</code> でした。payment-required ヘッダは付かず、402 ですらありません。discovery の一覧は<strong>掲載時点の情報</strong>で、<strong>現在の経路の存在を保証しません</strong>。</p>\n<p>ここで「404だから相手は死んでいる」と決めるのも早いです。同じホストの別パスは生きているかもしれません。買い手としてできるのは、<strong>①一覧のURLをそのまま叩く ②404ならホストのルートや別パスを1回だけ試す ③それでも402/200が返らなければ、そのURLは使わない</strong>までです。今回は1本だけでしたが、10本に1本の割合で「一覧と現物が違う」が起きた、というのが実測です。</p>"
    },
    {
      "見出し": "当方 /check は本文に条件を返す（比較）",
      "html": "<p>同じ「払う前の確認」を当方の <code>/check</code> でやると、未払い GET は <strong>402・33,510 B・613 ms</strong> で、本文に <code>accepts</code> があり、<strong>0.05 USDC（50000 atomic）・network=base</strong> と読めました。<code>payment-required</code> ヘッダも <strong>5,664 B</strong> 付きます。第三者の7本のように本文が空ではないので、<strong>本文派のクライアントでも価格を読める</strong>のが違いです。</p>\n<p>入力の検証は課金前に行われます。<code>/check?url=not-a-url</code> は <strong>400・271 B・485 ms・invalid_url</strong>、<code>/check?url=http://127.0.0.1:8080</code> は <strong>400・351 B・152 ms・blocked_target</strong>。どちらも 402 ではないので、<strong>URL の形式と行き先を確かめるだけであれば無料</strong>です。ただし、これは当方の実装の話で、第三者が同じように 400 を返すとは限りません。</p>\n<p>無料の <code>/status.json</code> は <strong>200・27,812 B・8,921 ms・73経路</strong>で、<code>/check</code> は<strong>納品5件・最終成功 2026-10-17T10:15:01Z・success_24h=0</strong>。<code>/openapi.json</code> は <strong>200・244,024 B・83 paths</strong>。納品5件は自己テストを含む可能性があり、需要の証拠ではありません。</p>"
    },
    {
      "見出し": "払う前のチェック手順（これを順に）",
      "html": "<ol>\n<li><strong>同じ URL を2回 GET する</strong>：status と本文 SHA-256 を比べる。今回は9本の402が2回とも同じ status で、7本の <code>{}</code> は同一 SHA <code>44136fa355b3678a</code> でした。</li>\n<li><strong>402なら本文とヘッダを両方保存する</strong>：本文が <code>{}</code> でも失敗にしない。ヘッダが無い場合だけ「条件なし」と判断する。</li>\n<li><strong>ヘッダを復号する</strong>：<code>payment-required</code> は Base64 の JSON。トップレベル5キーと <code>accepts</code> の7キーを読み、<code>amount</code>・<code>network</code>・<code>payTo</code>・<code>maxTimeoutSeconds</code> を取る。</li>\n<li><strong>本文の accepts と突き合わせる</strong>：両方あるのに金額・network・payTo が違うなら、どちらが正か分からない。支払わずに保留する。</li>\n<li><strong>network と asset を確認する</strong>：Base 本番（eip155:8453）か Sepolia（eip155:84532）か、Solana か。同じ USDC でも送金先が違う。</li>\n<li><strong>404/5xx は一覧の在庫と切り分ける</strong>：ホストのルートや別パスを1回だけ試し、それでも返らなければ使わない。</li>\n<li><strong>200 が返ったらラッキー、とは考えない</strong>：無料で200が返る経路は、402の条件を確かめられていない。有料本文の形は、支払うまで分からない。</li>\n</ol>\n<p>この手順は、当方の <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/check\"><code>/check</code></a>（0.05 USDC）を買う前の下調べにも、第三者の経路を自分で確かめるのにも同じように使えます。<strong>1回の GET の status だけを見て「生きている／死んでいる」を決めない</strong>のが、今回の実測から言える最小限です。</p>"
    },
    {
      "見出し": "できないこと・未確認",
      "html": "<ul>\n<li><strong>有料の200本文は取得していません</strong>（支払っていない）。返ってくるデータの形・正しさ・納品の有無は未確認です。</li>\n<li><strong>10本は無作為抽出ではありません</strong>。discovery 先頭100件から別ホストを順に拾ったもので、同じドメイン系列が6本を占めます。市場全体の分布ではありません。</li>\n<li><strong>402の本文が <code>{}</code> だった理由</strong>（実装の違い、CDN、facilitator の差）は未特定です。同じ相手でもパスや時間帯で変わる可能性は否定できません。</li>\n<li><strong>404の1本が一時的なものか</strong>は未確認です。今回は2回とも404でしたが、復活する可能性はあります。</li>\n<li><strong>429・5xx・タイムアウトの挙動</strong>は今回は観測していません。応答時間は各回1回の実測で、時間帯により変動します。</li>\n<li><strong>受取先のオンチェーン種別（EOA/コントラクト）</strong>は今回は調べていません。アドレスの集中度は測りましたが、同じ運営者かどうかは未確認です。</li>\n</ul>"
    },
    {
      "見出し": "次の一歩",
      "html": "<p>402 の読み方と生存確認は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/is-x402-endpoint-alive\"><code>/ja/is-x402-endpoint-alive</code></a>、買う順序は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/x402-usage\"><code>/ja/x402-usage</code></a>、変更検知は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/api-breaking-change-detector\"><code>/ja/api-breaking-change-detector</code></a> に実測でまとめています。市場の受取先分布は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/where-can-an-agent-receive-usdc\"><code>/ja/where-can-an-agent-receive-usdc</code></a>、価格分布は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/x402-price-benchmark\"><code>/ja/x402-price-benchmark</code></a>。無料データは <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/data.json\"><code>/data.json</code></a>、当方の宣言は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/product.json\"><code>/product.json</code></a>、納品記録は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/status.json\"><code>/status.json</code></a> で読めます。</p>"
    }
  ],
  "一覧": "https://x402-catalog-history.ai-business-surface.workers.dev/ja"
}
