Claude Media
Claude apps gatewayで開発者ごとの支出上限を設定する

Claude apps gatewayで開発者ごとの支出上限を設定する

Claude apps gatewayのAdmin APIで開発者・グループ・組織ごとに日/週/月の支出上限を設定し、429応答の中身と実際の料金計算まで一次ソースで確かめます。

支出上限は何を防ぐ仕組みか

Claude apps gatewayを通る推論リクエストは、すべて1つの共有アップストリーム認証情報を経由します。BedrockでもGoogle Cloud's Agent Platformでも、プロバイダーの請求はこの共有クレデンシャルにまとめて計上され、どの開発者がいくら使ったかはプロバイダー側の請求書には出てきません。暴走したエージェントのフリートが1つ動くだけで、組織のコミット枠を丸ごと食いつぶす構図です。

支出上限(spend limits)は、この共有請求の上に載る開発者単位の監視と遮断です。開発者・IdPグループ・組織全体の3段階で、日/週/月ごとの上限額を設定できます。上限を超えた開発者は次のリクエストで429を受け取り、期間がリセットされるか管理者が上限を引き上げるまでブロックされます。基本のセットアップがまだの場合は先にそちらでOIDCとPostgresを用意してから、本記事の設定を追加してください。

Admin APIで上限を設定する

gateway.yamladmin:ブロックを設定すると、ゲートウェイは/v1/organizations/spend_limitsにAdmin APIを公開し、以降すべての推論リクエストでライブに上限を強制します。上限そのものはgateway.yamlにではなくこのAPI経由で設定するもので、POST /v1/organizations/spend_limits{scope, amount, period}から上限を1件作成または置き換えます。このAPIはAnthropic公式のAdmin API(支出上限エンドポイント)とワイヤ形式を揃えているため、そのAPI向けに書いたHTTPクライアントはベースURLを変えるだけでゲートウェイにも向けられます。

組織全体に月500ドルの既定上限をかける例です。

curl -sS https://claude-gateway.internal.example.com/v1/organizations/spend_limits \
  -H "x-api-key: $GATEWAY_ADMIN_WRITE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scope": {"type": "organization"}, "amount": "50000", "period": "monthly"}'

contractorsグループのメンバーだけに、日100ドルというより厳しい上限を重ねる例です。

curl -sS https://claude-gateway.internal.example.com/v1/organizations/spend_limits \
  -H "x-api-key: $GATEWAY_ADMIN_WRITE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scope": {"type": "rbac_group", "rbac_group_id": "contractors"}, "amount": "10000", "period": "daily"}'
フィールド説明
scope.typeuser / rbac_group / organization説明userはIdPが割り当てるOpenID Connect(OIDC)のsubscope.user_idに渡して1人を指定。rbac_groupはIdPグループ名をscope.rbac_group_idに。organizationは組織全体の既定値。ゲートウェイは3種すべてを受け付けるが、Anthropic公式APIの公開POSTが対応するのはuserのみ
amountUSDセント単位の整数文字列、またはnull説明nullは無制限、"0"はすべてのリクエストを止めるゼロ上限
perioddaily / weekly / monthly説明1つのscopeは期間ごとに1件の上限を持て、それぞれ独立して効く。いずれか1つでも超えていればブロックされる

グループ上限や組織上限は共有プールではなく、メンバー1人あたりの既定値です。期間ごとに実際に効く上限は、ユーザー個別の上書き → 該当するグループ上限のうち最も厳しいもの → 組織の既定値 → 無制限、の順で解決されます。admin.group_limit_mode: maxを設定すると、複数グループにまたがる場合のタイブレークが最も緩いグループを採用する向きに反転します。

認証方法とキーの使い分け

Admin APIへの認証は2系統です。1つはx-api-keyヘッダーで、admin.write_keysに登録したキーなら書き込みを含む全操作、admin.read_keysに登録したキーならGET専用の読み取り権限になります。TerraformやCI、監視ダッシュボードのように参照だけで足りる自動化には、書き込み権限のないadmin.read_keysのキーを割り当てるのが安全です。キーはそれぞれidを持ち、監査ログにadmin-key:<id>として記録されるため、用途ごとに別のキーを発行すれば、どの自動化がいつ何を変更または参照したかを追えます。もう1つはadmin.admin_groupsのクレームを持つゲートウェイのベアラートークンで、こちらは常に全権限になり監査ログにはoidc:<sub>として記録されます。人間の管理者にはこちらを使うのが基本です。

上限に達するとどうなるか

/v1/messagesへのリクエストごとに、ゲートウェイは開発者の上限と期間内の累計支出を1回のPostgresクエリで参照します。いずれかの上限を超えていれば429が返り、error.typebilling_errorx-should-retry: falseヘッダーが付きます。

メッセージ本文にはspend limit reached (daily; resets 2026-08-08 00:00 UTC)のように、超過した期間とリセット時刻が具体的に含まれます。複数の上限を同時に超えている場合は、最後にリセットされる上限の名前が使われます。admin.blocked_messageを設定していれば、このメッセージの後ろに続けて表示されます。応答にはretry-afterヘッダーも付き、リセットまでの秒数が入ります。ゲートウェイサーバー側がv2.1.225より前のバージョンでは、メッセージは期間もリセット時刻もretry-afterヘッダーも持たない単なるspend limit reachedでした。v2.1.227以降では、<public_url>/protocolのプロトコルリファレンスにこの429応答のヘッダーと本文の正確な形が載ります。

上限は協定世界時(UTC)の暦境界でリセットされます。日次は00:00 UTC、週次は月曜、月次は1日です。/v1/messages/count_tokensはトークン数を数えるだけで課金対象ではないため、上限に関わらずブロックされません。

実際の支出額はどう計算されるか

応答が返るたびに、使用量メーターがトークン数を読み取り、日次・週次・月次それぞれのカウンターに費用を加算します。この処理はクライアントへ送るバイト列には一切触れないため、メーター側で計測に失敗しても応答自体が壊れることはありません。ここで出る金額はUSDの見積もりであり、請求書ではなくサーキットブレーカーとしての数字です。実際の請求額はプロバイダーの利用状況レポートと突き合わせて確認する必要があります。

料金は次の順で解決されます。

  1. そのアップストリームに対するpricing.overridesの行(v2.1.227以降が必要)
  2. アップストリームのモデルIDに対する定価。Claude Codeのコスト表がそのIDを認識できる場合で、AnthropicだけでなくAmazon Bedrock・Google Cloud's Agent Platform・Microsoft Foundryの各ID形式にも対応
  3. マッピングしたmodels[].idに対する定価。Bedrockのapplication-inference-profile ARNやFoundryのデプロイ名のように、アップストリーム文字列自体にモデル名が含まれない場合に使う(v2.1.218以降が必要)
  4. 未知モデル向けの1Mトークンあたり入力5ドル/出力25ドルという既定ティア。メーターが位置づけられないIDが無料扱いになることはない。起動時と、実行時はID単位で1回ずつ警告が出る

Bedrock自体の請求体系との対応はBedrock経由のClaude料金で個別に扱っているので、直接APIの単価との差を確認したいときはそちらを参照してください。

どのレートが適用されても、最後にpricing.multiplier(既定値1)を掛けます。クライアント側での中断も課金対象です。ストリームがアップストリームの最終usageフレームを受け取らずに終わった場合、メーターは出力トークンあたり約4文字という下限見積もりで、すでにクライアントへ送られたテキスト分を課金します。途中で打ち切っても上限を回避できない設計です。

Claude Code側での見え方

Claude Codeは上限に近づくと開発者に警告を出します。最も消費が多い上限の使用率が75%を超えた時点、さらに95%を超えた時点の2段階です。ゲートウェイがリクエストをブロックすると、Claude Codeは429のメッセージをそのまま表示し、設定していればadmin.blocked_messageも含まれます。

この警告は応答ヘッダーだけで動きます。ゲートウェイサーバー側がv2.1.225以降であれば、上限を持つ開発者への/v1/messagesの成功応答すべてに、その開発者自身の使用率とリセット時刻がanthropic-ratelimit-unified-*ヘッダーとして載ります。開発者のマシン側もv2.1.225以降であれば、Claude Codeがそのヘッダーを読んで警告を表示します。ヘッダーは常に開発者自身の上限を表すもので、ゲートウェイは上流プロバイダーが返す(組織全体の共有クォータを表す)レート制限ヘッダーを取り除き、転送しません。

開発者マシン側がv2.1.251以降であれば、Claude Codeは同じヘッダーから/usageSpend limitバーを表示し、ステータスラインの入力にもrate_limits.spend_limitオブジェクトを追加します。表示はドル金額ではなくパーセンテージで、ゲートウェイサーバー側に必要なのはv2.1.225以降のままで足ります。

Admin APIリファレンス

エンドポイントはすべて/v1/organizations/spend_limits配下です。

メソッドとパス説明
GET /v1/organizations/spend_limits説明設定済みの上限を一覧。scope_type(organization/rbac_group/user)で絞り込み可
POST /v1/organizations/spend_limits説明{scope, period}に対する上限を作成または置き換え
GET /v1/organizations/spend_limits/{id}説明spl_接頭辞のIDで1件取得
DELETE /v1/organizations/spend_limits/{id}説明1件削除。{type: "spend_limit_deleted", id}を返す
GET /v1/organizations/spend_limits/effective説明主体(principal)ごと・期間ごとの、実際に効いている上限と累計支出
GET /v1/organizations/spend_limits/audit説明管理操作の変更履歴を新しい順で

規約はAnthropic公式のAdmin APIに合わせています。すべてのオブジェクトにtypeが付き、IDはspl_接頭辞、金額はUSDセント単位の整数文字列(POSTは他のcurrency400で拒否)、エラーは{type: "error", error: {type, message}, request_id}の形。成功・失敗を問わずすべての管理API応答にrequest-idヘッダーが付き、エラー本文にはrequest_idとしても含まれます。すべての変更操作は同一トランザクションでadmin_auditに変更前後の行を書き込み、admin-key:<id>またはoidc:<sub>が紐づきます。

/effectiveはAnthropicのSpendSummaryスキーマを返しますが、ゲートウェイ固有の違いが4つあります。user_idはOIDCのsubそのものであること。actor.nameactor.email_addressは、その主体がゲートウェイ経由で最初の推論リクエストを送るまでnullであること(ゲートウェイはユーザーディレクトリを持たず、各ユーザー自身のセッションJWTから最終確認値を記録するだけ)。各行にgroups配列(その主体が最後に確認されたIdPグループ)が付くこと(これはゲートウェイの拡張で、管理UIが適用中の上限階層をすべて表示できるようにするためのもので、Anthropic向けに書かれたクライアントは無視してよい)。そしてuser_ids[]を指定しないと、支出記録のある主体だけが並ぶこと(ゲートウェイは組織メンバー全員を列挙できないため)。

AnthropicのAdmin APIとの違い

ワイヤ形式は揃えていますが、ゲートウェイの実装はAnthropic公式のAdmin APIそのものではありません。次の点が異なります。

  • scope.typeuser / rbac_group / organizationの3種類に対応する(公式APIの公開POSTが対応するのはuserのみ)
  • /effectiveにゲートウェイ拡張のgroups配列が付く
  • /auditはゲートウェイ独自のエンドポイントで、公式のワイヤ形式を踏襲していない
  • 公式Admin APIにあるspend_limit_increase_requestsキューのような他の管理面は、ゲートウェイには存在しない(ゲートウェイが提供するのは支出上限のエンドポイントだけ)

ページングにも違いがあります。生の一覧は相互排他なspl_接頭辞のIDであるafter_idbefore_idでページングし、作成順に並んでhas_moreがたどっている方向を反映します。/effectiveは不透明なnext_pageトークンを?page=として渡し、支出が記録され続ける間もページが安定するよう主体を昇順で並べます。両方ともlimitは1〜1000、既定20です。/auditは前ページ最後のイベントの数値idであるafter_idでページングし、limitの既定は100です。

データはいつまで保持されるか

ゲートウェイは支出関連のテーブルを4つ持ち、1時間ごとの掃除処理が保持期間を強制します。

テーブル内容保持期間
spend内容主体ごとの期間内累計(セント単位)保持期間admin.spend_retention_months、既定13か月
spend_limits内容設定済みの上限保持期間API経由で削除するまで
admin_audit内容変更履歴保持期間admin.audit_retention_days、既定365日
principal_emails内容各主体の最終確認メール・表示名・IdPグループ。個人情報を含む保持期間最終アクティビティからadmin.identity_retention_days、既定90日

Postgresのスキーマとバックアップ方針はデプロイと運用側の話ですが、支出上限を使う構成ではこの4テーブルもバックアップ対象に含めておく必要があります。

開発者が離職したら、DELETE /v1/organizations/spend_limits/{id}でユーザー個別の上限を削除します。支出と識別情報の行は上の保持期間で自然に消えます。オフボーディングやデータ主体アクセス要求(DSAR)で即座に1人分を消したい場合は、ゲートウェイのデータベースに直接DELETE FROM principal_emails WHERE principal = '<sub>'を実行します。これでメール・表示名・グループを保持している唯一のテーブルが消えます。spendadmin_auditの行は仮名化されたOIDCのsubしか参照していないため、それぞれの保持期間で自然に消えていきます。

支出上限が変えるのは、コスト管理の主体をどこに置くかだ

Bedrockやプロバイダー側の請求だけを見ている限り、コスト超過は「先月いくら使ったか」を月末に知る話にとどまります。支出上限は、この判断を管理者の月次レビューから、リクエストを送る瞬間のゲートウェイ自身へ移します。しかもその判断基準は開発者・グループ・組織という3段階の粒度を持ち、契約者チームだけを厳しく縛るような運用も1本のAPIで組めます。

ここでの実質的な制約はPostgresの可用性です。ストアが落ちてもフェイルオープンで推論を止めない既定挙動は妥当な選択ですが、その間は上限が事実上無効になっているという意味でもあります。厳格な予算統制を求めるならfail_closed_on_error: trueは検討に値しますが、その代償はストア障害がそのまま開発チーム全体の推論停止に直結することです。

まとめ

支出上限は、Claude apps gatewayが共有アップストリーム認証情報の上に持つ、開発者単位の可視化と遮断の仕組みです。社内に既存のLLMゲートウェイがあり、この機能だけを理由に乗り換える必要があるか判断に迷う場合は、選び方の比較で評価軸を確認してから判断すると手戻りが少なくなります。admin:ブロックを有効にしてAdmin APIから{scope, amount, period}を投げれば上限が効き、超過時は429とリセット時刻付きのメッセージで止まります。金額はあくまで見積もりベースの回路遮断であり、実際の請求はプロバイダー側の利用状況と突き合わせる前提です。組織全体の予算を守りたいチームはもちろん、契約者やインターンのように利用範囲を限定したい相手がいるチームは、導入時点でadmin.write_keysadmin.read_keysを用途ごとに分けて発行しておくと、後から誰がいつ何を変更したかを監査ログで追いやすくなります。

この記事を共有:XはてブLinkedIn