CLAUDE LABEN
MEMORY — Claude Codeの長時間セッションのメモリリークが一掃されました。MCP stdioサーバのstderrが最大64MB蓄積する問題やLSPドキュメントの開きっぱなしが修正されていますTABLES — 非常に大きなmarkdownテーブルが描画を止める不具合を修正。200行を超えるテーブルは先頭200行と「… N more rows」表示になりますSPEED — deny/askルールを多く抱えたセッションで毎ターン数秒遅くなる問題を修正。ルールマッチャがコンパイルして再利用されますTOOLS — MCPツールが多いprint/SDKセッションでは、ツールプールの組み立てをキャッシュし最大7倍速いラウンドになりましたARTIFACTS — Claude CodeのArtifactsは、セッションの作業をその場で更新される共有Webページに変えます。PR解説やダッシュボードに使えますDEADLINE — 7月24日にOpus 4.7のfastモードが削除されます。speed: "fast" はエラーになるため、Opus 4.8のfastモードへ移行が必要ですMEMORY — Claude Codeの長時間セッションのメモリリークが一掃されました。MCP stdioサーバのstderrが最大64MB蓄積する問題やLSPドキュメントの開きっぱなしが修正されていますTABLES — 非常に大きなmarkdownテーブルが描画を止める不具合を修正。200行を超えるテーブルは先頭200行と「… N more rows」表示になりますSPEED — deny/askルールを多く抱えたセッションで毎ターン数秒遅くなる問題を修正。ルールマッチャがコンパイルして再利用されますTOOLS — MCPツールが多いprint/SDKセッションでは、ツールプールの組み立てをキャッシュし最大7倍速いラウンドになりましたARTIFACTS — Claude CodeのArtifactsは、セッションの作業をその場で更新される共有Webページに変えます。PR解説やダッシュボードに使えますDEADLINE — 7月24日にOpus 4.7のfastモードが削除されます。speed: "fast" はエラーになるため、Opus 4.8のfastモードへ移行が必要です
記事一覧/API & SDK
API & SDK/2026-06-17上級

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

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

Claude API115マルチテナントSaaS14コスト帰属2レート制限6Row Level SecurityTypeScript24本番運用36

プレミアム記事

個人で複数のサービスを並行運用していると、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-07-07
Claude API が本番で突然 429 を返し始めたとき — レート制限の余白をヘッダから計測して枯渇前に絞る運用メモ
429 が出てから慌ててリトライを入れるのは後手です。Claude API のレスポンスヘッダには残量が毎回書かれています。余白を継続計測し、枯渇する前に自分から絞る運用メモを、実装フックと計測ログの読み方でまとめます。
API & SDK2026-07-01
Claude API のドキュメント抽出が「自信満々に間違える」とき — 沈黙する誤りを不変条件で捕まえる運用メモ
請求書や契約書の構造化抽出で一番怖いのは、クラッシュではなく「スキーマも通り信頼度も高いのに値だけ間違っている」沈黙の誤りです。不変条件・二段抽出・フィールド単位の誤り率で運用する実装メモを共有します。
API & SDK2026-06-17
Claude API のドキュメント抽出が「確信を持って間違える」とき — 検証層の設計メモ
Claude API で請求書や契約書を構造化抽出するとき、最も怖いのは例外ではなく「もっともらしく間違った JSON」です。スキーマ検証・算術整合・二重抽出の一致率で誤抽出を本番前に捕まえる検証層を、TypeScript の実装とともにまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →