Rate limits
Rate limits protect the platform and keep response times predictable for everyone. Limits are enforced per credential across all Talero servers.
Limits
| Scope of limit | Limit | Window |
|---|---|---|
| API requests, per credential (API key or OAuth access token) | 100 requests | 60 seconds |
OAuth token endpoint (POST /api/oauth/token), per client and IP | 10 requests | 60 seconds |
Response headers
Every authenticated response — success or error, including the 429 itself — reports the state of your window. Responses that never identified a credential (for example a 401 for an invalid key) carry no rate-limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Requests allowed per window (100). |
X-RateLimit-Remaining | Requests remaining in the current window. |
X-RateLimit-Reset | Seconds until the current window resets. |
Handling 429
When the limit is exceeded, the API returns 429 with problem code rate_limited and a Retry-After header (seconds):
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 17
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 17
{
"type": "https://docs.talero.dk/problems/rate_limited",
"title": "Rate limit exceeded",
"status": 429,
"detail": "Rate limit exceeded.",
"code": "rate_limited"
}
Honor Retry-After when present, and fall back to exponential backoff with jitter:
async function taleroFetch(url, options = {}, maxAttempts = 5) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await fetch(url, {
...options,
headers: { 'X-API-Key': process.env.TALERO_API_KEY, ...options.headers },
});
if (response.status !== 429) return response;
if (attempt === maxAttempts) return response;
const retryAfter = Number(response.headers.get('Retry-After'));
const backoff = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: Math.min(60_000, 1000 * 2 ** (attempt - 1));
const jitter = Math.random() * 250;
await new Promise((resolve) => setTimeout(resolve, backoff + jitter));
}
}
Staying under the limit
- Use webhooks instead of polling for changes.
- Request up to 200 items per page instead of many small pages — see Pagination.
- Use
since/untilfilters to fetch only what changed. - Watch
X-RateLimit-Remainingand slow down before you hit zero. - Cache OAuth access tokens for their full one-hour lifetime; do not request a new token per API call.