API Integration V1
API key setup, external integration endpoints, lifecycle states, and webhooks
Use this guide to integrate an external ATS or backend with Hirevoice.
External integration endpoints
- Base path:
/api/integration/v1 - Header:
X-API-Key: <api_key> - API key authenticated responses include:
X-API-Key-Expires-At: <iso_timestamp | never>
Setup Flow
API Key Management
API keys are generated from the Dashboard in Integrations. Use these endpoints to view, update, and revoke keys programmatically.
https://app.hirevoice.com/en/sign-in
External Integration Endpoints
All endpoints in this section use:
- Base:
/api/integration/v1 - Auth:
X-API-Key
POST /api/integration/v1/positions
Creates a position and binds your external identifier.
{
"name": "Senior Backend Engineer",
"job_description": "Build scalable backend systems in Python.",
"company_position_uuid": "ext-pos-001",
"location": "Barcelona",
"job_mode": "Remote",
"language": "en",
"duration": 30,
"evaluation_criteria": ["System design", "Communication"],
"extract_data": [
{
"key": "years_of_experience",
"description": "Candidate years of professional experience"
},
{
"key": "availability",
"description": "Notice period or start availability"
},
{
"key": "salary_expectation",
"description": "Expected salary amount and currency"
},
{
"key": "candidate_location",
"description": "Current city/country or relocation preference"
}
],
"white_label": {
"company_name": "Acme Corp",
"brand_assets": {
"logo_url": "https://cdn.example.com/acme-logo.png",
"colors": {
"foreground": { "type": "hex", "value": "#1a1a2e" },
"background": { "type": "hex", "value": "#f0f0f5" }
}
}
}
}Notes:
company_position_uuidmust be unique per company.durationis expressed in minutes and converted to seconds internally.extract_dataspecifies the key information that the AI can capture from the call.job_modeacceptsRemote,Hibird,Presential, and normalized valuesremote,hybrid,onsite,unspecified.- Position augmentation runs asynchronously after creation.
- Position starts as
status=idle. white_labelis optional. When provided, overrides company-level branding for this position's interviews. Onlycompany_nameis required;brand_assets(logo URL and foreground/background colors) are optional. Colors must be valid hex values (e.g.,#1a1a2e). When omitted, interview branding falls back to company-level settings.
Example response:
{
"id": "9e36a0df-2bf4-4f95-92f8-e74d8a22d2aa",
"name": "Senior Backend Engineer",
"job_description": "Build scalable backend systems in Python.",
"company_position_uuid": "ext-pos-001"
}GET /api/integration/v1/positions/{position_id}
Returns position details including augmentation status and interview context fields.
{
"id": "9e36a0df-2bf4-4f95-92f8-e74d8a22d2aa",
"name": "Senior Backend Engineer",
"job_description": "Build scalable backend systems in Python.",
"company_position_uuid": "ext-pos-001",
"evaluation_criteria": [],
"extract_data": [
{
"key": "Salary expectation",
"description": "Candidate expected salary range"
}
],
"applied_extract_data": null,
"interview_prompt_persona_role": null,
"interview_prompt_first_message": null,
"white_label": {
"company_name": "Acme Corp",
"brand_assets": {
"colors": {
"foreground": { "type": "hex", "value": "#1a1a2e" },
"background": { "type": "hex", "value": "#f0f0f5" }
},
"logo_url": "https://cdn.example.com/acme-logo.png"
}
},
"interview_type": "white-collar",
"status_detail": {},
"status": "idle"
}Notes:
- While status is
idleorprocessing, generated fields are still empty/null. - Once status becomes
done, criteria/prompt/applied settings are populated.
POST /api/integration/v1/candidates
Creates a candidate and initial interview relation.
{
"company_candidate_uuid": "ext-cand-0099",
"company_position_uuid": "ext-pos-001",
"first_name": "Ada",
"last_name": "Lovelace",
"cv_url": "https://files.example.com/cv/ada-lovelace.pdf",
"interview_language": "es"
}Rules:
company_candidate_uuidmust be unique per company.company_candidate_uuidandcompany_position_uuidare your external identifiers; use them in your system so you do not need to store Hirevoice resource IDs.- Pass exactly one selector:
position_idorcompany_position_uuid. - Passing both, or neither, returns
400. cv_urlmust be public and downloadable as a valid PDF.interview_languageoverrides the position-level language for this specific candidate's interview. Acceptsen,es, orca. Falls back to the position'slanguagewhen null or omitted.- Candidate creation does not wait for position augmentation; when position is not done the interview is returned as
queued.
Example response:
{
"id": "f3efbe2f-0dc1-424d-a57c-0f75e74fdc34",
"company_candidate_uuid": "ext-cand-0099",
"first_name": "Ada",
"last_name": "Lovelace",
"created_at": "2026-02-22T16:10:00+00:00",
"interviews": [
{
"position_id": "9e36a0df-2bf4-4f95-92f8-e74d8a22d2aa",
"company_position_uuid": "ext-pos-001",
"status": "queued",
"interview_url": null,
"result": null,
"context": {
"criteria_source": "position.interview_evaluation_criteria",
"job_opening_role": "Senior Backend Engineer",
"job_description": "Build scalable backend systems in Python.",
"evaluation_criteria": [],
"applied_extract_data": {
"tools_or_tags": [],
"must_have_questions_added": [],
"max_questions": 5,
"language": "en",
"persona_applied": false,
"first_message_applied": false
},
"extract_data_fields": [
{
"key": "Salary expectation",
"description": "Candidate expected salary range"
}
]
},
"white_label": {
"company_name": "Acme Corp",
"brand_assets": {
"colors": {
"foreground": { "type": "hex", "value": "#1a1a2e" },
"background": { "type": "hex", "value": "#f0f0f5" }
},
"logo_url": "https://cdn.example.com/acme-logo.png"
}
},
"error_detail": null,
"status_detail": {
"phase": "awaiting_position_ready",
"position_status": "idle"
}
}
]
}GET /api/integration/v1/candidates/{candidate_id}
Returns candidate identity plus interview lifecycle/result payloads.
Optional query filters:
position_idcompany_position_uuid
If both are sent, they must resolve to the same position.
GET /api/integration/v1/candidates
Lists candidates with optional filters:
company_candidate_uuidposition_idcompany_position_uuid
Interview Lifecycle Mapping
External interview status values:
queuedprocessingpreprocessingreadypostprocessingcompletederror
Each interview payload can include:
interview_urlresult(when completed)context(criteria + extract-data configuration)error_detail(when error)
Webhooks
Webhook events are queued per active webhook target for active API keys in the company.
Event types:
position.createdposition.augmentation.idleposition.augmentation.processingposition.augmentation.doneposition.augmentation.errorcandidate.createdinterview.processinginterview.preprocessinginterview.readyinterview.postprocessinginterview.completedinterview.error
Position augmentation webhook payload data fields:
position_idcompany_position_uuidnamestatus
Delivery headers:
X-Hirevoice-Event-IdX-Hirevoice-Event-TypeX-Hirevoice-Event-TimeX-Hirevoice-Signature
Signature details:
- Format:
sha256=<hmac_hex> - Signed input:
<event_id>.<occurred_at>.<raw_json_payload> - Algorithm: HMAC-SHA256
- Secret: webhook target
signing_secret event_idin signature input is headerX-Hirevoice-Event-Id(UUID), not payload fieldid(evt_...).
Retry schedule (seconds): 10, 30, 120, 600, 1800, 7200
Example payload envelope:
{
"id": "evt_0195a5e7-5d29-7f2a-93a8-5da72c9fa123",
"type": "candidate.created",
"occurred_at": "2026-02-22T14:00:00+00:00",
"api_version": "v1",
"company_id": "22222222-2222-2222-2222-222222222222",
"data": {}
}Errors and Troubleshooting
Domain-level error mapping:
409 Conflict: duplicate external identifiers.404 Not Found: resource not found in company scope.400 Bad Request: validation failures.401 Unauthorized: invalid/missing/expired/revoked key or invalid JWT.
Runtime error shape:
{
"detail": "Human-readable message"
}Common checks when requests fail:
- Confirm auth header type matches endpoint group.
- Confirm API key is active and not expired.
- Confirm position selector values are valid and in company scope.
- Confirm
cv_urlis publicly reachable and points to PDF content.
Upcoming
A WhatsApp-based interview flow for blue-collar positions, including a built-in document gathering step. See the WhatsApp & Blue-collar preview docs for the agent behavior and the document gathering schema.