Reports
What comes back, and what to ignore.
GET /v1/assessments/{id}/report returns the scored result once the assessment
has been scored. Before that it is a 404, deliberately, rather than a
zero-scored report for something nobody has taken.
Do not gate on status == "completed". Shortlisting or rejecting a candidate
overwrites the status in place, so a scored assessment often reads
shortlisted or rejected. The report is available for all three.
The envelope
Both assessment types return the same envelope. The type-specific detail sits in
feedback for an AI interview and in screening for a resume screen.
{
"object": "assessment_report",
"assessment_id": "3b8e1d02-5c77-4c2a-8a41-9b2f7e6d4c10",
"type": "ai_interview",
"status": "completed",
"livemode": true,
"score": 68,
"outcome": "good_fit",
"summary": "Answered clearly with concrete examples, hesitant on trade-offs.",
"question": "Walk me through a system you owned end to end.",
"feedback": { "...": "see below" },
"recording_url": "https://...",
"transcript_url": "https://...",
"created_at": 1767229200
}
outcome is good_fit, unlikely_fit or incomplete. It is empty until the
scoring pipeline has run, which is the most reliable "is this scored yet" check.
Resume screens
A resume_screen carries screening instead of feedback. Every number is
0-100.
{
"object": "assessment_report",
"assessment_id": "9d41c7b8-2e35-4a19-b6f0-1c8a5d3e2f47",
"type": "resume_screen",
"status": "completed",
"livemode": true,
"score": 74,
"outcome": "good_fit",
"screening": {
"ats_readiness": 81,
"readability": 76,
"experience_relevance": 72,
"formatting": 68,
"domain_skill_fit": 79,
"must_have_coverage": 83,
"good_to_have_coverage": 55,
"weighted_skill_score": 75,
"strengths": "Six years on payments infrastructure.",
"weaknesses": "No evidence of team leadership."
},
"created_at": 1767229200
}
must_have_coverage and good_to_have_coverage are the percentage of each
skill group the resume evidences. weighted_skill_score combines them at 70/30.
AI interview feedback
The report carries an overall score, a written summary, and a feedback object
with the detail.
Three arrays inside feedback use different key names, which is the most
common thing to get wrong:
| Array | Keys | Scale |
|---|---|---|
speech_analysis | criteria, rating, comments | 1-100 |
behavioural_analysis | label, score, outcome | 0-100 |
field_knowledge | criteria, score, comments | 0-100 |
Note rating on one and score on the others. They are genuinely different
fields, not one field described two ways.
{
"speech_analysis": [
{ "criteria": "Fluency", "rating": 72, "comments": "Steady pace, few fillers." }
],
"behavioural_analysis": [
{ "label": "Posture", "score": 61, "outcome": "Composed" }
],
"field_knowledge": [
{ "criteria": "Handling ambiguity", "score": 61, "comments": "One concrete example." }
]
}
Things that will mislead you
The audio-only sentinel. When there is no video, all three
behavioural_analysis entries come back at score: 0 with
outcome: "Not Analyzed (Audio Only)". That is "we did not measure this", not
"this candidate scored zero". Check the outcome before rendering a number.
field_knowledge criteria are generated per transcript. The names differ
between candidates, so they are readable but not comparable. Do not key a rubric
off them.
Integrity signals travel with the scores. feedback also carries proctoring
data. If you re-render the report to a candidate or a client, allowlist the keys
you want rather than passing the object through.
Media
Recording and transcript URLs are signed and expire in two hours. Do not store them. Store the assessment id and re-fetch.
A field is absent when the artefact was never produced, which is normal for an assessment that ended early.