Cohere API Multi-Tenant Guide: One Key, Many Customers, No Blast Radius

Every other integration guide assumes the traffic is yours. This one assumes it belongs to your customers — which means one of them can exhaust your Cohere quota, run up your invoice, or read another one's data, and every one of those failures arrives as a successful response.

12 min read
Staff Pick

📡 Monitor your APIs — know when they go down before your users do

Better Stack checks uptime every 30 seconds with instant Slack, email & SMS alerts. Free tier available.

Start Free →

Affiliate link — we may earn a commission at no extra cost to you

There is a specific moment where a Cohere integration stops being an integration and becomes a platform: the point at which the person whose prompt you are forwarding is not you. Before that moment, every hard problem is availability-shaped — is it up, did the call fail, how do I retry, where do I fail over. After it, a whole second category appears that none of those controls touch, because the adversary and the cost centre and the data owner are all your own users, and the provider sees exactly one customer: you.

That inversion is what makes multi-tenancy its own problem rather than a harder version of an existing one. A circuit breaker protects you from Cohere. A retry budget protects Cohere from you. Nothing in either protects your tenants from each other, and nothing in either notices when one of them is quietly the entire invoice.

Ranking the four risks by how much damage they do before anyone notices: cross-tenant data disclosure (silent, unbounded, and often discovered by the victim); cost blast radius (bounded by the billing cycle, discovered on the invoice); quota exhaustion (loud, but it looks like a provider outage and gets diagnosed as one); abuse of your endpoint as a free proxy (slow, and usually found by looking at cost). Confirm the platform is actually healthy at live Cohere status before you spend an afternoon debugging what turns out to be one tenant.

What the Provider Cannot See About Your Tenants

Start from the provider's point of view, because every gap in it is a control you have to build. Cohere sees one account, a set of keys, and a stream of requests. Here is what that view structurally cannot resolve, and what each blind spot costs you.

What Cohere cannot distinguishWhat it costs youWho has to build the control
Which tenant a request belongs toThe invoice is a single number. Per-customer margin is unknowable, and so is which customer to talk to when one is unprofitable.You, in the request path
Whether a burst is one tenant or all of themA 429 arrives with no attribution, so the incident presents as a provider problem and is investigated as one.You, in the request path
Whether a prompt is first-party or user-suppliedContent policy enforcement lands on your account. A tenant's violation is your suspension.You, before the call
Whose data is in a retrieved context blockCross-tenant disclosure with a 200 status. No error rate moves.You, in your own storage layer
Whether a tenant is on a free trialUnbounded spend from an account that will never pay. Trial abuse is a cost problem long before it is a fraud problem.You, at admission
That a request came from your product at allIf your endpoint is reachable and unmetered, it is a free Cohere proxy for anyone who finds it.You, at authentication

Every row resolves to the same sentence: the provider is not a participant in your multi-tenancy. That is not a criticism of Cohere — it is the correct design for a wholesale API. It just means the entire mechanism lives on your side of the wire, and any plan that begins “we will use the provider's per-key limits” is skipping the part where you check whether those limits are per key.

The Isolation Ladder

Multi-tenant Cohere deployments sit on one of five rungs. Most teams believe they are one rung higher than they are, because attribution and isolation feel like the same thing until the first contention incident proves they are not.

RungWhat it gives youWhat still breaks
1. One key, no tenant tagNothing. It ships fastest and it is where almost everyone starts.Everything. You cannot answer “which customer” about cost, contention or abuse, ever, retroactively.
2. One key, tenant id on every ledger rowAttribution. You can name the tenant behind any cost or burst, after the fact.No enforcement. You watch the noisy neighbour in a dashboard while it happens.
3. Rung 2 plus in-path per-tenant budgetsEnforcement. The first real rung: one tenant can no longer take the others down or run up an unbounded bill.Data isolation is untouched. Caches, indexes and example selectors still cross tenants.
4. Rung 3 plus tenant-scoped storageDisclosure containment: cache keys, vector namespaces and prompt assembly all carry the tenant id.Compliance ceiling. Everything still runs under your account, your DPA and your content-policy exposure.
5. Bring-your-own-keyThe tenant's traffic is billed to the tenant, limited by the tenant's quota, and governed by the tenant's agreement.Support load and a new secret-management problem. Only worth it for enterprise tiers that ask for it.

The jump that matters is 2 to 3. Rung 2 is where most production systems actually live, and it feels safe because the dashboard is informative — you can see the noisy tenant clearly. But a dashboard is a record of a decision you did not make. Rung 3 is the first rung where the system says no on its own, at 3am, without anyone reading anything.

📡
Recommended

Is It The Provider, Or Is It One Tenant?

A 429 storm caused by your busiest customer and a genuine Cohere degradation look identical from inside your own logs. An external monitor calling the API on a fixed, tiny schedule answers the question in seconds, because its traffic is not competing with anyone's.

Try Better Stack Free →

Admission Control, In the Request Path

The control that does the work is small and unglamorous: before the outbound call, ask whether this tenant is allowed to make it. Two independent checks — a rate bucket and a concurrency cap — because they fail differently. A tenant can stay under any per-minute rate and still occupy your entire connection pool with long streaming requests, and a tenant can hold one connection and still burn a per-minute allowance in a loop.

// Per-tenant admission for Cohere. State lives in Redis so the budget
// holds across every process — a per-instance bucket silently multiplies
// the real limit by your instance count, which is the most common way
// this control is built and then does not work.

const TIERS = {
  free:       { rpm: 5,   concurrent: 1,  usdPerDay: 0.50 },
  pro:        { rpm: 60,  concurrent: 4,  usdPerDay: 25 },
  enterprise: { rpm: 600, concurrent: 25, usdPerDay: 500 },
};

async function admit(tenant) {
  const tier = TIERS[tenant.tier];

  // 1. Rolling-window rate, not a counter reset on the minute boundary.
  //    A minute-boundary counter lets a tenant spend two full allowances
  //    back to back across the boundary.
  const rate = await redis.eval(ROLLING_WINDOW_LUA,
    ['rate:' + tenant.id], [tier.rpm, 60, nowMs()]);
  if (!rate.allowed) return deny('rate', rate.retryAfterMs);

  // 2. Concurrency, held for the life of the request. Independent of rate:
  //    long streaming calls exhaust connections without moving the rate.
  const slot = await acquireSlot('conc:' + tenant.id, tier.concurrent);
  if (!slot) return deny('concurrency', 250);

  // 3. Spend, priced at WRITE time from a dated rate table. Soft threshold
  //    degrades, hard threshold refuses — and the hard one is only ever
  //    applied to free and trial tiers.
  const spentToday = await redis.get('spend:' + tenant.id + ':' + today());
  if (spentToday >= tier.usdPerDay) {
    if (tenant.tier === 'free') return deny('budget', null);
    degradeToCheaperModel(tenant);   // paid tiers degrade, never hard-fail
    alertAccountOwner(tenant);
  }

  return { ok: true, slot };
}

// The sum of concurrent tenant allowances must sit BELOW the account
// ceiling. Tuning it to exactly 100% means normal variance produces 429s
// that look like a provider incident.

Three details in there are the ones that get dropped and each has a characteristic failure. State in process memory rather than shared storage multiplies your effective limit by the instance count, so the control appears to work in staging with one instance and does nothing in production with twelve. A minute-boundary counter instead of a rolling window lets a tenant spend two full allowances back to back across the boundary. And a hard spend refusal applied to a paying customer converts a cost problem into a churn problem — degrade paid tiers, refuse free ones.

The Cohere Trap: The Isolation Boundary Is in the Index, Not in the API Call

Most Cohere deployments are retrieval pipelines: embed, store, search, rerank. In that shape the multi-tenant boundary is almost never the API call — it is the vector store the embeddings land in, which is a system you own and the provider has no visibility into. You can hold every provider-side control perfectly and still leak, because the leak happens after the call succeeds.

The failure is a missing filter, and it returns HTTP 200. A search that omits the tenant predicate returns neighbours from the whole index, ranked by similarity with no notion of ownership, and then the rerank step does exactly what it is supposed to and puts another tenant's most relevant document at position one. Every component behaves correctly. The output is a confident, well-cited answer built from data the requesting tenant has no right to see, and no error is raised anywhere in the chain.

Because of that, tenant scoping must be structural rather than a parameter a caller can forget. Either give each tenant its own namespace or collection, or route every query through a single function that takes the tenant id as a required argument and constructs the filter itself, with no code path that reaches the index directly. Add a test that asserts a cross-tenant query returns zero results, and run it on every deploy — it is the only signal that will ever fire, since the production failure mode is a successful response.

Six Multi-Tenant Failures That Return HTTP 200

This is why multi-tenancy resists the monitoring you already have. Availability problems announce themselves with a status code; tenancy problems do not. Every row below is a successful response.

What happenedWhat you observeThe signal that would have caught it
Cache keyed on prompt text serves tenant A's answer to tenant B200, and a suspiciously fast responseCache-hit rate broken down by tenant pair; a hit across tenants should be structurally impossible, not rare
Retrieval query missing the tenant filter200, well-cited, confidently wrong ownershipA deploy-gating test asserting a cross-tenant query returns zero rows
Few-shot examples selected from recent traffic across all tenants200, and better output quality than beforeExample-selector unit test with a required tenant argument; the quality gain is what stops anyone looking
One tenant consumes 90 percent of the account's token allowance200 for them, intermittent 429 for everyone elseShare-of-account-ceiling per tenant, alerting above a threshold well under 100 percent
A trial account scripts your endpoint as a free Cohere proxy200 forever, until the invoicePer-tenant requests-per-active-session; a human and a script have entirely different pacing
A tenant's user content trips the provider's content policy200s, then an account-level warning aimed at youRefusal and moderation-flag rate per tenant; a single tenant's spike is the whole account's risk

The pattern across all six is that the request-level metrics you already collect — status code, latency, error rate — are blind to every one of them. Each requires a metric with a tenant dimension, which is the real argument for putting the tenant id on the ledger row long before you think you need it. You cannot add that dimension retroactively to traffic that has already happened.

🔐
Recommended

One Provider Credential, Many People Who Can Reach It

Multi-tenant deployments accumulate keys: a production key, per-environment keys, per-tier keys, and eventually tenant-supplied ones. Shared, audited credential storage is what keeps a revocation from turning into a search.

Try 1Password Free →

Data Isolation Is Not a Cohere Setting

Nothing in the Cohere API mixes one customer's data into another's response. Every real cross-tenant disclosure in an LLM product happens in code that runs before or after the call, in three places that are all optimisations someone added for good reasons.

  • The response cache. Keyed on the prompt, it is correct for a single-tenant app and a disclosure channel for a multi-tenant one. The tenant id belongs in the key, including in the negative and error caches that get added later without a review.
  • The retrieval index. A filter that a caller can forget will eventually be forgotten. Prefer a namespace per tenant, or a single query function that takes the tenant id as a required argument and builds the filter itself, with no code path that reaches the store directly.
  • Prompt assembly. Few-shot examples mined from recent production traffic, summaries carried between turns, and any “similar past request” feature all move text between requests. If that text is user content, the selector needs a tenant argument for the same reason the index does.

There is also a contractual layer that outlives all three. Whatever data-retention and training posture you have agreed with Cohere applies to every tenant's content, because it is all your account. A tenant that needs stricter terms than the ones you hold cannot get them inside your account at any rung below bring-your-own-key — see the data privacy guidefor what those terms actually cover.

When Bring-Your-Own-Key Is Worth It

BYOK is the top rung and it is genuinely different in kind: the tenant's requests are billed to the tenant, bounded by the tenant's own quota, and governed by the tenant's agreement with Cohere. Cost blast radius, quota contention and the content-policy exposure all leave your account in one move. It also creates three new obligations that are easy to underestimate.

What BYOK moves to the tenantWhat it moves to you
The bill, in full and per tenantSecret storage for customer-owned credentials, encrypted per tenant, with a revocation and rotation path
Rate-limit contention — their burst hits their ceilingA support surface: their key, their quota, their outage, and your product is where it surfaces
The data-processing agreement and retention termsPer-tenant failure handling — an expired or revoked key is now a routine, per-customer error state that needs a real UI

The honest recommendation is that BYOK is an enterprise-tier feature, driven by procurement rather than engineering, and that shipping it does not remove the need for rungs 2 through 4. You will run both models simultaneously — pooled for self-serve, BYOK for enterprise — so the ledger needs a field recording which key paid for each row, or your per-tenant unit economics will silently include traffic you never paid for.

Abuse: When a Tenant Is Not a Customer

The last category is the one that looks like healthy growth. An endpoint that accepts arbitrary text and forwards it to Cohere is a free inference proxy for anyone who can reach it, and the traffic it attracts is indistinguishable from enthusiastic usage in every aggregate metric. Cost per active user rises, engagement looks excellent, and nobody investigates a chart that is going up.

The reliable discriminator is pacing rather than volume. Human sessions have irregular gaps — seconds to minutes, with pauses to read the output. Scripted sessions have machine-uniform intervals and no reading pause at all, and they keep going through the hours where your real users are asleep. Two cheap signals catch nearly all of it: per-tenant request intervals with a low variance, and a ratio of request volume to any product action that is not the API call itself. A tenant generating thousands of completions and saving nothing, exporting nothing and viewing nothing is not using your product.

What to do about it is a product decision, but the technical prerequisites are the same three things in this guide: authenticate before the call so anonymous traffic is impossible, meter per tenant so the cost is attributable, and hold a hard budget on free tiers so the worst case is bounded at a number you chose. For the systematic version of the cost side, see the cost attribution guide; for tenant-supplied text that tries to redirect the model rather than just consume it, see the prompt injection guide.

Where Overflow Traffic Should Go

A per-tenant budget that only ever refuses is a blunt instrument. Once admission control exists, the interesting option is routing overflow to a second provider on separate infrastructure and a separate account ceiling, so a tenant over their share degrades rather than stops.

Groq

Separate account, separate ceiling, separate invoice. Overflow routed here does not consume the Cohere headroom your other tenants are sharing.

Check Groq status →

Mistral

Separate account, separate ceiling, separate invoice. Overflow routed here does not consume the Cohere headroom your other tenants are sharing.

Check Mistral status →

OpenAI

Separate account, separate ceiling, separate invoice. Overflow routed here does not consume the Cohere headroom your other tenants are sharing.

Check OpenAI status →

Deciding whether a destination's answer is worth the same is its own problem — see the fallback ranking guide, and note that a per-tenant overflow route needs the tenant id carried through to the second provider's ledger rows too, or the cheaper path becomes the unattributed one.

Frequently Asked Questions

Should I issue a separate Cohere API key per customer?

Only if you have first established what a key actually buys you at this provider. A key per tenant reliably buys attribution — you can tell whose traffic is whose without instrumenting anything — and it buys a fast revocation path when one tenant has to be cut off. What it usually does not buy is a quota boundary, because most providers apply rate limits at the account or organisation level regardless of how many keys that account has issued. Treat key separation as an accounting and revocation tool, and build the fairness mechanism yourself in your own process, where it can actually reject a request before it consumes shared headroom.

How do I stop one customer from consuming my whole Cohere rate limit?

Enforce a per-tenant admission decision before the outbound call, not after the provider rejects it. A token bucket per tenant, held in shared state so it holds across every process, with a refill rate assigned per plan tier and a hard concurrency cap alongside it. The concurrency cap matters as much as the rate: a single tenant issuing long-running streaming requests can occupy every connection in your pool without exceeding any per-minute rate at all. Size the sum of tenant allowances to sit meaningfully below the account ceiling, because the difference between the two is the headroom that absorbs bursts, and a system tuned to exactly 100 percent of the ceiling is a system that 429s under normal variance.

What is the right way to cap Cohere API costs per customer?

Price each request into a per-tenant ledger at write time using a dated rate table, then check the tenant's running total in the request path before the call is made. Post-hoc reconciliation against the invoice is necessary but it is a detection mechanism, not a control — by the time an invoice disagrees with your ledger, the money is spent. Run two thresholds: a soft one that degrades the tenant to a cheaper model or a smaller context and emits a warning, and a hard one that refuses. Reserve the hard refusal for free and trial tiers, where the downside of a wrong rejection is small and the upside is that an abusive signup cannot generate an unbounded bill.

Can one tenant's data leak into another tenant's Cohere responses?

Not through the provider's inference call in normal operation, but very easily through three things you built around it. A response cache keyed on prompt text alone will serve one tenant's answer to another. A retrieval index without a mandatory tenant filter will return another tenant's documents as context, and the model will use them faithfully. And a few-shot prompt assembled from recent examples across all users will paste one customer's content into another's request. All three return HTTP 200 with a plausible answer, so none of them will ever appear in an error rate. The tenant identifier belongs in the cache key, in the index filter, and in the example selector, enforced structurally rather than by convention.

Where does cross-tenant data leak in a Cohere retrieval pipeline?

Almost always in the vector store rather than in the API call. Embeddings from every tenant land in an index you own, and a search that omits the tenant filter returns neighbours from all of it; the rerank step then correctly promotes another tenant's most relevant document to the top. The call returns HTTP 200, every component behaves as designed, and the output is a confident answer built from data the requester should never see. Make the scoping structural — a namespace per tenant, or a single query function that requires a tenant id and builds the filter itself — and add a deploy-gating test asserting that a cross-tenant query returns zero results, because the production failure mode is a success response and nothing else will ever alert.

Related Cohere Guides

Know Whether It Is Cohere Or One Of Your Tenants

A 429 storm from your busiest customer and a real Cohere degradation are indistinguishable from inside your own traffic. API Status Check calls the provider on an independent schedule, so the first question in every multi-tenant incident already has an answer.

Start Your Free Trial →

Alert Pro

14-day free trial

Stop checking — get alerted instantly

Next time Cohere goes down, you'll know in under 60 seconds — not when your users start complaining.

  • Email alerts for Cohere + 9 more APIs
  • $0 charged today — card required to start
  • Cancel anytime — $9/mo after trial

🌐 Can't Access Cohere?

If Cohere is working for others but not for you, it might be an ISP or regional issue. A VPN can help bypass network-level blocks and routing problems.

🔒

Troubleshoot with a VPN

Connect from a different region to test if the issue is local to your network. Also protects your connection on public Wi-Fi.

Try NordVPN — 30-Day Money-Back Guarantee
🔑

Secure Your Cohere Account

Service outages are a common time for phishing attacks. Use a password manager to keep unique, strong passwords for every account.

Try NordPass — Free Password Manager
Quick ISP test: Try accessing Cohere on mobile data (Wi-Fi off). If it works, the issue is with your ISP or local network.

⏳ While You Wait — Try These Alternatives

🛠 Tools We Use & Recommend

Tested across our own infrastructure monitoring 200+ APIs daily

SEMrushBest for SEO

SEO & Site Performance Monitoring

Used by 10M+ marketers

Track your site health, uptime, search rankings, and competitor movements from one dashboard.

We use SEMrush to track how our API status pages rank and catch site health issues early.

From $129.95/moTry SEMrush Free
View full comparison & more tools →Affiliate links — we earn a commission at no extra cost to you