{
  "lang": "ja",
  "ページ": "https://x402-catalog-history.ai-business-surface.workers.dev/ja/api-breaking-change-detector",
  "title": "api breaking change detector — 4経路を無課金で当てる（400/402 の境界と 0.08 USDC の実測）",
  "h1": "API の破壊的変更を、壊れる前に検知する — 4経路を払わずに測る",
  "description": "api breaking change detector を自作する前に、検知の入口を無課金で測りました。2026-10-19 に /compat-check・/compat・/changes・/contract へ支払いなしで計8回投げ、8回すべて 402・宣言価格は各 0.02 USDC（合計 0.08）。不正入力は /compat-check・/contract・/changes が課金前に 400 で止め、/compat は JSON 構文だけを見て意味の不正は 402 のまま通りました。無料の /contract/sample（200・2,679 B）は出力契約の弱点まで返します。",
  "検索語": "api breaking change detector",
  "読者の問い": "API の変更で自分の連携が壊れるのを、支払う前にどこまで検知できるのか。",
  "実測日": "2026-10-19 JST",
  "実測": {
    "caption": "破壊的変更の検知経路（2026-10-19 JST・公開URLへの支払いなしリクエスト・各2回）",
    "columns": [
      "経路",
      "方法",
      "2回の応答",
      "本文（2回とも同一）",
      "payment-required",
      "応答時間",
      "宣言価格（USDC）"
    ],
    "rows": [
      [
        "/compat-check",
        "GET ?url=",
        "402 / 402",
        "27,357 B",
        "5,728 B",
        "683 / 445 ms",
        "0.02"
      ],
      [
        "/compat",
        "POST JSON",
        "402 / 402",
        "21,172 B",
        "3,120 B",
        "306 / 154 ms",
        "0.02"
      ],
      [
        "/changes",
        "GET ?from=&to=",
        "402 / 402",
        "20,238 B",
        "2,804 B",
        "283 / 161 ms",
        "0.02"
      ],
      [
        "/contract",
        "GET ?url=",
        "402 / 402",
        "26,872 B",
        "5,528 B",
        "288 / 187 ms",
        "0.02"
      ]
    ],
    "note": "4経路・8回すべて 402。本文は経路ごとに2回とも同一バイト数・同一 SHA-256（先頭16桁で比較）。本文の合計は 95,639 B、payment-required ヘッダの合計は 17,180 B、宣言価格の合計は 0.08 USDC（支払っておらず、すべて未課金の宣言値）。速い2回目は 154〜445 ms で、初回の 683 ms は Cloudflare のコールドスタートを含む可能性があり未分離。"
  },
  "見出し": [
    "結論",
    "実測",
    "無料で止まる境界",
    "検知器そのものが「契約の弱さ」を返す",
    "支払い実績は別の面で見る",
    "この実測で分からないこと",
    "次の一歩"
  ],
  "本文": [
    {
      "見出し": "結論",
      "html": "<p>破壊的変更の検知は、<strong>「無料で止まる入力検証」→「402 の宣言」→「有料の差分・互換レポート」</strong>の3層に分かれます。今回測った4経路はどれも<strong>未払いでは 402</strong> を返し、宣言価格は<strong>4本とも 0.02 USDC</strong>でした。つまり<strong>検知の中身は買うまで返りません</strong>が、<strong>入口が正しいか・課金前に何を弾くか</strong>は無料で確かめられます。</p><p>実測で差が出たのは<strong>不正入力の扱い</strong>です。<code>/compat-check</code>・<code>/contract</code>・<code>/changes</code> は壊れた入力を<strong>課金前に 400</strong> で返しました。一方 <code>/compat</code> は<strong>JSON として壊れている場合だけ 400</strong> で、<code>schema</code> が正しい JSON Schema でなくても<strong>402 のまま</strong>通りました。<strong>「無料で弾かれる」と期待してパイプラインを組むと、/compat だけ課金されてから失敗します</strong>。</p>"
    },
    {
      "見出し": "実測",
      "html": "<table>\n<thead><tr><th>経路</th><th>方法</th><th>2回の応答</th><th>本文（2回とも同一）</th><th>payment-required</th><th>応答時間</th><th>宣言価格（USDC）</th></tr></thead>\n<tbody>\n<tr><td><code>/compat-check</code></td><td>GET <code>?url=</code></td><td>402 / 402</td><td>27,357 B</td><td>5,728 B</td><td>683 / 445 ms</td><td>0.02</td></tr>\n<tr><td><code>/compat</code></td><td>POST JSON</td><td>402 / 402</td><td>21,172 B</td><td>3,120 B</td><td>306 / 154 ms</td><td>0.02</td></tr>\n<tr><td><code>/changes</code></td><td>GET <code>?from=&amp;to=</code></td><td>402 / 402</td><td>20,238 B</td><td>2,804 B</td><td>283 / 161 ms</td><td>0.02</td></tr>\n<tr><td><code>/contract</code></td><td>GET <code>?url=</code></td><td>402 / 402</td><td>26,872 B</td><td>5,528 B</td><td>288 / 187 ms</td><td>0.02</td></tr>\n</tbody>\n</table>\n<p>同時刻の無料面は <code>/openapi.json</code> <strong>200・175,454 B・168 ms・58 paths</strong>、<code>/product.json</code> <strong>200・683,011 B・385 ms</strong>、<code>/contract/sample?url=…</code> <strong>200・2,679 B・151 ms</strong>、<code>/health</code> <strong>200・2,089 B・163 ms</strong>、<code>/status.json</code> <strong>200・22,156 B・7,869 ms</strong> でした。status.json の初回は他より2桁近く遅く、これは集計処理のコストで、経路の生死とは別です。</p><p>402 の形は4経路とも同じで、本文 <code>x402Version=1</code>・<code>accepts[0]</code> は<code>scheme / network / maxAmountRequired / resource / description / mimeType / payTo / maxTimeoutSeconds / asset / extra</code> の<strong>10項目</strong>、<code>maxAmountRequired=20000</code>（6桁で 0.02 USDC）、<code>network=base</code>、<code>maxTimeoutSeconds=60</code>。ヘッダ側は V2 表記です。</p>"
    },
    {
      "見出し": "無料で止まる境界",
      "html": "<p>支払いを伴わない不正入力を7通り投げました。結果は<strong>5件が 400（本文 126〜570 B・132〜156 ms）</strong>、<strong>2件が 402</strong> です。</p>\n<table>\n<thead><tr><th>送ったもの</th><th>応答</th><th>本文</th><th>応答時間</th><th>error</th></tr></thead>\n<tbody>\n<tr><td><code>/compat-check?url=not-a-url</code></td><td>400</td><td>271 B</td><td>147 ms</td><td><code>invalid_url</code></td></tr>\n<tr><td><code>/compat-check?url=http://127.0.0.1:8080/x</code></td><td>400</td><td>351 B</td><td>147 ms</td><td><code>blocked_target</code>（<code>loopback_address</code>）</td></tr>\n<tr><td><code>/contract?url=not-a-url</code></td><td>400</td><td>271 B</td><td>156 ms</td><td><code>invalid_url</code></td></tr>\n<tr><td><code>/changes?from=2026-99-99&amp;to=2026-01-01</code></td><td>400</td><td>570 B</td><td>132 ms</td><td><code>invalid_period</code></td></tr>\n<tr><td><code>POST /compat</code>（<code>{not json</code>）</td><td>400</td><td>126 B</td><td>139 ms</td><td><code>invalid_json</code></td></tr>\n<tr><td><code>POST /compat</code>（<code>schema:\"nope\"</code>）</td><td><strong>402</strong></td><td>21,172 B</td><td>151 ms</td><td>—（課金宣言）</td></tr>\n<tr><td><code>POST /compat</code>（<code>schema:{type:\"object\"}</code>）</td><td><strong>402</strong></td><td>21,172 B</td><td>163 ms</td><td>—（正常）</td></tr>\n</tbody>\n</table>\n<p>つまり <code>/compat</code> の課金前検証は<strong>「UTF-8 の JSON オブジェクトか」まで</strong>で、<code>schema</code> が JSON Schema として意味を持つかは見ていません。<strong>自分の連携では、課金前に自分の側で <code>schema</code> の型を検査する</strong>のが安全です。<code>additionalProperties</code> や <code>required</code> の綴り間違いは 402 を通り、0.02 USDC を払った後に <code>unsupported_input</code> になり得ます（この先の応答は未確認）。</p><p>なお <code>/compat-check</code> は URL の形式だけでなく<strong>ループバック宛を課金前に拒否</strong>しました。SSRF 対策としては妥当ですが、<strong>社内ホストの互換性を測りたい買い手は、この経路では測れない</strong>という制約にもなります。</p>"
    },
    {
      "見出し": "検知器そのものが「契約の弱さ」を返す",
      "html": "<p>無料の <code>/contract/sample?url=…</code> は <strong>200・2,679 B・18項目</strong>を返し、出力契約の<strong>弱点まで宣言</strong>します。当方の <code>/gas</code> を対象にした実測では <code>error_shape_declared=false</code>、<code>weakness[0].code=declared_fields_are_schema_keywords</code> でした。内容は<strong>「<code>properties</code> が納品の実フィールド名ではなく JSON Schema のキーワード（<code>type</code>・<code>example</code>）で埋まっている」</strong>という指摘です。</p><p>これは検知器の使い方に直結します。<strong>変更前後で <code>properties</code> を比べれば差分は出ますが、その差分が「利用者が使うフィールドの変更」とは限らない</strong>からです。<strong>契約が弱い相手では、契約の差分だけを破壊的変更の証拠にしない</strong>のがよく、<strong>実際の 200 の本文（買った納品）と突き合わせる</strong>必要があります。</p><p>サンプルは無料なので、<strong>本番の検知を組む前に、対象の契約がどの程度「読める」かを 1 回 0 円で確認できます</strong>。18項目のうち <code>sample</code> と <code>sample_note</code> が無料部分で、<code>paid_route</code> と <code>sample_source</code> が購入先を示します。</p>"
    },
    {
      "見出し": "支払い実績は別の面で見る",
      "html": "<p>無料の <code>/status.json</code>（22,156 B）で4経路の納品記録を見ると、<code>/compat</code> <strong>2件</strong>（最終 2026-10-13）、<code>/compat-check</code> <strong>1件</strong>（最終 2026-10-15）、<code>/contract</code> <strong>2件</strong>（最終 2026-10-17）、<code>/changes</code> は <strong>0件</strong>（<code>data_status=no_data</code>）でした。4本とも 402 は返りますが、<strong>買われた回数は同じではありません</strong>。</p><p><strong>402 が返る＝検知が実績あり、ではありません</strong>。検知器を選ぶときは、<strong>「今払えるか」を 402 で、「過去に納品されたか」を /status.json で</strong>分けて見てください。</p>"
    },
    {
      "見出し": "この実測で分からないこと",
      "html": "<ul>\n<li><strong>有料の 200 本文は未取得</strong>。支払い・SMS・KYC を伴う操作はしていないため、<code>/compat-check</code> の <code>verdict</code> や <code>/changes</code> の <code>events[]</code> の中身・精度・鮮度は未確認です。数字はすべて「400 が返るところ、402 が返るところ、無料の 200 が返るところ」までです。</li>\n<li><strong>5xx・タイムアウトは今回取得できず</strong>、判定不能の扱いは一般論です。</li>\n<li><strong>応答時間は同時刻の反復計測ではなく</strong>、公開URLへの逐次リクエストの wall clock です。コールドスタートの影響は分離していません。</li>\n<li><strong>検索順位は未測定</strong>。この記事は検索語 <code>api breaking change detector</code> をタイトルに置いただけで、順位は測っていません。</li>\n</ul>"
    },
    {
      "見出し": "次の一歩",
      "html": "<p>課金前に何を弾くかの全体は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/ja/x402-usage\"><code>/ja/x402-usage</code></a>、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>、スキーマ変更の4経路は <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/ja/catalog-diff\"><code>/ja/catalog-diff</code></a> に実測でまとめています。仕様の全体は <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/openapi.json\"><code>/openapi.json</code></a>（58 paths）、出力契約の無料サンプルは <a href=\"https://x402-catalog-history.ai-business-surface.workers.dev/contract/sample\"><code>/contract/sample</code></a> で読めます。</p>"
    }
  ],
  "一覧": "https://x402-catalog-history.ai-business-surface.workers.dev/ja"
}
