Skip to main content

Phone screens

An AI interviewer calls the candidate on their phone, over your own SIP trunk.

A phone_screen is an AI interview conducted over the telephone. There is no browser, no link and nothing for the candidate to install: we dial their number, the interviewer speaks to them, and you get the same transcript and report any other interview produces.

It suits the candidates a link does not reach. People who will take a call but will not sit in front of a webcam, roles hired at volume, and the first pass where you mostly need to confirm interest, availability and a few facts.

GET /v1/assessment-types lists it with its credit cost. It needs the AI Voice Calls module on your organization, which we turn on for you once a trunk is connected.

You bring the number

We never supply a phone number. Calls are placed over your own SIP trunk, on your own number, so the candidate sees a number they recognize and your carrier bills you for the minutes.

Connecting a trunk is not an API step, and it is not self-serve yet. Send us your carrier details and we set it up with you: it needs credentials from your carrier and an allowlist entry on their side so our calls are accepted. Twilio, Plivo, Vonage and any standards-compliant SIP trunk all work, because every one of them is reached over plain SIP.

Once it is connected, read your numbers:

curl https://hiring-api.experthire.cloud/v1/phone-numbers \
  -H "Authorization: Bearer $EH_KEY"

Still a placeholder: $EH_KEY. Add it under Your values above.

{
  "object": "list",
  "data": [
    {
      "object": "phone_number",
      "id": "0f9c2a71-3e5b-4a18-9d64-7c1b2e8f5a03",
      "phone": "+14155550100",
      "label": "US recruiting line",
      "provider": "twilio",
      "inbound_enabled": false,
      "outbound_enabled": true,
      "registered": true,
      "created_at": 1767225601
    }
  ],
  "has_more": false,
  "total_count": 1
}

A number that is not registered or not outbound_enabled cannot place a call.

Create one

The candidate needs a phone number in international format. Send it on the candidate, or override it per call later.

curl -X POST https://hiring-api.experthire.cloud/v1/assessments \
  -H "Authorization: Bearer $EH_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "phone_screen",
    "job_id": "'$JOB_ID'",
    "candidate": {
      "name": "Jane Doe",
      "email": "[email protected]",
      "phone": "+14155550123"
    },
    "duration_minutes": 15
  }'

Still a placeholder: $EH_KEY, $JOB_ID. Add them under Your values above.

  • duration_minutes is 5 to 60, and 15 if you leave it out. A phone screen is shorter than a video interview by design.
  • questions works as it does on an AI interview: your list becomes the pool the interviewer draws from.
  • round_type and send_invite are refused. The shape is fixed, and there is no link to email.

phone is written to the candidate only when they do not already have one, so naming an existing candidate never overwrites a number one of your recruiters corrected. Patch it deliberately with PATCH /v1/candidates/{id}.

Creating the assessment does not call anybody. Nothing is dialed until you say so.

Place the call

curl -X POST https://hiring-api.experthire.cloud/v1/assessments/$ID/call \
  -H "Authorization: Bearer $EH_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Still a placeholder: $EH_KEY. Add it under Your values above.

With one outbound number connected you can leave the body empty: we call the candidate's number from the only number that can dial. Name phone_number_id once you have more than one, and to to call a different number for this attempt only.

The call returns as soon as it is placed, not when it is answered:

{
  "object": "call",
  "id": "5d3a6c19-8b2f-4e70-a1c4-92f6b0e7d518",
  "assessment_id": "3b8e1d02-5c77-4c2a-8a41-9b2f7e6d4c10",
  "status": "dialing",
  "from": "+14155550100",
  "to": "+14155550123",
  "attempt": 1,
  "duration_seconds": 0,
  "credits_spent": 0,
  "created_at": 1767225601
}

Nobody picks up the first time

That is the normal case, so it is worth building for.

GET /v1/assessments/{id}/calls returns every attempt with how it ended. Call again when one goes unanswered. Each attempt is its own row; the assessment stays open.

DispositionWhat happenedCall again?
answeredThey picked up and the interview ranNo
no_answerIt rang outYes, later
busyThe line was engagedYes, shortly
rejectedThey declined itOnce, then stop
voicemailIt reached an answering machineYes, at a different hour
invalid_numberThe number is not reachableNo. Fix the number first
trunk_unreachableYour trunk did not accept the callCheck the trunk, not the candidate
failedThe call could not be placedCheck the trunk

What a screen costs

A phone screen costs credits once, when the candidate answers, however many attempts it took to reach them. A call that rings out, hits a busy line, reaches voicemail or is declined costs nothing.

credits_spent on each attempt tells you which one carried the charge, and at most one per assessment ever does. Creating the assessment charges nothing, and cancelling it refunds nothing, because nothing was taken.

What you get back

The same things a browser interview produces: GET /v1/assessments/{id}/report for the score and feedback, GET /v1/assessments/{id}/transcript for what was said. A phone screen is written up and scored through the same path an ai_interview uses, so the webhooks you already handle fire for it too, keyed on the same assessment id.

Two differences worth knowing. There is no video, so the report carries no visual signals. And a phone screen has no room to embed: POST /v1/sessions and POST /v1/assessments/{id}/launch-link are refused on one with unsupported_operation.

Ending a call

The interviewer ends the call itself when the screen is done. POST /v1/assessments/{id}/cancel hangs up a call that is still running and closes the assessment. A candidate who hangs up early ends the call, and the interview is written up from what was said.

Sandbox

A sandbox key can create a phone screen, list its attempts and receive its webhooks, so you can build the whole flow without spending anything. It will not dial: the call endpoint returns sandbox_cannot_call. Use a live key to reach a real phone.

When it will not dial

CodeStatusWhat to do
candidate_phone_required400The candidate has no number. Set one, or pass to
invalid_phone400Use international format, for example +919876543210
phone_number_required400More than one of your numbers can dial. Name one
no_calling_number409No trunk is connected yet
call_not_placeable409Already on a call, or the candidate asked not to be called
sandbox_cannot_call400Sandbox never dials. Use a live key
agent_unavailable503The interviewer is not ready. Retry shortly

We refuse rather than dial when anything is wrong. A refused call creates no attempt and costs nothing.

Next