Skip to main content

Error envelope

Every 4xx and 5xx response from every module (Speech, Interview, CV DeepMatch, CV DeepSearch) and from the cross-module credits/health endpoints uses the same envelope. Learn it once.

The shape

{
"error": {
"code": "INVALID_INPUT",
"message": "A human-readable explanation of what went wrong.",
"timestamp": "2026-05-29T10:00:00.000Z",
"requestId": "req_1705412345678_abc123",
"details": { /* optional, code-specific extras */ }
}
}
FieldAlways present?Meaning
error.codeYesA stable, machine-readable code. Branch on this, not on message.
error.messageYesHuman-readable description. May change wording over time — don't parse it.
error.timestampYesISO 8601 time the error was generated.
error.requestIdWhen availablePer-response trace handle for support. Present once a route handler has run; middleware-level rejections (e.g. a bad API key) happen before one is generated and omit it.
error.detailsWhen applicableCode-specific structured extras (e.g. field-level validation errors).
requestIdidexternalId

requestId identifies this one HTTP response, for tracing. It is not the run's id and not your externalId correlation tag — see Identifiers.

Rate limiting and warm-up

Responses that ask you to retry — 429 rate limits and 503 service-warming — additionally carry error.retryAfterSeconds and the standard HTTP Retry-After header. Respect the header.

Branching on errors

resp = call_zenhire(...)
if not resp.ok:
err = resp.json()["error"]
if err["code"] == "RATE_LIMIT_EXCEEDED":
backoff_and_retry()
elif err["code"] == "INSUFFICIENT_CREDITS":
alert_billing()
else:
log(err["code"], err.get("requestId"))

Module error catalogs

The envelope is universal; the set of codes is module-specific. See each module's error reference, plus the shared catalog:

  • Speech error codes — submit/poll/run codes.
  • Interview, CV DeepMatch, and CV DeepSearch codes are listed on each endpoint page in the API reference (every status code shows its full response schema).