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

以下は2026年8月時点で確認した挙動です。
外部サービスのAPIに繋ごうとして、接続先のURLもリクエストの形も公開情報から分からないことがあります。マネーフォワード クラウド会計のAPIで仕訳の登録を自動化した作業がこれでした。技術サポートの窓口は士業事務所向けに限られ、問い合わせ先もありません。
行き詰まりの本体は、情報が無いことではありません。当てずっぽうで叩くと、動かない原因がURLの誤りなのか、認証が通っていないのか、権限が足りないのか、パラメータが違うのかを切り分けられません。どれも「エラーが返る」としか見えないので、直す場所が決まらないまま時間が溶けます。推測のまま設計を書き切れば、実物と食い違ったときに丸ごと書き直しになります。
切り分けの道具は、API自身が返します(応答の形や挙動はサービスごとに異なります)。
- 応答コードは確定診断ではなく、候補間の応答差から仮説を立てる手がかりになります。
404は無いことの証明になりません - 認可が成功しても、要求した権限が付いたとは限りません。エラー文よりトークンの中身が速いです
- 検証で弾かれる
400応答から、リクエスト本文の形を読み取れることがあります(更新系では安全条件の確認が先です)
応答コードの違いが、そこに何があるかを教えます
応答コードの意味はRFC 9110が定めています[1]。ただし仕様は「どの処理段階まで届いたか」を保証しません。下の表の右列は、同じ条件で候補を比べたときの差から立てる、このAPIでの読み方(仮説)です。
| コード | 仕様上の意味[1] | このAPIでの読み方(観測に基づく仮説) |
|---|---|---|
404 |
対象が見つからない | 不在の証明にならない |
401 |
有効な認証情報を欠く | 認証処理まで届いた可能性 |
403 |
理解したうえで実行を拒否 | 認証は通り、権限で止まった可能性 |
400 |
クライアント側の誤り | 本文の形まで検証された可能性 |
第一段で効くのは 401 です。認証の判定が返るのは、リクエストが認証の層まで届いたからです。ただし、認証を入口で一律に処理する構成では、存在しないパスにも 401 が返ります。
404 だけは逆に読めません。RFC 9110は、在る資源を隠すために 404 を返してよいと定めています[1]。
接続先は、返るコードを見比べて絞り込めます
候補のどれが正しいかを教える情報源はありません。認証のチュートリアルに載っていたのは別サービスのホスト名だけでした。そこで、ありそうなホスト名を並べ、同じ経路に同じリクエストを投げました。どの経路でも 404 を返す側と 401 を返す側に割れました。違いはハイフンの有無だけでした。
トークンをデコードするほうが、エラー文を読むより速いです
APIキーをトークンに交換する処理は成功しました。ところが目的のAPIは 401 を返し、トークンが有効でないという文面が返ります。この文面では、期限切れ・形式の誤り・権限不足を区別できません。
決め手はペイロードのデコードでした。使われていたのはJWTで、権限や発行者などの情報をJSONで書き、URLで運べる形に符号化したトークンです[2]。JWTには暗号化された形式もありますが、このトークンは暗号化されていない署名つきの形式(JWS)だったため、ペイロードは鍵がなくても読めます。読めることと信頼できることは別で、判断に使うときは発行者・署名・期限の検証を別に行います。デコードすると、トークンが有効なサービスを列挙したクレームに、目的のサービスが入っていません。
認可の成功は、要求が通ったことを意味しません
認可画面を通りトークンも手元にあるなら、権限は付いていると考えるのが自然です。この前提が崩れます。権限の委譲は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 を推奨しています[5]。ただし 403 は権限以外の理由でも返り、どの主体の権限が足りないかも区別しません。権限の主体はトークン・利用者・事業者に分かれます。3つを別々に確かめます。
送るべき形は、失敗する 400 が教えてくれます
送るキーの名前が分からなければ、総当たりすら組めません。候補を順に投げ、最初に受理されたもので止められます。ただし、400 が返ることは副作用がないことの保証ではありません。この探索を使ってよいのは、検証用の環境や帳簿で試せる、実行後に状態を確認できる、といった安全条件を確保できる場合に限ります。今回は、400 で拒否されたリクエストが何も作成していないことを、一覧の再取得で確かめながら進めました。
1回目の応答が道標になります。
400 missing_required_request_body_key: Target: account_id
- 不足しているキーの名前が返ります。
account_idを加えて再送し、別の不足キーが返れば同じ手順を繰り返します - ネストした構造は拒否され、受理されたのはフラットな本文でした
この手順は、成功すると取り消せない操作には使えません。その場合の設計は 取り消せない操作を含む処理は、どう自動化するのか に記載しています。
なお、応答コードを先に見る習慣は、探索が終わったあとの実装でも効きます。一覧取得で 429(リクエスト過多[4])が返ったとき、本文の配列が空だからと正常終了させると、取りこぼしが「全部取れた」に化けます。非200は必ず例外にし、終端の判定を中身に任せないことです。
調べる順序は、接続先、認証と認可、リクエスト本文の3段階です。どの段階でも、確定診断をくれる応答はありません。同じ条件で比べた応答の差から仮説を立て、安全に試せる方法で確かめて、実測になった事実だけを設計に書く。それが、ドキュメントのないAPIとの付き合い方でした。