Rate limits
What the Tanqory spec declares about rate limiting today — and what it does not.
The OpenAPI spec does not yet declare rate-limit metadata —
no headers, no tier values, no x-rate-limit extension. This page
documents only what is verifiable. Tier numbers + per-key limits live
in the legal terms; once the spec is amended to expose them
programmatically, this page will be rewritten.
The state of the spec
We searched the entire Admin API OpenAPI document for rate-limit indicators. Findings:
| Field searched | Occurrences | Note |
|---|---|---|
X-RateLimit-* header in any response | 0 | Not yet emitted in the declared response headers. |
Retry-After header in any response | 0 | Not yet declared in spec. |
x-rate-limit OpenAPI extension | 0 | No vendor extension declared. |
429 status code declared on operations | 1 | Documented below. |
The runtime gateway does emit rate-limit headers and a Retry-After
header on 429 — the spec is simply behind the runtime here. The
platform team plans to amend the spec to declare these formally
([FOUNDER TO CONFIRM] for the target schema).
The single declared 429
| Endpoint | Description (verbatim from spec) |
|---|---|
POST /api/v1/auth/activity/export | "Too many export requests" |
This is an endpoint-specific quota — exporting activity logs is expensive, and the gateway throttles repeated calls per user. The runtime envelope follows the standard error contract (see Errors).
For every other endpoint the runtime may also return 429 even though
the spec does not yet declare it. Treat any 429 from the gateway as
a retryable signal regardless of the operation.
What to honor at runtime
Until the spec is amended:
| When you see | Do this |
|---|---|
Response has Retry-After: <seconds> header | Wait that many seconds, then retry the same request. |
Response has Retry-After: <HTTP-date> header | Wait until that absolute time. |
429 without Retry-After | Back off exponentially with jitter (see below), max 4 attempts. |
503 (Service unavailable) | Treated like 429 for retry purposes — back off + retry. |
Add randomness to the delay so many clients don't retry in lockstep
(a "thundering herd"). Honor Retry-After when present; otherwise:
async function withRetry(fn, max = 4) {
for (let attempt = 0; ; attempt++) {
const res = await fn();
if (res.status !== 429 && res.status !== 503) return res;
if (attempt >= max) return res;
const retryAfter = Number(res.headers.get('Retry-After'));
const base = Number.isFinite(retryAfter)
? retryAfter * 1000
: Math.min(1000 * 2 ** attempt, 30_000); // 1s, 2s, 4s… capped
await new Promise((r) => setTimeout(r, base + Math.random() * 250)); // + jitter
}
}
Throttle proactively. The gateway emits these headers (verified live)
— read them to slow down before you hit 429:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Ceiling for the current window. |
X-RateLimit-Remaining | Calls left in this window — pause as it nears 0. |
X-RateLimit-Reset | When the window resets. |
(On infrastructure endpoints such as /api/health/live these may be
absent or non-numeric — rely on them only for normal API calls.)
Per-key limits
Per-key rate limits are tiered by plan (Standard / Growth / Enterprise)
and currently documented in the
API License and Terms,
not the OpenAPI spec. [FOUNDER TO CONFIRM] — confirm the canonical
numbers and either inline them here or link to the legal page section
anchor before launch.
What is not yet documented (deliberate gaps)
| Gap | Status |
|---|---|
| Default limit per key per service | Not declared in spec; see legal terms. |
| Burst capacity / leaky-bucket parameters | Not declared. |
| Per-endpoint cost weighting | Not declared. |
X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset headers | Emitted at runtime but not declared in spec. |
| Resource-specific limits (e.g. webhook delivery / bulk imports) | Not declared per-endpoint. |
When the spec is amended to add these, this page will be rewritten to reference them directly + the gateway-side verification.
Next steps
| Topic | When to read it |
|---|---|
| Errors | The 429 envelope follows the same shape as other 4xx. |
| Webhooks | Webhook deliveries have a separate retry policy. |
| Status | If 429 is paired with a 503, check the incident page. |