Skip to main content

Interview as a Service

You already have an ATS, or your own hiring pipeline. You do not want Tarkflo's dashboard, its pipeline stages or its candidate emails. You just want one thing: a candidate interviewed by Tarkflo's AI, on Tarkflo's own interview page, with a result you can read back into your own system.

That is this flow. It is three calls, not two: Submit candidates is for a workspace that runs its pipeline in Tarkflo's dashboard. This is for one that does not.

create ──▶ interview_url, shown once ──▶ candidate opens it, interviews ──▶ poll status ──▶ completed ──▶ report

One-time setup: a job built for this​

Create an interview needs a job whose workflow opens with an AI interview round — nothing else happens first, no CV screen, no outreach step. Build this once in the Tarkflo dashboard: the interview's questions, its rubric, how long it runs, and whether scheduling is required all live there, by design. The API never creates or edits a workflow. See Read jobs, workflows and templates to confirm a job is set up this way before using it here: its first round's interview_kind should be two_way.

A job set up any other way — a CV screen first, an outreach step first — gets 409 job_not_interview_ready. Use Submit candidates for that job instead; this flow is specifically for a job with nothing before the interview.

Create an interview​

One candidate per call, not a batch: you are starting one interview, not filling a pipeline. Send an Idempotency-Key, the same rule as Submit candidates.

curl -X POST https://api.tarkflo.com/v1/interviews \
-H "Authorization: Bearer $TARKFLO_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"job_id": "66f1c2a9b3d4e5f607182934",
"name": "Ananya Rao",
"email": "ananya.rao@example.com",
"external_id": "greenhouse-48213"
}'
{
"id": "66f2d4b8e1a7c3095b6f8a21",
"job_id": "66f1c2a9b3d4e5f607182934",
"status": "ready",
"candidate": { "name": "Ananya Rao", "email": "ananya.rao@example.com", "external_id": "greenhouse-48213" },
"decision": null,
"scheduled_at": null,
"created_at": "2026-10-02T09:41:12.000Z",
"updated_at": "2026-10-02T09:41:12.000Z",
"interview_url": "https://hire.tarkflo.com/?token=x7k2m9qa4cjv1n0bRaNDoM",
"link_expires_at": "2026-10-16T09:41:12.000Z"
}

interview_url is shown once, in this response. Tarkflo stores only a hash of the token inside it, the same way your own API key's secret works, so it cannot be read back by any other call. Store it immediately, next to id. Hand it to the candidate however you already reach them: an email, a message, a link inside your own product. Tarkflo never emails the candidate on this path. That is the point: your system owns that relationship.

If you lose the link before using it, call Get a fresh interview link. It mints a new token and invalidates the old one.

What the candidate sees​

They open interview_url in a browser. If the job requires booking a time slot, they pick one first; otherwise they start right away. Either way, this happens entirely on Tarkflo's own interview page — the API does not drive it, and cannot skip it.

Poll status​

curl "https://api.tarkflo.com/v1/interviews/66f2d4b8e1a7c3095b6f8a21" \
-H "Authorization: Bearer $TARKFLO_API_KEY"
statusMeaning
awaiting_scheduleThe job requires booking a time slot, and the candidate has not booked one yet.
scheduledA slot is booked. scheduled_at says when the interview opens.
readyNo scheduling is required. The link works as soon as the candidate opens it.
in_progressThe candidate is interviewing right now.
completedScored. Get an interview's report has something to return.
abandonedThe candidate started and left before it finished.

This never returns interview_url — there is nothing to read back once it was shown. Poll on whatever interval suits you; it costs the same as any other read and shares your key's normal rate limit.

Get the result​

Once status is completed:

curl "https://api.tarkflo.com/v1/interviews/66f2d4b8e1a7c3095b6f8a21/report" \
-H "Authorization: Bearer $TARKFLO_API_KEY"
{
"interview_id": "66f2d4b8e1a7c3095b6f8a21",
"status": "completed",
"score": 82,
"verdict": "YES",
"decision": "HIRE",
"summary": "Strong on system design, communicated trade-offs clearly, no gaps on the role's core stack.",
"report_url": "https://hire.tarkflo.com/r/9f1c8a3b5d7e2f4061a8c9d0e1f2a3b4",
"report_url_expires_at": "2026-11-01T10:24:51.000Z"
}

score, verdict and decision are enough to drive a go/no-go in your own system. report_url is a scoped, expiring link to the full report on Tarkflo, the same kind a recruiter shares from the dashboard — open it for the competency breakdown and the AI's written reasoning. It never carries the transcript, the recording or the rubric an answer was scored against: a leaked key or link cannot be used to see how the interview is graded, and this read never gives you that either. Calling this endpoint again before the link expires returns the same report_url, not a fresh one.

Called before completed, this returns 409 interview_not_ready. Check status first.

Instead of polling: webhooks​

Set a webhook URL in Settings, Integrations and Tarkflo posts interview.completed the moment a round is scored, report.ready right after. Both carry application_id (the same ID as interview_id here), and report.ready includes report_url. Use polling for a simple integration, or combine both: a webhook tells you when to stop polling.

Errors specific to this flow​

StatusCodeWhat it means
409job_not_interview_readyThe job's workflow does not open with an AI interview round. Build one for this, or use Submit candidates for a different pipeline.
409interview_not_readyThe report was requested before the interview completed.
409interview_liveA relink was requested while the candidate is interviewing. Reissuing a link would end their session.
404interview_not_foundThe ID is wrong, or this key cannot see it.
422no_candidates_createdThe candidate could not be created. details.failed[0] says why, the same shape Submit candidates uses.

See Errors for the full list every endpoint shares.