API

A small REST surface for pulling screening results into your tools and pushing candidates in. It covers what the review page summarises, never the transcript or the written assessment: those stay behind sign-in.

Last updated 8 September 2026.

Authentication

Create a key on your workspace page (owners only). Send it on every request; it acts as the workspace owner.

Authorization: Bearer isk_live_...

Keys are shown once and can be revoked at any time. Limit: 120 requests per minute per key (429 with Retry-After beyond that). Errors are JSON: { "error": { "code": "not_found", "message": "..." } }.

Screenings

GET /api/v1/screenings?status=ACTIVE&limit=50&cursor=<id>
GET /api/v1/screenings/:id

{
  "id": "…",
  "title": "Backend engineer screen",
  "company": "Acme",
  "role": "Software Engineer",
  "level": "mid_level",
  "interview_type": "technical",
  "focus": "Backend fundamentals",
  "language": "en",
  "duration_minutes": 30,
  "proctored": true,
  "voice_required": false,
  "video_policy": "OPTIONAL",
  "practice_enabled": true,
  "status": "ACTIVE",
  "plan_status": "READY",
  "invite_ttl_days": 7,
  "candidate_count": 12,
  "created_at": "2026-09-08T09:00:00.000Z"
}

Lists return { "data": [...], "next_cursor": "<id>" | null }; pass next_cursor back as cursor for the next page.

Candidates

GET /api/v1/screenings/:id/candidates?status=COMPLETED&limit=50
GET /api/v1/candidates/:id

{
  "id": "…",
  "name": "…",
  "email": "…",
  "status": "COMPLETED",         // INVITED, CONSENTED, PRACTICING,
                                 // IN_PROGRESS, COMPLETED, EXPIRED, WITHDRAWN
  "source": "INVITE",            // or APPLY_LINK
  "anonymized": false,
  "invited_at": "…", "started_at": "…", "completed_at": "…", "expires_at": "…",
  "experience_rating": 4,        // 1-5, the candidate's own rating, or null
  "ai_signal": 71,               // 0-100, a signal, not a decision;
                                 // null until the interview is scored
  "scored": true,
  "plan_coverage": "4/5",
  "flags_count": 0,              // session flags, context for the recruiter
  "decision": "UNDECIDED",       // UNDECIDED, ADVANCE, REJECT
  "dimensions": [                // GET /candidates/:id only: the numbers,
                                 // never the reasoning
    { "key": "technical_proficiency",
      "label": "Technical proficiency", "score": 7, "max": 10 }
  ],
  "review_url": "https://hire.interviewstack.io/s/…/c/…"
}

A candidate the workspace deleted comes back as anonymized: true with no name or email; the numeric signal stays.

Invite candidates

POST /api/v1/screenings/:id/candidates
{ "candidates": [ { "name": "Ada Lovelace", "email": "ada@example.com" } ] }

201 { "data": [ { "id": "…", "name": "…", "email": "…",
                  "invite_url": "https://hire.interviewstack.io/i/…",
                  "expires_at": "…" } ],
      "skipped": [ { "input": "…",
                     "reason": "Already invited to this screening" } ] }

The invite URL is the candidate's credential: it opens the interview with no sign-in. Send it to the candidate only. InterviewStack does not email it on your behalf through the API; the dashboard's "Email invite" button does. When every candidate was skipped nothing is created, so the call is a 400 nothing_created that carries the same skipped array explaining why. 409 when the screening is closed or its plan failed.

Webhook subscriptions

The same signed deliveries as the dashboard webhook (see Webhooks), created and removed by API. This is the REST-hook model Zapier and similar tools use.

GET    /api/v1/webhooks
POST   /api/v1/webhooks
       { "url": "https://…", "events": ["screening.completed"] }
       201 { "id": "…", "url": "…", "events": [...],
             "secret": "whsec_…" }   // the secret is shown once
DELETE /api/v1/webhooks/:id

Up to ten live subscriptions per workspace. Revoking the key that created a subscription does not delete the subscription; delete it explicitly.

API | InterviewStack for Recruiters