Console
Guardrails and limits

Rate limits & spend caps

Request and token limits, and monthly caps.

RouterPlus checks these limits before a request reaches a provider:

  • the key's requests-per-minute (RPM) limit
  • the organization's token and concurrency limits
  • the provider pool's capacity
  • guardrail budgets and key spend limits
  • the monthly spend caps
  • the balance

Each limit refuses with a typed error. The error names its class in the body and in x-tm-error-code. RouterPlus does not slow down or queue a request without telling you. A refused request costs nothing.

In the console, open Billing > Rate limits.

Per-key requests per minute

Every key has an RPM limit over a rolling 60-second window. All gateway instances count in one shared store. The count for a request can stay in the window for up to 61 seconds.

KeyRPM
First trial key shown after verified browser sign-in20
Key created in the console or with the identity API300
The managed Playground key of the console60

Trial rate

  • Until the organization buys credit, every customer key and the organization as a whole run at 20 requests per minute. Credit that RouterPlus granted counts as bought credit. More keys do not add more requests.
  • The first purchase removes the trial rate within seconds. No key changes.
  • The trial rate does not apply to requests served only by your own provider keys (BYOK). It does not apply to the managed Playground key.
  • Past card-verification bonuses are promotional credit. They do not count as purchases.

An organization that joined through a RouterPlus signup invitation (for example, at a hackathon) counts as paid from the start. By default, the organization and each key get these limits: 600 requests per minute, 10,000,000 tokens per minute and 32 requests in flight.

GET /v1/limits shows the values that apply to your key.

RouterPlus can also limit an organization on trial credit when it detects unusual usage. The request gets 429 usage_limited (with retry-after) or 403 usage_restricted. The message asks you to contact support. Support can review the account. A purchase usually removes the limit.

The rate-limit refusal

Above the limit, RouterPlus refuses the request before any reservation or provider work:

HTTP/1.1 429 Too Many Requests
retry-after: 23
x-tm-error-code: rate_limit
x-tm-error-origin: gateway_admission
x-tm-limit-scope: key
x-tm-limit-kind: rpm
x-tm-limit-id: key:<key id>
json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "configured quota exhausted",
    "type": "requests",
    "metadata": {
      "error_type": "rate_limit",
      "origin": "gateway_admission",
      "limit_scope": "key",
      "limit_kind": "rpm",
      "limit_id": "key:<key id>",
      "retryable": true,
      "retry_at": "2026-09-24T10:14:04.000Z"
    }
  },
  "request_id": "..."
}
Surfacecodetype
/v1/chat/completions, /v1/responsesrate_limit_exceeded, the OpenAI code that OpenAI SDKs and coding agents readrequests, or tokens for a token limit
/v1/decisions, images, videorate_limitinvalid_request_error
Anthropic surfaceA native rate_limit_error with the same error_type and metadata, so the Anthropic SDK's backoff runs

error_type and x-tm-error-code are always rate_limit.

retry-after

  • A rate limit's retry-after is in whole seconds, 1 to 59. The usage_limited refusal sends 60 or 3,600.
  • On an RPM or token limit, it is the time until the rolling window has room for the request.
  • On a limit on requests at once, it is 10 seconds. A slot becomes free when one of your running requests ends. No window can predict that time.
  • metadata.retry_at is the same instant.
  • Other requests can take the room first. Then a retry can get another 429 with the rest of the wait. Wait for retry-after, then retry.
Note

You cannot raise a key's RPM ceiling yourself. On /console/limits you can only lower a key's RPM and set its other limits.

Provider rate limits

A provider can rate-limit RouterPlus upstream. Then RouterPlus fails over to another deployment and pauses that provider's pool. You see a provider rate_limit (x-tm-error-origin: upstream) only when every candidate was rate-limited. Its retry-after is the provider's value, up to 59 seconds. A provider 429 that names no wait gets 10 seconds.

Organization tokens and concurrency

Every organization and every key also has a tokens-per-minute limit and a concurrency limit, in the same shared window:

ScopeRPMTokens per minuteConcurrent requests
Organization (all keys together)300 (20 until the first purchase)1,000,0008
Keyits ceiling above1,000,0008
  • These are the defaults. Set your own on /console/limits or with POST /api/admission-limits.
  • A key's RPM cannot go above its ceiling. You can add a limit for one model on top.
  • Under a contract, RouterPlus can replace these defaults and the keys' RPM ceiling for your organization. A limit that you set still applies and can only lower them.
  • At admission, tokens are an estimate: one token for each four UTF-8 bytes of the request, rounded up, plus a media allowance, plus the output limit (at most 32,768 tokens of it). When the request completes, observed usage replaces the estimate. The balance hold in The worst-case reserve counts one token for each byte.
  • A refusal has the 429 shape above, with limit_scope org or key and limit_kind tpm or concurrency. On the OpenAI surface, a token-limit refusal has "type": "tokens". A refusal for requests at once sends retry-after: 10.

Every admitted response has x-tm-remaining-rpm and x-tm-remaining-tpm. Each is the smallest remaining amount across the scopes that the request claimed, at that moment. GET /v1/limits?model=<id> on the gateway returns the effective limits for your key.

Provider pools

Each house deployment has a declared pool. One organization can use at most half of a pool's usable capacity, or three quarters on the decision-model pools. When the pool is full, you get a 429 with x-tm-error-origin: upstream_quota and x-tm-limit-scope: pool. Limits and capacity covers workspace and principal scopes.

Dedicated endpoints

A dedicated endpoint has its own limits. For its traffic, they replace the defaults above.

  • The limits can include a requests-per-second limit: a count per second, or a paced limit that holds a short burst in a queue.
  • A paced request that waited has x-tm-queue-ms, the wait in milliseconds.
  • Above the hard rate, the refusal is x-tm-limit-kind: rps. When the wait would pass its bound, it is rps_queue.
  • Refusals have x-tm-limit-scope: endpoint.

Budgets, key limits and grants

A guardrail budget limits the spend of its targets for a day, week, month or lifetime. A key's own spend limit (limit and limit_reset on the key) limits one key. A used-up budget or key limit returns 403 budget_exceeded. To see every budget and key limit with the spend of this period, open Governance > Budgets in the console.

A grant raises a budget or a key limit for a set time. Then the base value applies again. To request, approve, reject or cancel a grant, open Access > Grants in the console. The management API has the same actions.

Granted limits show in these places:

  • x-tm-grants on the response: the ids of the active grants that applied to the request. A refusal also has it.
  • The budget_exceeded message. It adds "(raised by grant <id>)" when a grant raised the limit.
  • GET /v1/guardrails/:id/status: limit_usd is the granted limit, base_limit_usd the guardrail's own limit, and grant_id the grant.
  • Key reads (GET /v1/keys, GET /v1/keys/:id) and GET /v1/key: limit is the granted limit, base_limit the key's own limit, and grant_id the grant.
  • Budget alerts. They count against the granted limit.

A guardrail with "overridable": false takes no grant. On the org, its budgets limit every grant.

Monthly spend caps

You can set two optional hard caps in the console:

Rules:

  • Both caps run on the UTC calendar month and reset at the first instant of the next month.
  • They can overlap. The strictest one wins.
  • In the console, a blank cap field changes nothing. A cap of 0 removes the cap.
  • The console marks keys near their cap. It shows each key's month-to-date spend against its cap.

How enforcement works

Before RouterPlus sends anything, it reserves a worst-case cost for the request. See The worst-case reserve. The cap check adds this month's settled spend and the worst-case cost of every request in flight, this one included. If the sum is above the cap, RouterPlus refuses the request before it costs anything. RouterPlus claims the in-flight amount synchronously, so concurrent requests cannot pass the cap together.

The check is conservative. RouterPlus can refuse a request near the cap even when its settled cost would have fit. A tight max_tokens lowers the worst-case reserve and gives you more room near the cap.

The cap refusal

A cap breach is the standard out-of-credits 429: insufficient_quota, a class that OpenAI SDKs recognize. The message and a header give the reset time:

HTTP/1.1 429 Too Many Requests
x-tm-error-code: insufficient_quota
x-tm-cap-reset: 2026-10-01T00:00:00.000Z
x-should-retry: false
json
{
  "error": {
    "code": "insufficient_quota",
    "type": "insufficient_quota",
    "message": "org monthly cap exceeded; resets 2026-10-01T00:00:00.000Z",
    "metadata": { "error_type": "insufficient_quota", "origin": "gateway_admission", "retryable": false }
  },
  "request_id": "..."
}
  • The message names the scope of the cap that was reached: org or key.
  • On the Anthropic surface, the body is a native billing_error with the same error_type and message.
  • The refusal has no retry-after. x-should-retry: false tells the OpenAI and Anthropic SDKs and Claude Code not to retry.
  • Do not retry before the reset time. Backoff does not change a hard cap.

The worst-case reserve

The cap and balance checks use a pessimistic cost estimate. There is one exception: a request without an output limit holds at most 32,768 output tokens. A longer answer is still charged in full.

InputValue
Estimated input tokensOne per UTF-8 byte of the request body, plus 65,536 per image or document part. An image sent inline as base64 counts the 65,536 only, not its bytes.
Assumed output tokensYour max_tokens (or max_completion_tokens), all of it. When omitted, at most 32,768, and the request is sent with the model's own maximum, fitted to its context window. More than the model's own max_output_tokens (32,768 when no maximum is declared) is a 400.
Images (/v1/images/generations)Assumed output = n × the model's per-image ceiling.
RoundingThe reserve rounds up. Settlement rounds down.

The reserve exists only while the request is in flight. At settlement, RouterPlus releases it and records the observed cost: the usage that the provider reports, at the prices pinned when the request was admitted. RouterPlus debits your balance and caps only for observed usage, with two exceptions:

  • An attempt can end before the provider reports usage, because you cancelled it or the provider failed during the answer. It is charged its input and the output already streamed to you.
  • An attempt whose outcome the gateway could not observe (unknown_after_crash) settles at the reserved maximum, because the provider may have billed the call. See Pricing & billing.

Balance exhaustion

The org balance must cover the worst-case reserve of every request that the org has in flight, this one included. When it cannot, the refusal is the same insufficient_quota 429, with a different message:

json
{
  "error": {
    "code": "insufficient_quota",
    "type": "insufficient_quota",
    "message": "insufficient marketplace credits for authorized house fallback",
    "metadata": { "error_type": "insufficient_quota", "origin": "gateway_admission", "retryable": false }
  },
  "request_id": "..."
}
  • To tell the two insufficient_quota cases apart in code: only cap breaches have x-tm-cap-reset.
  • A balance refusal has no retry-after and no x-should-retry. When your own requests in flight hold the balance, the balance becomes free as they end, and a retry can succeed. Otherwise, add credits.
Tip

Signup alone does not add free credit. An invitation link from RouterPlus does. Buy credits in Billing. Eligible purchases may receive matching promotional credit. If calls return insufficient_quota, check your balance and spend caps there.

Handling the two 429s

Both refusals are 429s, so the OpenAI SDK raises RateLimitError for both. Read error_type. Retry a rate_limit after retry-after. Stop on insufficient_quota.

python
import os, time
from openai import OpenAI, RateLimitError

client = OpenAI(base_url="https://demo-api.routerplus.com/v1", api_key=os.environ["TM_API_KEY"])

def create(**kw):
    try:
        return client.chat.completions.create(**kw)
    except RateLimitError as e:
        kind = e.response.json()["error"]["metadata"]["error_type"]
        if kind == "rate_limit":
            time.sleep(int(e.response.headers.get("retry-after", "10")))
            return client.chat.completions.create(**kw)  # one retry
        raise  # insufficient_quota: retrying cannot help; add credits or raise the cap
typescript
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://demo-api.routerplus.com/v1", apiKey: process.env.TM_API_KEY });

try {
  await client.chat.completions.create({
    model: "claude-haiku-5-5",
    messages: [{ role: "user", content: "hello" }],
  });
} catch (err) {
  if (err instanceof OpenAI.APIError && err.status === 429) {
    const kind = (err.error as { metadata?: { error_type?: string } })?.metadata?.error_type;
    if (kind === "rate_limit") {
      // wait Number(err.headers?.get("retry-after")) seconds, then retry
    } else {
      // insufficient_quota: stop; x-tm-cap-reset (cap breaches only) says when a cap reopens
      const capReset = err.headers?.get("x-tm-cap-reset");
    }
  }
}

Other limits

  • Monthly spend caps only. The monthly caps use the UTC calendar month and nothing shorter. For a daily or weekly limit, use a guardrail budget or a key limit with limit_reset.
  • No self-serve RPM raises. Trial keys are 20 RPM. Console keys are 300, or 20 until the organization's first purchase. A limit that you set can only lower a key's RPM.
  • RouterPlus refuses sign-ups that look automated or abusive. The page says that unusual activity was detected. If this happens to you, contact support. Existing accounts sign in without limit.
  • Request size: a body over 10 MB gets a 413 request_too_large.
  • Image response size: an upstream image response over 32 MiB is a 502 gateway_error and bills nothing. It is not a 413. Lower n or the quality.
  • An image request holds one admission slot for the whole render, typically 10 to 60 s. The gateway sends no first byte before the image is ready.

For agents: /docs/limits.md and /llms.txt