Skip to main content

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.

IdentifierWho assigns itWhere it appearsWhat it's for
idZenHireEvery create/poll/list responseThe public, canonical identifier of a run/session. Use it to poll, fetch, and list.
externalId (your correlation tag)YouRequest you send; echoed back on responsesYour own reference (your ATS id, candidate id, batch id). ZenHire stores and echoes it but never interprets it.
requestIdZenHireThe error envelope onlyA per-HTTP-response trace handle. Quote it in support tickets.

id — the run identifier

Every unit of work you create returns a single id:

ModuleReturned byUsed by
SpeechPOST /api/v1/speech/analyzeidGET /api/v1/speech/analyze/{id}
InterviewPOST /api/v1/interview/personas/{personaId}/sessionsidGET /api/v1/interview/sessions/{id}
CV DeepMatchPOST /api/v1/cvdeepmatch/submitidGET /api/v1/cvdeepmatch/{id}
CV DeepSearchPOST /api/v1/cvds/searchidGET /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.

One name, every module

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)