Developer Guide
Rate Limits & Errors
The PollsLive API uses per-key rate limits and returns consistent JSON error objects with machine-readable codes.
Rate limits
Limits are enforced per API key (or per OAuth client) using a Redis fixed-window counter. Exceeding the limit returns 429 Too Many Requests.
| Endpoint group | Limit | Window |
|---|---|---|
All /api/v1/ endpoints | 120 requests | 1 minute |
POST /api/v1/media | 30 requests | 1 minute |
POST /api/oauth/token | 10 requests | 1 minute per client_id |
Enterprise plan customers can request higher limits. Contact our team.
Rate limit headers
Every API response includes rate limit metadata headers:
X-RateLimit-Limit: 120
X-RateLimit-Window: 60sExceeding the limit returns 429 with the rate_limited error code. The window is a fixed 60-second bucket - wait for it to reset before retrying.
Error response format
All API errors return a JSON body with a nested error object containing a machine-readable code and a human-readable message:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"code": "not_found",
"message": "Poll not found."
}
}Validation errors return 422 with a details field inside the error object:
{
"error": {
"code": "validation_failed",
"message": "Request validation failed.",
"details": {
"fieldErrors": { "title": ["String must contain at least 1 character(s)"] },
"formErrors": []
}
}
}OAuth token errors follow RFC 6749 §5.2 format instead:
{
"error": "invalid_client",
"error_description": "Invalid client credentials."
}Error codes
| HTTP status | code | Meaning |
|---|---|---|
| 400 | invalid_json | Request body is not valid JSON |
| 401 | missing_authorization | No Bearer token provided |
| 401 | invalid_api_key | Unknown or incorrect API key |
| 401 | revoked_api_key | Key was revoked |
| 401 | expired_api_key | Key expired after rotation |
| 401 | invalid_oauth_token | OAuth token is invalid or expired |
| 402 | upgrade_required | Action requires Pro/Enterprise plan |
| 403 | insufficient_scope | Credential lacks the scope this endpoint requires |
| 404 | not_found | Resource not found |
| 409 | already_responded | This voter already answered the slide/poll |
| 422 | validation_failed | Request body failed schema validation |
| 429 | rate_limited | Too many requests - retry after the 60s window resets |
| 500 | internal_error | Unexpected server error |
Retries & backoff
We recommend an exponential backoff with jitter strategy for production integrations:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, options);
if (res.status === 429) {
// PollsLive uses a fixed 60s window and does not send Retry-After,
// so back off exponentially (capped at the window length).
const backoff = Math.min(1000 * 2 ** attempt + Math.random() * 500, 60000);
await new Promise((r) => setTimeout(r, backoff));
continue;
}
if (res.status >= 500 && attempt < maxRetries) {
const backoff = Math.min(1000 * 2 ** attempt + Math.random() * 500, 30000);
await new Promise((r) => setTimeout(r, backoff));
continue;
}
return res;
}
throw new Error("Max retries exceeded");
}Do not retry on 4xx errors (other than 429) - they indicate a problem with your request that won't resolve with retrying.
OAuth error format
The token endpoint (POST /api/oauth/token) returns errors in RFC 6749 format:
| error | Meaning |
|---|---|
invalid_request | Missing or malformed parameters |
invalid_client | Unknown client_id or wrong client_secret |
access_denied | Client is revoked or rate-limited |
unsupported_grant_type | Only client_credentials is supported |
Still have questions?
Our team is happy to help.