Skip to main content

CV DeepSearch overview

CV DeepSearch is the inverse of CV DeepMatch. CV DeepMatch scores one CV against one job; CV DeepSearch lets you ingest a corpus of candidates once and then run repeated searches that return the best-first candidates for a given position.

Base URL: https://platform.zenhire.ai/api/v1/cvds

Two flows

CV DeepSearch is two distinct flows — fill the corpus, then query it. Each has its own guide:

Flow 1 — Ingestion (fill the corpus) → see the Ingestion guide
Ingest a corpus POST /api/v1/cvds/candidates
(batch parsed CVs) → per-candidate embedding status
Check status GET /api/v1/cvds/candidates[/{external_id}]

Flow 2 — Search (query the corpus) → see the Search guide
Run a search POST /api/v1/cvds/search
for one position → run id (status: pending)
Consume the results GET /api/v1/cvds/runs/{id} (poll)
(or receive the completion webhook)

You ingest a corpus once and keep it warm; searching it for different positions is cheap and repeatable. Re-ingest only when a candidate's CV changes.

Core concepts

ConceptWhat it is
CorpusA named pool of candidates (corpus_id, chosen by you). A search only ever reads candidates in the named corpus. Corpora are tenant-scoped — yours are never visible to other clients.
CandidateOne parsed CV in a corpus, keyed by your own external_id. Each candidate is embedded for semantic retrieval.
Embedding statuspendingembedded (searchable) → or failed. A candidate is only returned by a search once embedded.
Search runOne search of a corpus for one position. Triggering a search returns a run id; the search runs asynchronously.
Position configThe position_metadata you search against — the same shape CV DeepMatch consumes as its requirements config.

Authentication

Authenticate every call with your platform API key in the X-API-Key header — the same model as Speech, Interview, and CV DeepMatch. Your client needs the cvdeepsearch permission enabled; calls without it return MISSING_PERMISSION.

X-API-Key: zh_api_…

An API key is pinned to its own client (no cross-tenant access). The same endpoints also back the ZenHire console UIs, which use a logged-in browser session instead — both modes share one contract.

See Authentication for key management.

Corpus isolation (fail-closed)

corpus_id is mandatory on ingest and search. A request with no resolvable corpus_id is rejected with MISSING_CORPUS_ID — it is never merged into a default corpus. This is deliberate: it prevents one client's candidates from silently leaking into another search context.

Error responses

All CV DeepSearch endpoints use the platform's structured error envelope:

{
"error": {
"code": "MISSING_CORPUS_ID",
"message": "corpus_id is mandatory and fail-closed.",
"timestamp": "2026-06-09T10:00:00.000Z",
"details": {}
}
}

See Errors for the shared envelope, and the Ingestion and Search guides for the per-code catalog. The full endpoint reference is the CV DeepSearch section in the API reference sidebar.

Results side is in progress

The per-run results — the best-first candidate list on GET /api/v1/cvds/runs/{id}, the GET /api/v1/cvds/runs/{id}/results pagination endpoint, and the final webhook completion payload — are finalized in a follow-up release. Until then the run poll returns the run's status with results: null and results_pending: true. The ingest, search-trigger, and run-status sides documented here are final.