API reference
Error Reference
All errors follow a consistent JSON structure. Use the code field for programmatic handling and message for human-readable context.
Error response structure
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The field 'jurisdiction' is required.",
"details": {
"field": "jurisdiction",
"issue": "missing_required_field"
}
}
}HTTP status codes
OK
Request succeeded. Body contains the result.
Created
Resource created successfully.
No Content
Success with no response body (e.g. DELETE).
Bad Request
Malformed JSON or missing required fields.
Unauthorized
Missing or invalid API key.
Forbidden
Key does not have the required scope for this action.
Not Found
The requested resource does not exist.
Conflict
A conflicting resource already exists.
Unprocessable Entity
Validation failed — see details in the error body.
Too Many Requests
Rate limit exceeded. See Retry-After header.
Internal Server Error
Unexpected server error. Contact support if persistent.
Service Unavailable
Temporary outage. Check status.policifyai.com.
Error codes
| Code | Status | Meaning |
|---|---|---|
| UNAUTHORIZED | 401 | API key missing, invalid, or revoked |
| FORBIDDEN | 403 | Key does not have the required scope |
| NOT_FOUND | 404 | Resource with the given ID does not exist |
| VALIDATION_ERROR | 422 | One or more fields failed validation |
| MISSING_FIELD | 422 | A required field was not included |
| INVALID_FIELD | 422 | A field has an invalid value or format |
| RATE_LIMITED | 429 | Too many requests in the current window |
| GENERATION_FAILED | 500 | Policy generation encountered an AI error |
| PLAN_LIMIT_REACHED | 403 | Your plan's policy generation quota is exhausted |
| CLIENT_NOT_FOUND | 404 | The specified client_id does not exist |
| WEBHOOK_ENDPOINT_INVALID | 422 | The webhook URL is not reachable or returned non-2xx |
Recommended error handling
async function callPolicify(endpoint, options) {
const res = await fetch(`https://policifyai.com/api/v1${endpoint}`, options)
if (res.ok) return res.json()
const { error } = await res.json()
switch (error.code) {
case 'RATE_LIMITED':
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '60')
await sleep(retryAfter * 1000)
return callPolicify(endpoint, options) // retry once
case 'UNAUTHORIZED':
throw new Error('Invalid API key — check your environment variable')
case 'PLAN_LIMIT_REACHED':
throw new Error('Policy quota exhausted — upgrade your plan')
default:
throw new Error(`API error ${res.status}: ${error.message}`)
}
}