Appearance
API reference
Available onEnterprise
Who can do thisWorkspace owners and admins create keys
These are the endpoints of the Infyva public API. Paths are relative to the base URL, https://api.infyva.ai/api/v1/public. It is also shown in Settings > API keys and webhooks, under API reference on the Developer platform page.
Send your key as Authorization: Bearer infy_live_... or X-API-Key: infy_live_... on every request. Keys, scopes, limits and pagination are explained in Public API.
Generated from the OpenAPI schema
Parameters and request bodies below are generated from Infyva's OpenAPI schema. The API does not declare response schemas, so example responses, scopes and errors are written by hand from the API code and checked against it.
List jobs
GET /api/v1/public/jobs
Scope: read:interviews
Your company's jobs, newest first.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
status | query | string | Filter by job status: draft, active, closed or archived. |
limit | query | integer | 1 to 200; default 50 |
skip | query | integer | at least 0; default 0 |
Example response
{
"data": [
{
"id": "6adc2869a0b4af3b1cfb32a3",
"name": "Senior Backend Engineer",
"job_title": "Senior Backend Engineer",
"status": "active",
"team_department": "Engineering",
"total_candidates": 12,
"created_at": "2026-10-01T09:30:00Z"
}
],
"total": 1,
"limit": 50,
"skip": 0
}List a job's candidates
GET /api/v1/public/jobs/{job_id}/candidates
Scope: read:interviews
The candidates on one job, newest first. The id of each item is the job-candidate record: pass it as candidate_id to the scheduling endpoint. It is also the candidate_id in the get-an-interview response and in the candidate.stage_changed webhook. stage can be a current stage (applied, screened, interviewed, offer, hired, rejected) or an older stage name such as resume_review. status is one of uploaded, screened, scheduled, interviewed, rejected or hired.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
job_idrequired | path | string | |
limit | query | integer | 1 to 200; default 50 |
skip | query | integer | at least 0; default 0 |
Example response
{
"data": [
{
"id": "6adc286aa0b4af3b1cfb32b9",
"job_id": "6adc2869a0b4af3b1cfb32a3",
"name": "Maya Chen",
"email": "maya.chen@example.com",
"stage": "screened",
"status": "screened",
"screening_score": 82,
"interview_ids": ["6adc286aa0b4af3b1cfb32ba"],
"added_at": "2026-10-02T14:05:00Z"
}
],
"total": 1,
"limit": 50,
"skip": 0
}Errors
404Job not found (the job is not in your company).
Add a candidate
POST /api/v1/public/jobs/{job_id}/candidates
Scope: write:candidates
Adds one candidate to a job. A resume_url is stored as a link; Infyva does not download it. New candidates start with stage resume_review and status uploaded. Returns 201.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
job_idrequired | path | string |
Request body (JSON)
| Field | Type | Details |
|---|---|---|
namerequired | string | 1 to 200 characters |
emailrequired | string (email) | |
resume_url | string | 0 to 2048 characters |
Example response
{
"id": "6adc286aa0b4af3b1cfb32c4",
"job_id": "6adc2869a0b4af3b1cfb32a3",
"name": "Daniel Whitaker",
"email": "daniel.whitaker@example.com",
"stage": "resume_review",
"status": "uploaded",
"resume_url": "https://files.example.com/cv/daniel-whitaker.pdf",
"added_at": "2026-10-23T10:00:00Z"
}Errors
409Candidate is already in this job. Here detail is an object: {"message": "Candidate is already in this job", "candidate_id": "<the existing job-candidate record id>"}.409This email belongs to a non-candidate account.409This candidate can't be added right now.422resume_url must be an http(s) URL, or another field failed validation (for example an invalid email).
Schedule an interview
POST /api/v1/public/jobs/{job_id}/candidates/{candidate_id}/interviews
Scope: write:candidates
Schedules an interview for a candidate on the job and emails them their link. candidate_id is the job-candidate record id from the list or add endpoints. Leave out scheduled_date to send the link now. Leave out interview_type to use the job's default. An AI interview holds 1 credit. A Live AI interview uses 0.5 credit per minute of conversation (minutes round up, 1-minute minimum). Your company's compliance policies apply and an API key can't override them. status is scheduled, or cancelled if the email could not be delivered (the credit is then returned). Returns 201.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
job_idrequired | path | string | |
candidate_idrequired | path | string |
Request body (JSON)
| Field | Type | Details |
|---|---|---|
scheduled_date | string | ISO datetime; omit to send the link now |
timezone | string | default UTC |
question_count | integer | 1 to 50 |
duration_minutes | integer | Total interview length, in minutes 5 to 180 |
link_expiration_hours | integer | 1 to 720; default 72 |
interview_type | string | one of recruiter, elite_live |
elite_mode | string | one of structured, conversational |
Example response
{
"interview_id": "6adc2871a0b4af3b1cfb3390",
"candidate_id": "6adc286aa0b4af3b1cfb32c4",
"job_id": "6adc2869a0b4af3b1cfb32a3",
"status": "scheduled",
"scheduled_date": "2026-10-23T10:00:00+00:00",
"question_count": 5,
"interview_url": "https://www.infyva.ai/candidate/interviews/recruiter-session/6adc2871a0b4af3b1cfb3390?token=..."
}Errors
400Could not schedule this interview.402Not enough credits to schedule this interview.403Live AI is not switched on for your workspace, there are no credits left for it, or your trial ended (Your trial ended. Choose a plan to send new invites and run Live AI interviews. Your reports stay readable.).404Candidate not found in this job.409The candidate already has an open interview, or your company's compliance policy blocks invites for this job until its checklist is complete (detail.code is COMPLIANCE_POLICY_BLOCKED).422The job's language is not available for Live AI, or a field failed validation.500Failed to schedule interview.
Get an interview
GET /api/v1/public/interviews/{interview_id}
Scope: read:interviews
Status of one interview and whether its report is ready. candidate_id is the job-candidate record id. report_status is pending, generating, completed or failed, or null before the candidate starts. scheduled_date, started_at and completed_at are passed through as stored and may have no time zone suffix; they are UTC.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
interview_idrequired | path | string |
Example response
{
"id": "6adc2871a0b4af3b1cfb3390",
"job_id": "6adc2869a0b4af3b1cfb32a3",
"candidate_id": "6adc286aa0b4af3b1cfb32c4",
"title": "Senior Backend Engineer",
"status": "completed",
"scheduled_date": "2026-10-23T10:00:00",
"created_at": "2026-10-23T10:00:00Z",
"started_at": "2026-10-23T15:12:00",
"completed_at": "2026-10-23T15:41:00",
"report_status": "completed",
"report_available": true
}Errors
404Interview not found.
Get a report summary
GET /api/v1/public/interviews/{interview_id}/report
Scope: read:reports
The summary of a finished report: overall score, recommendation, up to five strengths and five areas to improve, and the integrity risk level. The full report stays in Infyva. recommendation is the report's verdict as stored, for AI interview reports usually Hire, Needs Follow-up or Reject; it can be null, for example on Live AI reports. integrity_risk_level is LOW_RISK, MEDIUM_RISK, HIGH_RISK or CRITICAL, or null when no integrity data was collected.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
interview_idrequired | path | string |
Example response
{
"report_id": "6adc286ba0b4af3b1cfb32de",
"interview_id": "6adc2871a0b4af3b1cfb3390",
"overall_score": 76,
"recommendation": "Hire",
"performance_summary": {},
"strengths": ["Explains trade-offs clearly"],
"areas_for_improvement": ["Testing strategy was thin"],
"integrity_risk_level": "LOW_RISK",
"completed_at": "2026-10-23T15:41:00",
"created_at": "2026-10-23T15:43:00"
}Errors
404Report is not ready yet.
Pull the audit log
GET /api/v1/public/audit-log
Scope: read:audit_log · Also needs the audit log, which is on Enterprise.
Your workspace audit log as NDJSON: one event per line, oldest first, in the infyva.audit.v1 shape. Pass the X-Next-Cursor header from the last response as after to continue. The X-Event-Count header says how many events came back. Each pull is itself written to the audit log.
Parameters
| Name | In | Type | Details |
|---|---|---|---|
after | query | string | Cursor from the previous response's X-Next-Cursor header. |
since | query | string (date-time) | Only events at or after this time (ISO 8601). |
limit | query | integer | Events per response, 1 to 5000. 1 to 5000; default 1000 |
Example response
{"action": "sso.login.succeeded", "actor_email": "maya.chen@example.com", "actor_is_infyva_support": false, "actor_system": null, "actor_user_id": "6adc2867a0b4af3b1cfb3290", "details": {}, "id": "6adc2899a0b4af3b1cfb3401", "ip_address": "203.0.113.10", "organization_id": "6adc2866a0b4af3b1cfb3288", "resource_id": null, "resource_type": "sso", "schema": "infyva.audit.v1", "target_email": null, "target_user_id": null, "timestamp": "2026-10-23T09:00:00Z", "user_agent": "Mozilla/5.0"}Errors
400The cursor is not valid.403The audit log is included on the Enterprise plan.