Invitations
Invite candidates, and resend, extend or cancel their links.
An invitation sends one candidate one interview. Reading needs candidates:read; everything that changes an invitation needs invitations:send.
The invitation object
| Field | Type | |
|---|---|---|
id | string | inv_… |
object | "invitation" | |
status | string | pending, started, completed, abandoned, expired or canceled. See Concepts. |
interviewer_id | string | |
candidate_id | string | |
session_id | string | |
url | string or null | The candidate's link. null once the invitation is no longer pending. |
expires_at | timestamp or null | When the link stops working |
external_ref | string or null | Your reference, echoed back |
tags | string[] | |
metadata | object | |
attempt_number | integer | Goes up when a candidate is given another attempt |
resend_count | integer | |
first_sent_at, last_sent_at | timestamp or null | When the first and latest links were issued |
livemode | boolean | |
created_at | timestamp |
List invitations
GET /invitations. Filters: interviewer_id, candidate_id, status, external_ref, created_gte, created_lt.
Create an invitation
POST /invitations
| Field | ||
|---|---|---|
interviewer_id | required | int_… |
candidate | required | { email, name, phone?, external_id? }. Creates the candidate or updates the existing one with that email. |
external_ref | optional | Up to 200 characters. Filter sessions and invitations by it later. |
tags | optional | Up to 20 strings |
metadata | optional | Object |
send_email | optional | Default true. Set false to deliver the url yourself. |
expires_at | optional | ISO 8601 time the link stops working. Must be in the future and at most 90 days out. Default 14 days. |
Returns the invitation with status 201. Send an idempotency key so a retry cannot invite twice.
In live mode, a request fails with 403 credits_exhausted when the organisation has no credits left.
Bulk invite
POST /invitations/bulk invites up to 500 candidates to one interviewer and returns 202 straight away. Links are created and sent in the background; each one fires an invitation.created event.
{
"interviewer_id": "int_…",
"candidates": [
{ "email": "ada@example.com", "name": "Ada Lovelace", "external_ref": "app-1" },
{ "email": "alan@example.com", "name": "Alan Turing", "external_ref": "app-2" }
],
"send_email": true,
"expires_at": "2026-10-20T00:00:00Z"
}{ "object": "bulk_invitation", "queued": 2, "skipped": [] }skipped lists rows rejected up front, such as emails that belong to the other mode. For spreadsheets, use an import instead.
Retrieve an invitation
GET /invitations/{id}
Resend an invitation
POST /invitations/{id}/resend issues a fresh link and, unless send_email is false, emails it. The old link stops working.
Extend an invitation
POST /invitations/{id}/extend with { "days": 7 } (1 to 90) pushes the expiry out from whichever is later: now or the current expiry. Works on pending and expired invitations; others return 400 invalid_request.
Cancel an invitation
POST /invitations/{id}/cancel closes a pending invitation. The link stops working at once, the invitation becomes canceled and its session cancelled. An invitation that has started cannot be cancelled.