long_answer question needs something more: a rubric (named criteria, each worth part of the marks) or a model answer (the answer an examiner would accept), or both. Rubrics and model answers apply to long_answer questions in both handwritten and typed exams.
The rubric object
boolean
default:"true"
Whether a criterion can earn part of its marks.
string
Instructions for this question, up to 4,000 characters.
object[]
required
1 to 30 criteria.
Validation rules
Rubrics are checked when you send them, so a wrong rubric never silently changes how a paper is marked.Keep marks out of guidance
Marks belong incriteria[].marks only. If guidance also mentions marks, the grader gets two sources of truth that can disagree. The check refuses:
- A number followed by
mark,marks,mk,point,ptsand similar: “2 marks”, “1.5 points”. - A number word followed by
mark(s): “half marks”, “full marks”, “two marks”. - An awarding verb (
award,give,deduct,allot,allocate,assign,grant,cut) followed by an amount: “award 1”, “give half”, “deduct one”. - The signs
½,¼and¾.
- Refused
- Accepted
Phrases like “give full credit” also match the check, because “give” is followed by “full”. Write “credit if the student names glucose” instead.
Model answers
A model answer is plain text, up to 20,000 characters: the answer an examiner would accept, with the points that earn marks. You can send it on its own or alongside a rubric.Without a rubric
A generated rubric is consistent, but nobody has reviewed it. Read it with
GET /exams/{id}/rubrics after the first copy, and replace it with your own if needed.
Set rubrics and model answers
You can send rubrics and model answers inline with each question onPOST /exams or POST /exams/{id}/questions. To change them later, use one of the endpoints below. They work in draft and after open, until the exam is finalized.
- One question: PUT
- Many questions: PATCH
PUT /exams/{id}/questions/{question_id}/rubric{"rubric": {...} | null, "model_answer": "..." | null}:
- Key left out: that part is left as it is.
null: that part is deleted.- Value: that part is replaced.
max_marks. You can also set or clear a rubric with PATCH /exams/{id}/questions/{question_id} and a rubric or model_answer field.
Versions and If-Match
Every accepted change bumps the exam’s rubric version. Each result records therubric_version it was graded with, so you can tell which results were graded before a change.
To avoid overwriting someone else’s edit (for example, a teacher editing the same rubric in the dashboard), send If-Match: <version> with the version you last read:
- Read the current version with
GET /exams/{id}/rubrics. - Send your change with
If-Match: 4. - If the rubric is no longer at version 4, you get
412 rubric_version_mismatchwithdetails.expectedanddetails.current. Re-read, merge and retry.
If-Match takes a plain number (4, "4" and W/"4" are all accepted). Anything else returns 422 validation_failed. An exam with no stored rubric yet is at version 0.
Sync status
Changes are saved straight away and then delivered to the grader. Usually that takes a moment and the response carries the newversion. If delivery is delayed, the response carries "version": null, "sync": "pending", and delivery is retried automatically every minute. While changes are pending, a write with If-Match returns 412 rubric_version_mismatch, because the current version isn’t known yet. Retry shortly.
If the grader refuses a change that was already accepted, GET /exams/{id}/rubrics shows "sync": "failed" and a sync_error object listing the affected question_ids. Set those questions’ rubrics again to clear it.
Read rubrics
GET /exams/{id}/rubrics (scope evaluation:read) returns every question’s rubric and model answer, with changes that are still syncing already applied:
source is partner (you set it), generated (created from the question text) or none. If the grader is briefly unreachable, this call returns 503 engine_unavailable with Retry-After: 30.
Rubric generation on request and rubric locking are on the roadmap. Until then, write rubrics yourself, or let the first copy generate them and review them afterwards.