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.
- Ingestion guide — fill the corpus.
- Search guide — query the corpus.
Core concepts
| Concept | What it is |
|---|---|
| Corpus | A 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. |
| Candidate | One parsed CV in a corpus, keyed by your own external_id. Each candidate is embedded for semantic retrieval. |
| Embedding status | pending → embedded (searchable) → or failed. A candidate is only returned by a search once embedded. |
| Search run | One search of a corpus for one position. Triggering a search returns a run id; the search runs asynchronously. |
| Position config | The 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.
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.