Identifiers
The ZenHire API uses three distinct identifiers. They look similar but mean different things, and conflating them is the single most common integration mistake. This page is the canonical definition; the same model holds across Speech, Interview, CV DeepMatch, and CV DeepSearch.
| Identifier | Who assigns it | Where it appears | What it's for |
|---|---|---|---|
id | ZenHire | Every create/poll/list response | The public, canonical identifier of a run/session. Use it to poll, fetch, and list. |
externalId (your correlation tag) | You | Request you send; echoed back on responses | Your own reference (your ATS id, candidate id, batch id). ZenHire stores and echoes it but never interprets it. |
requestId | ZenHire | The error envelope only | A per-HTTP-response trace handle. Quote it in support tickets. |
id — the run identifier
Every unit of work you create returns a single id:
| Module | Returned by | Used by |
|---|---|---|
| Speech | POST /api/v1/speech/analyze → id | GET /api/v1/speech/analyze/{id} |
| Interview | POST /api/v1/interview/personas/{personaId}/sessions → id | GET /api/v1/interview/sessions/{id} |
| CV DeepMatch | POST /api/v1/cvdeepmatch/submit → id | GET /api/v1/cvdeepmatch/{id} |
| CV DeepSearch | POST /api/v1/cvds/search → id | GET /api/v1/cvds/runs/{id} |
This is the same id everywhere it appears — in the create response,
in poll/get responses, and as a row's id in the corresponding list
endpoint. There is exactly one canonical identifier per run; ZenHire does
not expose a second internal id.
Earlier versions of individual modules called this field requestId,
request_id, or session_id. The public surface is now unified: the
field is id on every module's responses. Treat id as opaque —
don't parse or construct it.
externalId — your correlation tag
externalId is a free-form string you supply when you create a run.
ZenHire stores it, echoes it back on every response for that run, and lets
you filter list endpoints by it — but it is never interpreted by
ZenHire and is not required to be unique.
Use it to tie a ZenHire run back to a record in your own system without
having to persist ZenHire's id separately:
// You send:
{ "externalId": "candidate-abc-123", /* … */ }
// Every response for that run echoes it back:
{ "id": "req_1705412345678_abc123", "externalId": "candidate-abc-123", /* … */ }
Because it isn't unique, it's safe to reuse across retries. To look up
every run you tagged with a given value, filter the module's list
endpoint by externalId.
externalId is the correlation id in the classic sense: your tag
for your bookkeeping. It is not the same as id (which ZenHire
owns) and not the same as requestId (below).
requestId — the error trace handle
requestId appears only inside the error envelope.
It identifies one specific HTTP response — not the run — so that ZenHire
support can trace exactly what happened to that one call:
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred.",
"timestamp": "2026-05-29T10:00:00.000Z",
"requestId": "req_1705412345678_abc123"
}
}
When you contact support about a failed call, quote the requestId from
the error envelope. It is distinct from both id (the run) and
externalId (your tag) even when the strings happen to look alike.
At a glance
You assign ┌─ externalId ──► your own correlation tag (echoed, not interpreted)
│
ZenHire assigns ├─ id ──────────► the run/session — poll, fetch, list with this
│
ZenHire assigns └─ requestId ───► one HTTP error response — quote it to support
(only ever inside error.requestId)