Errors & Rate Limits
Response Format
All API responses follow a consistent format:
Success:
{
"success": 1,
"data": { ... }
}
Error:
{
"error": 1,
"message": "Human-readable error description"
}
Some errors include a code field for programmatic handling:
{
"error": 1,
"code": "NO_ORGANIZATION",
"message": "User has no organization attached"
}
HTTP Status Codes
| Code | Meaning |
|---|---|
200 |
Success |
201 |
Created (new resource) |
204 |
No Content (successful deletion) |
400 |
Bad Request — invalid parameters or missing required fields |
401 |
Unauthorized — missing or invalid authentication |
403 |
Forbidden — insufficient permissions |
404 |
Not Found — resource doesn't exist |
429 |
Too Many Requests — rate limit exceeded |
500 |
Internal Server Error |
Common Errors
Authentication Errors
// Missing auth
{ "error": 1, "message": "Authentication required" }
// Invalid/expired token or API key
{ "error": 1, "message": "Invalid or expired token" }
{ "error": 1, "message": "Invalid API key" }
// Wrong user type
{ "error": 1, "message": "Admin access required" }
Validation Errors
// Missing required field
{ "error": 1, "message": "Survey name is required" }
// Invalid ID parameter
{ "error": 1, "message": "Invalid survey ID" }
Resource Errors
// Not found
{ "error": 1, "message": "Survey not found" }
// Organization database not configured
{ "error": 1, "message": "Organization database not configured" }
Rate Limits
| Endpoint Group | Window | Max Requests |
|---|---|---|
General API (/api/*) |
15 minutes | 1,000 |
Authentication (/api/auth/*) |
15 minutes | 20 |
Registration (/api/register/*) |
1 hour | 10 |
Rate Limit Headers
Every response includes:
RateLimit-Limit: 1000
RateLimit-Remaining: 994
RateLimit-Reset: 1714060800
Handling Rate Limits
When you exceed the limit:
// HTTP 429
{ "error": 1, "message": "Too many attempts. Please try again later." }
Best practices:
- Cache responses when possible
- Use batch endpoints (e.g.,
chart-data-batch) instead of individual requests - Implement exponential backoff on 429 responses
- Monitor
RateLimit-Remainingto stay within limits
Error Handling Best Practice
async function apiCall(path) {
const response = await fetch(`${BASE_URL}${path}`, {
headers: { 'X-API-Key': API_KEY },
});
if (response.status === 429) {
// Rate limited — wait and retry
const retryAfter = response.headers.get('Retry-After') || 60;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return apiCall(path);
}
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || `API error: ${response.status}`);
}
return data;
}