CLAUDE LABEN
BILLING — 6/15に告知されていた課金変更(Agent SDK・headless・GitHub Actions・他社エージェントを別枠の月次クレジットへ移す案)は撤回・保留に。これらは引き続きサブスクリプションの上限内で扱われますMANAGED — Code w/ ClaudeでManaged Agentsを発表。サンドボックス内で動作しprivate MCPへ接続でき、実行環境も到達先サービスも企業の管理境界内に収まりますLIMITS — 同会議でClaude Codeのレート上限が倍増、APIの上限も引き上げられました。多段のエージェント運用に余裕が生まれますSUBAGENTS — Claude Codeにネスト型サブエージェント(サブエージェントが別のエージェントを生成)と、壊れた構成を隔離する安全モードが追加されましたEXPORT — Fable 5・Mythos 5は米政府の輸出管理指令による停止が継続中(6/12〜)。Opus・Sonnet・Haikuなど他の全モデルは通常どおり稼働していますCODE — /doctor・Remote Control・/bugの改善やフォールバックモデルの拡張など、Claude Codeの更新が継続していますBILLING — 6/15に告知されていた課金変更(Agent SDK・headless・GitHub Actions・他社エージェントを別枠の月次クレジットへ移す案)は撤回・保留に。これらは引き続きサブスクリプションの上限内で扱われますMANAGED — Code w/ ClaudeでManaged Agentsを発表。サンドボックス内で動作しprivate MCPへ接続でき、実行環境も到達先サービスも企業の管理境界内に収まりますLIMITS — 同会議でClaude Codeのレート上限が倍増、APIの上限も引き上げられました。多段のエージェント運用に余裕が生まれますSUBAGENTS — Claude Codeにネスト型サブエージェント(サブエージェントが別のエージェントを生成)と、壊れた構成を隔離する安全モードが追加されましたEXPORT — Fable 5・Mythos 5は米政府の輸出管理指令による停止が継続中(6/12〜)。Opus・Sonnet・Haikuなど他の全モデルは通常どおり稼働していますCODE — /doctor・Remote Control・/bugの改善やフォールバックモデルの拡張など、Claude Codeの更新が継続しています
記事一覧/API & SDK
API & SDK/2026-06-17上級

Claude API のマルチテナント SaaS で「請求が合わない」を消す — テナント分離とコスト帰属の実装メモ

Claude API の SaaS をマルチテナント化したとき最初に壊れるのはコスト帳尻です。計測の単一窓口・原子的カウンター・Anthropic 請求との突合・テナント分離の敵対的検証まで、本番で動く TypeScript と運用判断を実装メモとしてまとめます。

Claude API75マルチテナントSaaS14コスト帰属レート制限3Row Level SecurityTypeScript16本番運用25

プレミアム記事

個人で複数のサービスを並行運用していると、Claude API を組み込んだ SaaS を「動く」状態から「複数の顧客に課金できる」状態へ引き上げる瞬間が必ず来ます。そこで最初に壊れるのは、機能でもレイテンシでもありません。月末の帳尻です。

自社の Anthropic の請求は $312 なのに、テナント別に積み上げた金額の合計は $270 にしかならない。差額の $42 が誰の利用だったのか、もう追えない。この「合計が合わない」状態は、料金プランの設計そのものを足元から崩します。原価が分からなければ、いくらで売れば黒字なのかも分からないからです。

ここでは、テナント分離とコスト帰属を「だいたい」ではなく「突合できる」水準で実装する方法を、本番で動く TypeScript と、そのとき迫られる運用判断とあわせて書いていきます。Next.js + PostgreSQL + Redis(または Cloudflare KV) を前提にしていますが、考え方はスタックを問いません。

なぜ「だいたい合っている」では破綻するのか

通常の Web API なら、コストはサーバー費用として固定費に近く、誰が何回叩いたかをログで追えば十分です。Claude API はそうではありません。コストはリクエスト数ではなくトークン数で決まり、しかもプロンプト長・モデル・キャッシュの効き具合で 1 リクエストの原価が数円から数百円まで動きます。

この変動を「リクエスト数 × 平均単価」で近似すると、ヘビーユーザーのコストを必ず過小評価します。長文を投げる大口テナントほど 1 リクエストが高く、平均で割った瞬間に実態とずれるからです。結果として、最も課金すべき相手のコストを取りこぼします。

だからコスト帰属の出発点は単純です。すべての Claude API レスポンスに入っている usage を、そのリクエストを発生させたテナントに、その場で正確に紐付ける。推定で埋めない。レスポンスに書いてある実数だけを記録する。これを徹底できるかどうかで、月末の突合が成立するかどうかが決まります。

計測は API 呼び出しと不可分にする

帳尻が合わなくなる最大の原因は、計測の付け忘れです。新しい機能を追加するたびに anthropic.messages.create を直接呼ぶと、そのたびに計測コードを書き足す必要が生まれ、いつか必ず忘れます。忘れた経路のコストは静かに消え、月末に差額となって現れます。

対策は、Claude API へ到達する経路を 1 本に絞ることです。テナントコンテキストを受け取る単一の関数を作り、アプリ内のどこからもこの関数経由でしか Claude を呼べないようにします。

// lib/claude-client.ts
import Anthropic from '@anthropic-ai/sdk';
import type { TenantContext } from '@/types/tenant';
import { checkRateLimit } from '@/lib/rate-limiter';
import { recordUsage } from '@/lib/usage-tracker';
 
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });
 
export interface ClaudeRequestParams {
  model: string;
  messages: Anthropic.MessageParam[];
  system?: string;
  maxTokens?: number;
}
 
export async function callClaudeForTenant(
  tenant: TenantContext,
  params: ClaudeRequestParams,
): Promise<Anthropic.Message> {
  // ① まずレート制限。ここで弾けばトークンを 1 つも消費しない
  if (!(await checkRateLimit(tenant.tenantId, tenant.requestsPerMinuteLimit))) {
    throw new Error(`RATE_LIMIT_EXCEEDED:${tenant.tenantId}`);
  }
 
  const message = await anthropic.messages.create({
    model: params.model,
    max_tokens: params.maxTokens ?? 4096,
    system: params.system,
    messages: params.messages,
  });
 
  // ② 計測は await しない。失敗してもレスポンスは返す。ただし握りつぶさない
  recordUsage(tenant.tenantId, {
    inputTokens: message.usage.input_tokens,
    outputTokens: message.usage.output_tokens,
    cacheReadTokens: message.usage.cache_read_input_tokens ?? 0,
    cacheWriteTokens: message.usage.cache_creation_input_tokens ?? 0,
    model: params.model,
    requestId: message.id,
  }).catch((err) => {
    // ここを console.error だけで終わらせると、計測欠損に誰も気づけない
    reportCriticalError('usage_tracking_failed', { tenantId: tenant.tenantId, err });
  });
 
  return message;
}

ポイントは 2 つあります。1 つは、usage から cache_read_input_tokenscache_creation_input_tokens まで拾うこと。キャッシュ読み出しは通常入力より安く、キャッシュ書き込みは少し高い。この区別を捨てると、キャッシュを多用するテナントのコストを系統的に間違えます。

もう 1 つは、計測の失敗を console.error で終わらせないこと。私自身、個人開発で 4 サイトを自動運用するなかで「ログには出ていたが誰も見ていなかった」欠損を経験しました。計測失敗は機能のバグより静かで、しかも金額に直結します。Sentry や Slack など、人間が必ず気づく経路へ流すべき種類のエラーです。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
テナント別コストを Anthropic の実請求と月末に突合し、誤差を数%以内に収める計測設計
予算チェックと API 呼び出しの間に必ず生まれる競合を、ソフトリミットとアトミック差し引きで使い分ける判断基準
テナント分離が本当に効いているかを CI で証明する敵対的テストの組み方
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

API & SDK2026-05-30
Claude API の max_tokens 打ち切りを継続生成でつなぐ — 重複とコードブロック分断を防ぐ実装
長文生成が途中で切れる max_tokens 打ち切りを検出し、assistant プレフィルで続きを書かせ、つなぎ目の重複やコードフェンスの分断を防いで安全に組み立てる継続生成の実装パターンをまとめました。
API & SDK2026-05-04
Bun × Claude API で本番運用するエッジAIサービス — Node.js移行の判断軸と落とし穴を回避する実装パターン
Claude APIをBun上で本番運用するための実装ガイド。Node.jsからの移行判断軸・組み込みSQLite/WebSocketの活用・ストリーミング最適化・典型的な落とし穴の回避策まで、動作するコードと実測値で解説します。
API & SDK2026-04-30
Claude API で多言語翻訳 SaaS を本番運用する設計ガイド — 用語集・スタイル・ドメイン適応の実装
Claude API で多言語翻訳 SaaS を本番運用する設計を、用語集・スタイルガイド・ドメイン適応・品質ゲート・コスト最適化まで具体的なコードと運用ノウハウで解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →