Rate Limits
The Prooflio API enforces rate limits using a sliding window algorithm powered by Upstash Redis. Limits vary by your organization’s plan and the type of endpoint.
Limits by Plan
| Plan | Requests per Minute | Identifier |
|---|---|---|
| Growth | 60 | Per API Key |
| Agency | 200 | Per API Key |
Public Endpoints
Widget endpoints (/api/v1/widgets/{id}/embed and /api/v1/widgets/{id}/schema) do not require authentication and are rate-limited by IP address:
| Endpoint | Limit | Identifier |
|---|---|---|
| Widget Embed & Schema | 60 per minute | Per IP Address |
Need higher limits for enterprise usage? Contact us.
Rate-Limit Headers
Every API response includes headers that report your current quota status:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum number of requests allowed in the current window. |
X-RateLimit-Remaining | Number of requests remaining in the current window. |
X-RateLimit-Reset | Unix timestamp (in seconds) when the current window resets. |
Example response headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1695820800429 Too Many Requests
When you exceed the rate limit, the API returns a 429 status code with a Retry-After header indicating how many seconds to wait before retrying.
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 12 seconds.",
"details": []
}Response headers:
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1695820812Best Practices
Exponential Backoff
When you receive a 429 response, wait before retrying using exponential backoff:
async function requestWithBackoff(fn, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fn();
if (response.status !== 429 || attempt === maxRetries - 1) {
return response;
}
const retryAfter = response.headers.get('Retry-After');
const delay = retryAfter
? parseInt(retryAfter, 10) * 1000
: Math.min(1000 * 2 ** attempt, 30000);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}Reduce Request Volume
- Fetch larger pages (
limit=100) instead of many small pages. - Cache responses locally when review data doesn’t change frequently.
- Use the
sinceparameter on the List Reviews endpoint to fetch only new reviews since your last sync.
Rate limits are applied per API key, not per IP address. Distributing requests across multiple servers using the same key will not increase your quota.