Errors & Rate Limits
HTTP status codes, error response format, rate limiting details, and retry strategies for the ReelPlus API.
All API errors return a consistent JSON structure:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "A human-readable description of what went wrong."
}
}
| Status | Meaning | When It Occurs |
|---|
200 | OK | Request succeeded |
304 | Not Modified | Content unchanged (cached) |
400 | Bad Request | Invalid parameters or malformed request |
401 | Unauthorized | Missing or invalid Authorization header |
403 | Forbidden | Invalid/revoked API key or plan does not include API access |
404 | Not Found | Resource does not exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
| Code | Message | Fix |
|---|
INVALID_DATE | Invalid date format | Use ISO 8601: YYYY-MM-DD |
INVALID_DATE_RANGE | start_date after end_date | Swap your dates |
INVALID_PARAMETER | Invalid value | Check endpoint docs |
MISSING_PARAMETER | Required param missing | Include required params |
| Code | Message | Fix |
|---|
UNAUTHORIZED | Missing or invalid Authorization header | Add Authorization: Bearer rp_xxx |
| Code | Message | Fix |
|---|
INVALID_API_KEY | Key not found or revoked | Check the key. In the sandbox, use the demo key from the API Overview |
PLAN_LIMIT | Plan does not include API access | API access is available on Enterprise plans, on request |
| Code | Message | Fix |
|---|
NOT_FOUND | Video not found / Widget not found | Check the ID against the list endpoint |
| Code | Message | Fix |
|---|
RATE_LIMIT_EXCEEDED | Too many requests | Wait and retry (see below) |
| Scope | Limit | Window |
|---|
| Per API Key | 60 requests | 1 minute (fixed window) |
Every authenticated response includes (401 and 403 carry none, since no key was matched):
| Header | Description | Example |
|---|
X-RateLimit-Limit | Max requests per window | 60 |
X-RateLimit-Remaining | Remaining in current window | 45 |
X-RateLimit-Reset | Unix timestamp of reset | 1706540400 |
When exceeded, you also get Retry-After (seconds to wait).
Implement exponential backoff for production integrations:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.ok) return response.json();
if (response.status === 429) {
const retryAfter = response.headers.get("Retry-After");
const wait = retryAfter
? parseInt(retryAfter, 10) * 1000
: Math.pow(2, attempt) * 1000;
await new Promise(r => setTimeout(r, wait));
continue;
}
if (response.status >= 500) {
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
continue;
}
const error = await response.json();
throw new Error(`${response.status}: ${error.error.message}`);
}
throw new Error("Max retries exceeded");
}
import time, requests
def fetch_with_retry(url, headers, params=None, max_retries=3):
for attempt in range(max_retries):
resp = requests.get(url, headers=headers, params=params)
if resp.ok:
return resp.json()
if resp.status_code == 429:
wait = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
if resp.status_code >= 500:
time.sleep(2 ** attempt)
continue
raise Exception(f"{resp.status_code}: {resp.json()['error']['message']}")
raise Exception("Max retries exceeded")
Never retry 401 or 403 errors — they require manual intervention (new key or plan upgrade). Only retry 429 and 5xx errors.