← Blog

Claude API Multi-Tenant Setup: A Practical Guide

2026-09-23 · 5 min read · SubToAPI Team

If you're building a SaaS product where multiple customers or internal teams all need access to Claude, you can't just hand everyone the same API key. A multi-tenant Claude API setup means each tenant (customer, team, or internal service) gets isolated credentials, its own usage tracking, and its own rate limits — while your backend still talks to a single upstream Claude account.

The core problem is that Anthropic's API gives you one key per account, not per customer. Without a tenant layer on top, you end up either sharing one key across everyone (no way to attribute cost or usage, no way to revoke one customer without breaking all of them) or juggling dozens of separate Claude accounts, which doesn't scale operationally or financially. This article covers the architecture patterns that solve this, the tradeoffs between building it yourself and using a managed layer, and working code for the most common approach.

What "multi-tenant" actually requires

Before picking an architecture, be clear on what you're isolating per tenant:

Any setup that doesn't cover all five isn't really multi-tenant — it's just a shared key with extra logging.

Option 1: Build a proxy layer yourself

The DIY approach is a thin service that sits between your tenants and the Claude API. Each tenant gets an application-level key issued by you; your proxy validates it, maps it to a tenant ID, logs the request, enforces a rate limit, and forwards the call upstream using your single Claude API key.

A minimal version looks like this:

const tenantKeys = new Map([
  ["tenant_abc", { claudeKey: process.env.CLAUDE_KEY, rateLimit: 60 }],
  ["tenant_xyz", { claudeKey: process.env.CLAUDE_KEY, rateLimit: 200 }],
]);

app.post("/v1/messages", async (req, res) => {
  const appKey = req.headers.authorization?.replace("Bearer ", "");
  const tenant = lookupTenant(appKey); // your own key->tenant mapping
  if (!tenant) return res.status(401).json({ error: "invalid key" });

  if (await exceedsRateLimit(tenant.id, tenant.rateLimit)) {
    return res.status(429).json({ error: "rate limit exceeded" });
  }

  const response = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "x-api-key": tenant.claudeKey,
      "anthropic-version": "2023-06-01",
      "content-type": "application/json",
    },
    body: JSON.stringify(req.body),
  });

  const data = await response.json();
  await logUsage(tenant.id, data.usage); // per-tenant token accounting
  res.json(data);
});

This works, but the real cost shows up over time: you now own key rotation, per-tenant rate limiting logic, usage aggregation for billing, streaming support (SSE passthrough is fiddly), retry and error handling for Claude's own rate limits, and audit logging. None of that is hard individually, but together it's a small platform you have to maintain indefinitely just to resell access to a model you don't control the pricing of.

Option 2: Use a managed key-issuing layer

The alternative is to let a service handle the tenant layer and just issue application keys against it. SubToAPI does exactly this: it sits between your Claude access and your application, giving you sub_live_... keys you can hand out per tenant, per environment, or per team seat, each with its own usage metadata visible in a dashboard.

The request shape is the same as calling Claude directly, so migrating an existing integration is mostly a base URL and header swap:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Summarize this ticket."}]
  }'

For multi-tenancy specifically, you'd issue one key per tenant (or per environment — staging vs. production, or per customer if you're building a platform on top of Claude), track their usage independently through the dashboard, and revoke a single key without affecting anyone else. Streaming, tool use, and team seats work the same way as a single-tenant setup — see the docs for the full request/response reference and streaming guide if your tenants need token-by-token output.

This doesn't remove the need to think about your own tenant model — you still decide what a "tenant" is in your product and how you map incoming requests to a key — but it removes the part where you have to build and operate the proxy, rate limiter, and usage ledger yourself.

Choosing between the two

Build it yourself if:

Use a managed layer if:

Most teams start with the managed route to ship the multi-tenant version of their product quickly, then decide later if custom routing logic justifies building their own proxy. You can try this with a free trial at signup — check the quickstart to get a working call in a few minutes, and pricing for per-seat costs if you're issuing keys across a team.

questions

Do I need a separate Claude API account per tenant? No. A single upstream Claude account is enough — the isolation happens at the application-key layer, whether you build that layer yourself or use a service that issues per-tenant keys against one account.

How do I track token usage per tenant? Log the usage object returned in every Claude response against the tenant ID that made the request. If you use a managed key layer like SubToAPI, this is tracked automatically per key in the dashboard without extra logging code.

Can I rate-limit tenants differently? Yes — this is usually the main reason to build tenant isolation at all. Store a rate limit per tenant ID (or per key) and enforce it before forwarding the request, either in your own proxy or via per-key limits if your provider layer supports them.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →