Error Handling
HTTP status codes, error response format, and common error examples.
Error Response Format
All API errors return a JSON object with an error field (string). Some errors include a code field for programmatic handling and a details object with additional context.
{
"error": "Human-readable error message",
"code": "machine_readable_code",
"details": { ... }
}| Field | Type | Present | Description |
|---|---|---|---|
error | string | Always | Human-readable error description |
code | string | Sometimes | Machine-readable error code for programmatic handling |
details | object | Sometimes | Additional context about the error |
HTTP Status Codes
| Status Code | Meaning | Description |
|---|---|---|
200 | OK | Request successful |
202 | Accepted | Async job accepted for processing |
400 | Bad Request | Invalid request parameters or payload |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | API key lacks required scope, or insufficient credits |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
503 | Service Unavailable | AI detection service temporarily unavailable |
Common Errors
Missing API Key
Status: 401
{
"error": "API key is required. Please provide it in X-API-Key header."
}Invalid API Key
Status: 401
{
"error": "Invalid API key."
}Expired or Inactive API Key
Status: 401
{
"error": "API key is invalid, inactive, or expired."
}Missing Required Scope
Status: 403
{
"detail": "API key does not have required scope: AI Detector"
}API Key Limit Reached
Status: 403
{
"error": "API key limit reached",
"code": "key_limit_reached",
"details": {
"active_keys": 5,
"max_keys": 5,
"plan": "1M"
}
}Invalid Request Payload
Status: 400
{
"error": "Invalid payload",
"code": "invalid_payload",
"details": {
"content": ["This field is required."]
}
}Insufficient Credits
Status: 403
{
"error": "Insufficient credits",
"code": "insufficient_credits",
"details": {
"credits": 50,
"required": 120
}
}Credits Exhausted (Paid Plan)
Status: 403
{
"error": "Credits exhausted. Credits reset on next billing cycle.",
"code": "credits_exhausted",
"details": {
"plan": "1M",
"credits": 0
}
}Trial Expired
Status: 403
{
"error": "Trial expired, please subscribe",
"code": "trial_expired"
}Rate Limit Exceeded
Status: 429
The response includes a Retry-After header indicating how many seconds to wait.
Too Many Pending Jobs
Status: 429
{
"error": "Too many pending jobs. Wait for existing jobs to complete.",
"code": "too_many_pending_jobs",
"details": {
"pending": 5,
"limit": 5
}
}Service Unavailable
Status: 503
{
"error": "No active detector services configured"
}Rate Limits
Rate limits are applied at multiple levels:
| Scope | Default Limit |
|---|---|
| Per IP (burst) | 60 requests / minute |
| Per IP (sustained) | 3,000 requests / hour |
| Per user (global) | 60 requests / minute |
| Detector (sync) | 10 requests / minute |
| API key creation | 10 requests / minute |
Rate limits may vary by plan. Higher-tier plans may have higher limits.
Async requests are not subject to the per-minute rate limit — they are constrained by credits and the pending jobs limit (varies by plan, see Async Jobs).
Best Practices
- Always check the HTTP status code before parsing the response body.
- Use the
codefield (when present) for programmatic error handling instead of parsing theerrorstring. - Implement retry logic with exponential backoff for
429and5xxerrors. - Do not retry
400,401, or403errors — these indicate a problem with the request that must be fixed. - Log error responses for debugging.