Rate limits
Patomic rate-limits per API key, per minute. Each key has its own rate_limit_rpm value, set at mint time and modifiable via PATCH /v1/keys/{id}.
How it works
Section titled “How it works”A single SQL statement enforces the limit atomically — there is no read-then-write race window:
INSERT INTO rate_limits (key, count, window_start, expires_at)VALUES (?, 1, ?, ?)ON CONFLICT(key) DO UPDATE SET count = count + 1RETURNING count;The key is ${api_key_id}:${minute_window}. After incrementing, if count > rate_limit_rpm, the request returns 429 and the increment is preserved (so a flood of attempts after the limit doesn’t reset the counter).
Response headers
Section titled “Response headers”Every successful response includes:
x-ratelimit-limit: 600 # your key's rpmx-ratelimit-remaining: 587 # calls left in the current minutex-ratelimit-reset: 1715292000 # unix epoch when the window resetsWhen you exceed the limit, you also get:
Retry-After: 32…the seconds until the current window expires. Always honour Retry-After — fixed-interval retries are a footgun.
Handling 429 cleanly
Section titled “Handling 429 cleanly”async function callPatomic(path: string, init: RequestInit = {}): Promise<Response> { for (let attempt = 0; attempt < 5; attempt++) { const res = await fetch(`https://patomic-api.pedrotengelmann.workers.dev${path}`, { ...init, headers: { Authorization: `Bearer ${process.env.PATOMIC_KEY}`, ...init.headers }, });
if (res.status !== 429) return res;
const wait = Number(res.headers.get("retry-after") ?? 1) * 1000; await new Promise((r) => setTimeout(r, wait)); } throw new Error("rate-limited 5 times in a row — investigate");}When you need more
Section titled “When you need more”Mint a second key with a higher limit, or rotate an existing one upward via PATCH /v1/keys/{id} with {"rate_limit_rpm": 6000}. There is no enterprise plan upsell wall today — limits exist to protect Patomic itself, not to extract revenue.