Reference
Error Codes
All error responses follow a consistent JSON structure. The error.code field contains a machine-readable string identifier that you should use in your error handling logic. Never rely on the message field, which may change.
Error response format
JSON
{
"success": false,
"error": {
"code": "FACE_NOT_FOUND",
"message": "No face found with the given ID in this collection."
},
"requestId": "0c772a2c-af02-413e-9ef0-c7da186d724d",
"timestamp": "2026-09-20T11:22:33Z"
}HTTP status codes
| Status | Meaning |
|---|---|
| 200 OK | Request succeeded. |
| 201 Created | Resource created successfully. |
| 400 Bad Request | Missing or invalid parameters. |
| 401 Unauthorized | Missing or invalid authentication credentials. |
| 402 Payment Required | A plan limit was reached — collections, faces, or API keys. |
| 403 Forbidden | Valid credentials but insufficient permissions or IP blocked. |
| 404 Not Found | Requested resource does not exist. |
| 409 Conflict | Resource already exists (e.g. duplicate external_id). |
| 422 Unprocessable Entity | Validation passed but business logic rejected the request. |
| 429 Too Many Requests | Your organization's per-minute limit was reached. Wait for Retry-After. |
| 500 Internal Server Error | Unexpected server error. Contact support with the requestId. |
| 503 Service Unavailable | The recognition engine is busy for a moment. Wait for Retry-After and send the request again. |
API key errors
| Code | HTTP | Description |
|---|---|---|
| UNAUTHORIZED | 401 | No X-API-Key header was sent. |
| INVALID_API_KEY | 401 | The key does not exist, or it was revoked. |
| API_KEY_EXPIRED | 401 | The key passed the expiry date set when it was issued. |
| API_KEY_INACTIVE | 401 | The key was disabled in the console without being deleted. |
| INSUFFICIENT_SCOPE | 403 | The key lacks face:read or face:write for this call. |
| COLLECTION_NOT_ALLOWED | 403 | The key is restricted to other collections. |
| IP_NOT_ALLOWED | 403 | The calling address is not in the key's whitelist. |
Face & recognition errors
| Code | HTTP | Description |
|---|---|---|
| FACE_NOT_FOUND | 404 | No face with the given face_id or external_id in this collection. |
| NO_FACE_DETECTED | 422 | No face was detected in the submitted image. |
| MULTIPLE_FACES | 422 | More than one face detected; submit a single-face image. |
| FACE_QUALITY_TOO_LOW | 422 | Quality score below threshold (blur, occlusion, extreme pose). |
| SPOOF_DETECTED | 422 | The collection requires liveness at enrolment and the image did not pass. Capture the face live. |
| EXTERNAL_ID_EXISTS | 409 | An active face with this external_id already exists in the collection. |
Collection & API key errors
| Code | HTTP | Description |
|---|---|---|
| COLLECTION_NOT_FOUND | 404 | Collection does not exist or belongs to a different org. |
| COLLECTION_LIMIT_EXCEEDED | 402 | Plan collection limit reached. Upgrade to create more. |
| FACE_LIMIT_EXCEEDED | 402 | Collection face limit reached for your current plan. |
| API_KEY_LIMIT_EXCEEDED | 402 | API key limit per member reached for your current plan. |
| RATE_LIMIT_EXCEEDED | 429 | Your organization's per-minute limit (or the key's own lower limit) was reached. See the Retry-After header. |
| SERVICE_BUSY | 503 | The recognition engine is saturated for a moment; not your limit. See the Retry-After header. |
| INVALID_RATE_LIMIT | 400 | A key's customRateLimitRpm must be from 1 up to your plan's rate. |
Validation errors
A malformed request fails on the first problem found and names it in error.code. There is no aggregated details array — fix one, resend, see the next.
JSON
{
"success": false,
"error": {
"code": "IMAGE_REQUIRED",
"message": "image file is required"
},
"requestId": "49d93b21-76e1-47ef-9e01-be5f02df47ec",
"timestamp": "2026-09-20T11:12:57Z"
}Handling rate limits
A 429 (your limit) and a 503 SERVICE_BUSY (the engine is busy) both carry a Retry-After header with the number of seconds to wait before retrying:
async function identifyWithRetry(formData, apiKey, retries = 3) {
for (let i = 0; i < retries; i++) {
const res = await fetch(
'https://api.livexface.com/api/v1/collections/COLLECTION_ID/identify',
{ method: 'POST', headers: { 'X-API-Key': apiKey }, body: formData }
)
if (res.status === 429 || res.status === 503) {
const wait = parseInt(res.headers.get('Retry-After') ?? '5', 10)
await new Promise(r => setTimeout(r, wait * 1000))
continue
}
const data = await res.json()
if (!data.success) throw new Error(data.error.code)
return data
}
throw new Error('Max retries exceeded')
}