Rate limits
Per-credential request budgets, the headers that report them, and how to back off.
1 min read
Limits apply per credential: each API key, and each OAuth connection (one user’s grant to one app), has its own budget.
| Limit | Budget |
|---|---|
| All requests | 120 per minute |
Writes (POST, PATCH, PUT, DELETE) | 30 per minute |
| Concurrent requests | 10 in flight |
Analytics endpoints (/v1/analytics/* and other computed reports) cost two requests each, because they do more work.
Headers#
Every response reports where you stand, using the IETF RateLimit-* headers (with X-RateLimit-* aliases for older clients):
RateLimit-Limit: 120
RateLimit-Remaining: 87
RateLimit-Reset: 23RateLimit-Reset is the number of seconds until the budget refills, not a timestamp.
When you hit a limit#
The API answers 429 with code rate_limited and a Retry-After header in seconds. Wait that long, then retry. Retrying sooner only fails again.
{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Rate limit exceeded. Retry in 12 seconds.",
"doc_url": "https://developers.listener.com/docs/errors#rate_limited",
"request_id": "req_8f2LkQ0aZ1"
}
}Staying under the limits#
- Page big. Use
limit=100on lists. - Ask once for many shows. Analytics endpoints take
show_ids; one request for ten shows beats ten requests. - Cache. Analytics are themselves cached for up to two minutes, so polling faster than that returns the same numbers. Use
If-None-Matchwith theETagto make unchanged polls cheap. - Subscribe instead of polling. Webhooks tell you when data changes;
analytics.refreshedfires when a platform’s numbers advance. - Limit concurrency to a handful of parallel requests per credential.
Need more headroom for a real workload? Email tech@listener.com with your use case and expected volume.