Hirevoice Docs

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

sequenceDiagram autonumber actor Client as Client (ATS/Backend) participant API as Hirevoice API participant Pos as Position Augmentation participant Int as Interview Orchestrator participant WH as Your Webhook Endpoint Note over Client,API: Step 1: API key created in Dashboard Client->>API: Step 2: POST /positions API-->>Client: 201 Position created API->>WH: position.created API->>WH: position.augmentation.idle API->>Pos: Start augmentation (status=idle) Pos->>WH: position.augmentation.processing Client->>API: Step 3: POST /candidates API-->>Client: 201 Candidate + Interview(status=queued) API->>WH: candidate.created Note over API,Int: Interview remains queued while position != done alt Position augmentation done Pos->>WH: position.augmentation.done Pos->>Int: Position ready signal Int->>WH: interview.processing Int->>WH: interview.preprocessing Int->>WH: interview.ready Int->>WH: interview.postprocessing Int->>WH: interview.completed API-->>Client: Poll candidates/interviews => completed else Position augmentation error Pos->>WH: position.augmentation.error Int->>WH: interview.error API-->>Client: Poll candidates/interviews => error end

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_uuid must be unique per company.
  • duration is expressed in minutes and converted to seconds internally.
  • extract_data specifies the key information that the AI can capture from the call.
  • job_mode accepts Remote, Hibird, Presential, and normalized values remote, hybrid, onsite, unspecified.
  • Position augmentation runs asynchronously after creation.
  • Position starts as status=idle.
  • white_label is optional. When provided, overrides company-level branding for this position's interviews. Only company_name is 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 idle or processing, 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_uuid must be unique per company.
  • company_candidate_uuid and company_position_uuid are your external identifiers; use them in your system so you do not need to store Hirevoice resource IDs.
  • Pass exactly one selector: position_id or company_position_uuid.
  • Passing both, or neither, returns 400.
  • cv_url must be public and downloadable as a valid PDF.
  • interview_language overrides the position-level language for this specific candidate's interview. Accepts en, es, or ca. Falls back to the position's language when 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_id
  • company_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_uuid
  • position_id
  • company_position_uuid

Interview Lifecycle Mapping

External interview status values:

  • queued
  • processing
  • preprocessing
  • ready
  • postprocessing
  • completed
  • error

Each interview payload can include:

  • interview_url
  • result (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.created
  • position.augmentation.idle
  • position.augmentation.processing
  • position.augmentation.done
  • position.augmentation.error
  • candidate.created
  • interview.processing
  • interview.preprocessing
  • interview.ready
  • interview.postprocessing
  • interview.completed
  • interview.error

Position augmentation webhook payload data fields:

  • position_id
  • company_position_uuid
  • name
  • status

Delivery headers:

  • X-Hirevoice-Event-Id
  • X-Hirevoice-Event-Type
  • X-Hirevoice-Event-Time
  • X-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_id in signature input is header X-Hirevoice-Event-Id (UUID), not payload field id (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_url is 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.

On this page