System status
Checking the backend…
Developer docs
One call creates an assessment from a role. HireVoice writes the job description and the question bank, gives each candidate their own random questions, grades them, and sends you the result by webhook.
hv_sk_…): everything on this page. Server-side only. Send it as Authorization: Bearer hv_sk_….hv_pk_…): safe in a browser. It can only open the candidate screen for an invitation you created (the embed widget). It cannot read results.# Your secret key (hv_sk_…) stays on your server. Never put it in a browser or an app.API="https://api.hirevoice.example/api/v1"AUTH="Authorization: Bearer $HIREVOICE_SECRET_KEY" # 1. Create an interview from a role. Leave out jobDescription and the AI writes one.ID=$(curl -s -X POST "$API/assessments" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"type": "voice_interview", "title": "Backend engineer screen", "role": "Backend engineer", "seniority": "senior", "focusSkills": ["Python", "PostgreSQL"], "questionsPerAttempt": 8}' | jq -r .id) # 2. Generate the job description and a 25-question bank (charged in credits)curl -s -X POST "$API/assessments/$ID/generate" -H "$AUTH" # 3. Review or edit, then activatecurl -s -X PATCH "$API/assessments/$ID" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"status": "active"}' # 4. Invite a candidate: each gets a random 8 of the 25 questions. The link is returned once.curl -s -X POST "$API/assessments/$ID/invitations" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"candidateName": "Asha Rao", "candidateEmail": "asha@example.com"}'Tests work the same way with "type": "mcq_test": a 50-question bank by default, 15 random questions per candidate.
Add an endpoint in the portal. When a candidate is graded we POST attempt.completed with the score, the report (summary, strengths, gaps, recommendation) and a link to the full result. Failed deliveries are retried for about 15 hours (1 min, 5 min, 30 min, 2 h, 12 h).
Every delivery is signed: HireVoice-Signature: t=<unix>,v1=<hex> where v1 is HMAC-SHA256 of "<t>.<raw body>" with your endpoint's secret. Verify it on the raw bytes before parsing the JSON.
import hashlib, hmac, time def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool: """header = the HireVoice-Signature value: "t=<unix seconds>,v1=<hex>".""" parts = dict(item.split("=", 1) for item in header.split(",")) t, v1 = int(parts["t"]), parts["v1"] if abs(time.time() - t) > tolerance: # reject old deliveries: no replays return False expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, v1) # constant timeGenerated from the live API schema. * = required. Full schema: /openapi.json and the interactive /docs on the API host.
The live reference is unavailable right now. The quick start above is complete on its own.
Errors are RFC 9457 Problem Details with a stable code to switch on; title is a readable message and fieldErrors names fields.
| Status | Code | Meaning |
|---|---|---|
| 401 | UNAUTHENTICATED | Missing, wrong or revoked key. |
| 402 | INSUFFICIENT_CREDITS | Your balance cannot pay for this. Contact us for more credits. |
| 403 | FEATURE_DISABLED | Tests or interviews are not enabled for your organization. |
| 404 | ASSESSMENT_NOT_FOUND | Not found, or it belongs to another organization (same answer on purpose). |
| 409 | ASSESSMENT_NOT_READY | Activate it, or add enough questions for one candidate's set. |
| 409 | ASSESSMENT_HAS_ATTEMPTS | Questions freeze once a candidate is invited. |
| 422 | VALIDATION_FAILED | See fieldErrors for the exact field. |
| 422 | IMPORT_INVALID | A spreadsheet's rows: see fieldErrors {"row 4": "…"}. |
| 429 | RATE_LIMITED | Too many requests. Wait for the Retry-After seconds. |
nextCursor back as cursor; limit is 1 to 100 (default 20).ETag. Send it back as If-None-Match to get an empty 304 when nothing changed.