Errors & retries
Error envelope
Every error response has the same shape:
{
"error": {
"type": "validation",
"message": "country must be ISO-3166-1 alpha-2",
"code": "VALIDATION_ERROR",
"details": [
{ "field": "country", "message": "must match ^[A-Z]{2}$" }
]
}
}
Common error codes
| HTTP | code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Malformed body or invalid field |
| 400 | INVALID_TRANSITION | Action not allowed from current KYC status |
| 401 | MISSING_API_KEY | Authorization header absent |
| 401 | INVALID_API_KEY | Key malformed, unknown, or revoked |
| 403 | FORBIDDEN | Authenticated but not allowed |
| 404 | NOT_FOUND | Resource doesn't exist or not in your org |
| 409 | CONFLICT | Duplicate (e.g. same externalRef on applicant) |
| 422 | UNPROCESSABLE | Business rule violation (e.g. archived applicant) |
| 429 | RATE_LIMITED | Too many requests |
| 500 | INTERNAL_ERROR | Our fault — retry with backoff |
| 503 | SERVICE_UNAVAILABLE | Temporary — retry |
Idempotency
All POST /v1/* endpoints accept an Idempotency-Key header.
POST /v1/kyc-requests HTTP/1.1
Idempotency-Key: user-1234-verification-attempt-1
Authorization: Bearer idv_test_…
Content-Type: application/json
- Keys are scoped per
(organization, environment, key). - TTL: 24 hours.
- First request runs normally and caches the response.
- Subsequent requests with the same key return the cached response with
Idempotent-Replayed: trueheader. - Only successful responses (2xx) are cached — 4xx/5xx can be safely retried.
Use any client-generated unique string (UUIDv4, ULID, or a business key like order-1234).
Retrying safely
- Network errors / 5xx / 429: retry with exponential backoff (500ms → 1s → 2s → 4s → 8s). Set
Idempotency-Keyon POSTs so retries don't create duplicates. - 4xx (except 429): fix your request — do not retry.
- Webhook deliveries: Idova retries automatically. Your endpoint should be idempotent on
eventId.
Tracing
Every response includes X-Request-Id. If you report an issue, include that ID so we can trace it across services.
