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 |
code | The candidate's final submission, when the round had an editor |
code_language | The editor mode it was written in, when the client sent one |
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 | Posture, derived from video, score 0 to 100. Eye Contact and Emotional State are withheld for institutions, see below |
code_score | Zeros unless the round ran code. See below: zeros do not always mean nothing was written |
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.
Institutions do not receive Eye Contact or Emotional State. Inferring emotion
in an education institution is a prohibited practice under EU AI Act Art. 5(1)(f),
so those two entries are removed from behavioural_analysis before the report
leaves us. Posture is unaffected. Only a self-signup learner practising on their
own account still receives them, and the same rule applies to the sandbox sample,
so what you parse in sandbox is what you get on live. Do not treat a missing entry
as a scoring failure.
Sandbox returns a sample, not a 404. Scoring runs off the recording and
sandbox never records, so there is nothing to measure. Rather than leave you
without a shape to parse, GET /v1/interviews/{id}/report answers with a
sample report. It has the real shape, the real keys and the real scales,
and carries "sample": true.
Its numbers are fixed placeholders that describe nobody. Gate on sample
before showing a report to a user, and use a live key for real scores. The
sample also carries the audio-only sentinel in behavioural_analysis, so
handling it is part of what you can test in sandbox.
The transcript is unaffected: it is uploaded when the interview ends rather
than by the scoring pipeline, so GET /v1/interviews/{id}/transcript returns
the real thing in sandbox.
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.
Zero code_score with code present
Before scoring, we check the submission is a genuine attempt at the question that
was asked. A snippet that does not engage with it, a print("hello") left behind
while testing the editor, scores 0 across the board with the reason "No code
available for evaluation" even though code and code_analysis are populated.
So zeros mean one of two things: nothing was submitted, or what was submitted did
not answer the question. Read code_analysis to tell them apart. It says outright
when the submission was not a real attempt.
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.