Errors and retries
Choose the right recovery action without duplicating submissions.
Successful responses wrap a resource in data. Error responses contain error.code, error.message, and error.requestId. Some include a stable reason and validation fields. Save the request ID for support; never attach keys, invitation tokens, signed URLs, or candidate documents to ordinary logs.
{
"error": {
"code": "CONFLICT",
"message": "Request conflicts with the current resource state.",
"reason": "QUOTE_STALE",
"requestId": "25cbb923-8b3c-4d05-b74f-623efc6d5f8d"
}
}The message is for people and can change. Branch on status, code, and reason where provided. Not every endpoint returns every domain error; consult its recovery section.
HTTP recovery
| Status | What to check | Retry approach |
|---|---|---|
| 400 | Input shape, field validation, query parameters, cursor, supported result schema | Correct the input; unchanged retries cannot fix it |
| 401 | Key expiry/revocation and creating Admin's current access | Restore valid authentication |
| 403 | Required scope, workspace access, and feature availability | Resolve access before retrying |
| 404 | Workspace, resource ID, deletion, or preparation expiry | Reconcile the resource; do not retry deleted resources forever |
| 405 | Supported method in Allow | Correct the HTTP method |
| 409 | Quote, idempotency input, or resource state | Follow the domain reason below |
| 410 | Event cursor older than retained history | Reconcile current resources and establish a new cursor |
| 422 | Upload contents, workspace allowance, or active-work limits | Resolve the specific reason |
| 429 | Request rate | Wait at least Retry-After, then retry |
| 500 / 503 | Temporary server failure | Back off; preserve the original body and idempotency key |
Domain recovery
| Reason | Action |
|---|---|
IDEMPOTENCY_CONFLICT | Recover the original request; choose a new key only for genuinely new work |
EXTERNAL_REFERENCE_CONFLICT | Find the existing application report or replay its original preparation |
JD_REVISION_CHANGED | Re-read and review the job before preparing against its new revision |
QUOTE_STALE | Review a fresh quote, then submit its fingerprint with a new request key |
RESOURCE_ALREADY_ADMITTED | Read current state; do not repeat upload or admission with new keys |
INVALID_UPLOAD | Verify PUT completion, file bytes, size, and content type |
UPLOAD_EXPIRED | Create a fresh preparation; refreshing a URL cannot revive an expired preparation |
PENDING_UPLOAD_LIMIT | Cancel unused preparations or wait for expiry |
ACTIVE_ANALYSIS_LIMIT | Wait for capacity; at most five analyses can be active in a workspace |
BATCH_ACTIVE_LIMIT | Wait for the active batch of that kind to complete |
INSUFFICIENT_CREDITS / QUOTA_EXCEEDED | Ask the workspace Admin to resolve the available allowance |
RESULT_VERSION_UNSUPPORTED | Request a supported result schema version |
EVENT_CURSOR_EXPIRED | Reconcile current reports/interviews, then begin a fresh event-feed position |
Backoff and limits
Use bounded exponential backoff with jitter for transient errors; honor Retry-After when present. Keep a retry budget and surface a persistent failure to an operator. Do not retry malformed requests or access failures indefinitely.
| Limit | Per minute |
|---|---|
| Reads per key / workspace | 60 / 120 |
| Writes per key / workspace | 10 / 20 |
| Ingress requests per IP | 300 |
| Invalid-authentication attempts per IP | 30 |
These are fixed-minute windows. Poll conservatively and prefer webhooks for completion updates. Batch item admission has separate work budgets; a batch request does not bypass workspace limits.
Handling partial batches
An accepted batch can fail some items. Store each successful resource ID, inspect failed errorCode values, and submit only corrected failed items in a new batch with fresh quotes where required. Read bulk workflows for the different completion rules.