Skip to main content
業務自動化

ドキュメントに載っていないAPIの仕様は、どう調べるのか

外部サービスと連携するとき、必要な情報が公開ドキュメントに載っていないことがあります。応答コードとトークンの中身から、接続先・認可の範囲・指定方法を絞り込む手順を説明します。

モニタに表示されたプログラムのコード
Photo: Al Nahian / Pexels

以下は2026年8月時点で確認した挙動です。

外部サービスのAPIに繋ごうとして、接続先のURLもリクエストの形も公開情報から分からないことがあります。マネーフォワード クラウド会計のAPIで仕訳の登録を自動化した作業がこれでした。技術サポートの窓口は士業事務所向けに限られ、問い合わせ先もありません。

行き詰まりの本体は、情報が無いことではありません。当てずっぽうで叩くと、動かない原因がURLの誤りなのか、認証が通っていないのか、権限が足りないのか、パラメータが違うのかを切り分けられません。どれも「エラーが返る」としか見えないので、直す場所が決まらないまま時間が溶けます。推測のまま設計を書き切れば、実物と食い違ったときに丸ごと書き直しになります。

切り分けの道具は、API自身が返します。この記事では、応答から記載のない仕様と権限の状態を絞り込む手順を説明します。要点は3つです。

  • 401 が返れば、ホスト名は当たっています。404 は無いことの証明になりません
  • 認可が成功しても、要求した権限が付いたとは限りません。エラー文よりトークンの中身が速いです
  • 何も作成しない 400 を使えば、リクエスト本文の形をAPIに教えてもらえます

応答コードの違いが、そこに何があるかを教えます

応答コードの意味はRFC 9110が定めています[1]。下の行ほど、リクエストは深くまで届いています。

コード 仕様上の意味 探索での読み方
404 対象が見つからない 不在の証明にならない
401 有効な認証情報を欠く ホスト名が当たっている印
403 理解したうえで実行を拒否 認証を通過し、権限で止まった
400 クライアント側の誤り 権限も通り、パラメータだけ違う

第一段で効くのは 401 です。認証の判定が返るのは、リクエストが認証の層まで届いたからです。ただし、認証を入口で一律に処理する構成では、存在しないパスにも 401 が返ります。

404 だけは逆に読めません。RFC 9110は、在る資源を隠すために 404 を返してよいと定めています[1]。

接続先は、返るコードを見比べて絞り込めます

候補のどれが正しいかを教える情報源はありません。認証のチュートリアルに載っていたのは別サービスのホスト名だけでした。そこで、ありそうなホスト名を並べ、同じ経路に同じリクエストを投げました。どの経路でも 404 を返す側と 401 を返す側に割れました。違いはハイフンの有無だけでした。

トークンをデコードするほうが、エラー文を読むより速いです

APIキーをトークンに交換する処理は成功しました。ところが目的のAPIは 401 を返し、トークンが有効でないという文面が返ります。この文面では、期限切れ・形式の誤り・権限不足を区別できません。

決め手はペイロードのデコードでした。使われていたのはJWTで、権限や発行者などの情報をJSONで書き、URLで運べる形に符号化したトークンです[2]。署名だけの形式なので、鍵がなくても読めます。デコードすると、トークンが有効なサービスを列挙したクレームに、目的のサービスが入っていません。

認可の成功は、要求が通ったことを意味しません

認可画面を通りトークンも手元にあるなら、権限は付いていると考えるのが自然です。この前提が崩れます。権限の委譲はOAuth 2.0で行い、範囲はスコープと呼ぶ空白区切りの文字列です。RFC 6749の §3.3 は、認可サーバが要求されたスコープを全部または一部無視してよいと定めています[3]。付与した範囲が要求と異なる場合は scope パラメータで伝えなければならない、とも定めています。

検証では、スコープ名を複数形で綴り間違えたまま要求しました。認可は成功しました。付与された一覧から、その名前だけが消えていました。存在しない権限名は、誤りとして返らず、単に無視されます。

対策は、トークン取得の直後に差分を取ることです。

requested = set(scopes.split())
dropped = sorted(requested - set(granted.split()))

dropped が空でなければ警告を出して止めます。この検査がなければ、綴り間違いは後の権限エラーになります。

エラーメッセージの主語を疑います

権限が足りないというエラーは、どの主体の話なのかを書いているとは限りません。返ってきた本文は、アクセスされている事業者に十分な権限がない、と読めるものでした。この主語に従えば、疑う先は契約や事業者の設定です。実際の原因はトークンのスコープ不足でした。

RFC 6750 は、トークンの権限が足りない場合のエラーを insufficient_scope と定め、403 を推奨しています。ただし 403 は権限以外の理由でも返り、どの主体の権限が足りないかも区別しません。権限の主体はトークン・利用者・事業者に分かれます。3つを別々に確かめます。

送るべき形は、失敗する 400 が教えてくれます

送るキーの名前が分からなければ、総当たりすら組めません。候補を順に投げ、最初に受理されたもので止められます。条件は、失敗が副作用を残さないことだけです。400 で止まったリクエストは何も作成しません。

1回目の応答が道標になります。

400 missing_required_request_body_key: Target: account_id
  • 足りないキーの名前が返り、埋めて投げ直すと次が返ります
  • ネストした構造は拒否され、受理されたのはフラットな本文でした

この手順は、成功すると取り消せない操作には使えません。その場合の設計は「取り消せない操作を含む処理は、どう自動化するのか」で説明しています。

429 を「データの終わり」と読むと、取りこぼします

切り分けを誤ると、失敗が正常終了に化けます。一覧を取得する経路は、結果をページ単位で返します。連続して取ると 429 が返ります。単位時間あたりのリクエストが多すぎることを示すコードで、RFC 6585が定義しています[4]。

配列が空になったらループを抜ける実装だと、事故になります。429 の応答本文に目的の配列は入っていないため、空と判定されてループは正常に終了します。取りこぼしても「全部取れた」と見えます。非200を必ず例外にし、終端の判定を中身に任せません。

まとめ

  • 401 はホスト名が当たっている印、400 は経路に届いた印です。404 は無いことの証明になりません[1]
  • 調査はエラー文より、トークンのデコードと付与スコープの差分から始めます[2,3]
  • 429 は本文だけ見ると空に見えます。応答コードを先に見ないと取りこぼします[4]

参考文献

  1. RFC 9110 — HTTP Semantics, Status Codes
  2. RFC 7519 — JSON Web Token (JWT)
  3. RFC 6749 — The OAuth 2.0 Authorization Framework, Section 3.3 Access Token Scope
  4. RFC 6585 — Additional HTTP Status Codes
LET'S START TOGETHER

Ready to
Design Your Voice?

法人向け受託開発から、コンシューマーアプリの導入相談まで。まずはお気軽にお問い合わせください。