Reports
Reading a result, and what a score does and does not mean.

Fetch a report once the interview reaches Completed. Before that you get 404
report_not_ready naming the current status, rather than a report full of
zeros that reads like a candidate who scored nothing:
curl https://prep-api.experthire.cloud/v1/interviews/$ID/report \
-H "Authorization: Bearer $EH_SECRET_KEY"
Still a placeholder: $EH_SECRET_KEY. Add it under Your values above.
Fields
| Field | Notes |
|---|---|
overall_score | 0 to 100 |
summary | Prose summary of how the interview went |
feedback | Scored dimensions, see below |
main_question | The coding or design prompt, when the round had one |
code | The candidate's final submission |
media | Signed URLs, see below |
events | Proctoring signals, unordered. Sort by timestamp |
duration_seconds | Actual time in the room, not the scheduled length |
What is inside feedback
The keys are the same on every round type. Only the contents differ, so a
non-coding round still carries a code_score object holding zeros.
| Key | What it is |
|---|---|
field_knowledge | Subject-matter judgement, score 0 to 100. The criteria are generated per transcript, so the names differ between candidates. Do not key a fixed rubric off them |
speech_analysis | Fluency, Pronunciation, Grammar, Active Listening, Confidence. Note the key is rating, not score, and the scale starts at 1 |
behavioural_analysis | Eye Contact, Posture, Emotional State, derived from video, score 0 to 100 |
code_score | Zeros unless the round ran code |
num_speakers, num_faces_detected, off_platform_time, voice_verification | Integrity signals, not grading |
speech_analysis is judged from the transcript rather than measured from the
audio, so it reflects what was transcribed. There is no words-per-minute or
pause measurement.
An audio-only interview returns all three behavioural_analysis entries at
score: 0 with outcome: "Not Analyzed (Audio Only)". That is a sentinel, not
a candidate who never looked at the camera.
Sandbox reports carry that same sentinel. Sandbox never records, so it is scored from the transcript alone. Every other dimension is produced exactly as it is in live, because they are all judged from the transcript anyway. Use sandbox to build against the shape of a report; use live to evaluate the video-derived scores.
Two cautions:
audio_analysis,hiring_signal,anchor_insightandimpact_indicatorsare present but always empty. Do not build against them.voice_verificationcarries impostor and spoof verdicts. If you re-renderfeedbackto a candidate or to your own client, allowlist the keys you want rather than passing the object through.
Treat feedback as additive: new keys can appear without a version change.
Media
media carries signed URLs valid for two hours:
{
"recording_url": "https://...",
"transcript_url": "https://...",
"face_image_url": "https://...",
"has_whiteboard": false
}
A field is absent when the artefact was never produced, which is normal: an interview that ended in the first minute has a transcript but no recording, and sandbox interviews are never recorded. Check for the field rather than assuming it is there.
Do not store these URLs. They expire. Store the interview id and re-fetch.
To refresh a recording link without pulling the whole report again:
curl https://prep-api.experthire.cloud/v1/interviews/$ID/recording-url \
-H "Authorization: Bearer $EH_SECRET_KEY"
Still a placeholder: $EH_SECRET_KEY. Add it under Your values above.
Transcript
transcript_url above points at the raw stored file. If you would rather not
parse our storage format, ask for it decoded:
curl https://prep-api.experthire.cloud/v1/interviews/$ID/transcript \
-H "Authorization: Bearer $EH_SECRET_KEY"
Still a placeholder: $EH_SECRET_KEY. Add it under Your values above.
{
"object": "list",
"data": [
{ "at": "0:00:00", "speaker": "AGENT", "text": "Thanks for joining..." },
{ "at": "0:00:14", "speaker": "Ada [CANDIDATE]", "text": "Happy to be here." }
],
"total_count": 2
}
at is an offset from the start of the recording, so it lines up with the video.
Entries are in the order they were spoken.
Both this and recording-url return 404 until the interview finishes
processing, with codes transcript_not_ready and recording_not_ready. Those
mean retry later, not that the interview is missing. An interview where nobody
spoke returns an empty list rather than an error.
What a score means
The score reflects one conversation, scored against the role you supplied. It is evidence, not a verdict.
Read it alongside the transcript, particularly when it is near a threshold you care about. The summary explains the reasoning; the number compresses it, and compression loses things.
A short interview is a weak signal. If duration_seconds is well under the
round length, the candidate left early or hit a problem, and the score is built
on less evidence than usual. Treat it accordingly.
Proctoring events
events lists what the candidate's browser reported: tab switches, pastes,
multiple monitors.
An empty array means nothing was reported. It does not mean nothing happened. Browser proctoring reports signals, it does not enforce anything, and some signals require a permission the candidate can simply decline. Multiple-monitor detection is the clearest case: no permission, no signal, and absence is not evidence of a single screen.
Where the result carries real consequences, use the desktop app, which enforces at the operating system level rather than asking the browser nicely.