Rate limits
Every account has a plan. A plan limits requests per second and per calendar month, counted per account: every token you create draws on the same budget. The pricing page compares the plans.
| Plan | Price | Requests per month | Requests per second | Extras |
|---|---|---|---|---|
| Free | $0 | 100,000 | 5 | |
| Developer | $20 / month | 1,000,000 | 25 | |
| Business | $100 / month | 10,000,000 | 100 | 99.9% uptime SLA, priority email support |
Prices are in US dollars, plus applicable taxes. Commercial use is allowed on every plan. Change plans on your billing page.
What counts
Months are calendar months in UTC: the quota resets at 00:00 UTC on the 1st. Successful
responses (2xx), redirects (3xx) and client errors (4xx) count. These don't: 403
(verify your email first), 429 (a limit turned the request away) and 5xx (our failure).
Paid plans get 10% of headroom: requests above the quota are still served until 110% of it, so a busy month doesn't break your integration while you upgrade. The Free plan stops at its quota. We email you when you reach 80% and 100% of it.
Monthly quotas aren't enforced yet. Until they are, no request is refused for the month,
no quota emails go out, and the rate-limit headers carry only the per-second burst limit.
We'll email every account before quotas start.
Traffic that degrades the service for others can be throttled or suspended under the fair use terms.
Rate-limit headers
Every response carries the
IETF rate-limit fields
next to the older X-RateLimit-* pair:
| Header | Example | Meaning |
|---|---|---|
RateLimit-Policy |
"burst";q=5;w=1, "monthly";q=100000 |
Your limits: q requests per w seconds, and monthly per calendar month. |
RateLimit |
"burst";r=4;t=1, "monthly";r=98766;t=345600 |
What remains (r) and the seconds until each resets (t). |
X-RateLimit-Limit |
5 |
Requests allowed per second. |
X-RateLimit-Remaining |
4 |
Requests left this second. |
Over a limit
Both limits answer 429 Too Many Requests with a Retry-After header in seconds.
Over the per-second limit, Retry-After is a second or so, and X-RateLimit-Reset gives the
Unix time the window resets:
{
"message": "Too Many Attempts."
}
Over the monthly quota, Retry-After is at most an hour (check back then), RateLimit's
monthly t counts down to the 1st, and the message says what to do:
{
"message": "Your Free plan's 100,000 requests for September 2026 are used up. Upgrade at https://www.timezone.io/billing for more, or wait until the quota resets on October 1, 2026 at 00:00 UTC."
}
Example — retry politely after a 429
A short Retry-After (the per-second limit) is worth waiting for; add a little jitter so
concurrent clients don't stampede back at the same instant. A long one means the monthly
quota: waiting won't help, so stop and surface the message, which says how to get more.
async function getWithRetry(url, options, attempts = 3) {
for (let attempt = 1; attempt <= attempts; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
const retryAfter = Number(response.headers.get('Retry-After') ?? 1);
if (retryAfter > 60) {
// The monthly quota: the message names your plan and how to get more.
const { message } = await response.json();
throw new Error(message);
}
const jitter = Math.random() * 250;
await new Promise((resolve) =>
setTimeout(resolve, retryAfter * 1000 + jitter),
);
}
throw new Error('Rate limited after retries');
}
Avoid hitting the limit at all
- Cache responses.
meta.tzdb_versiontells you when the underlying data actually changed — cached reference data (zones, countries, abbreviations) stays valid until the next tzdb release. - Prefer one filtered list call over many lookups.
GET /v1/timezones?country=usis one request; fetching 29 zones one by one is 29. - Spread scheduled jobs out rather than firing them on the same second.