Skip to content

Papers

A paper is a question paper and its marking scheme. We read them into questions, each with its marks and answer key. Someone on your side checks what we read and approves it. From then on, you can submit scripts against it.

processing ──▶ awaiting_review ──(approve)──▶ ready
│
└────────▶ failed
status Meaning Next step
processing We’re reading the question paper and the marking scheme. Wait for paper.awaiting_review or paper.failed.
awaiting_review The questions, marks and answer keys are read, and processing has been charged. Check the paper, starting with any warnings. Correct it if needed, then approve it.
ready Approved. Create submissions.
failed Not processed, and nothing charged. See failure.code in Appendix A, then create a new paper with a new idempotency key.

POST /v1/papers. Requires an Idempotency-Key.

Parameter Required Description
title Yes Up to 255 characters. Printed on reports.
subject_id Yes A subject from GET /v1/subjects.
question_paper Yes The question paper: { "file_id": "file_…" } or { "url": "https://…" }. One PDF.
marking_scheme Yes The marking scheme, in the same form. One PDF.
results_release No automatic (default): a result is final as soon as its script is marked. after_review: results wait for a reviewer to release them. See Releasing results.
grading.strictness No How strictly to apply the marking scheme: lenient, standard (default) or strict.
grading.feedback No How much feedback we write: none (marks only), brief (one short sentence for each question and part), standard (the default: feedback, strengths and points to improve) or detailed (standard, plus the idea behind each question the student lost marks on). Less feedback is quicker to mark. See Retrieve a result for what each level returns.
grading.instructions No Extra guidance for marking this paper, up to 5,000 characters. We also read the general instructions printed in the marking scheme, so you don’t need to repeat them. Board-wide marking principles aren’t copied from the scheme.
external_id No Your ID for the paper, up to 128 characters, unique per mode.
metadata No See Your own IDs and metadata.
test_outcome No Test mode only. See Simulating outcomes.
{
"title": "Physics Paper 2 - Mock exam",
"subject_id": "subj_8Hn2Qx5Lw1",
"question_paper": { "file_id": "file_Qp4Ys8Lm1R" },
"marking_scheme": { "url": "https://cdn.example.com/papers/physics-p2-ms.pdf" },
"results_release": "automatic",
"grading": {
"strictness": "standard",
"feedback": "standard",
"instructions": "Accept answers in SI or derived units."
},
"external_id": "MOCK-PHY-P2-2026",
"metadata": { "course": "IGCSE Physics", "term": "Autumn 2026" }
}

Response 201 returns the Paper with status: "processing".

A paper’s subject, documents, results_release and grading can’t change after creation, either through the API or in the review workspace. To change them, create a new paper.

{
"id": "pap_3fT9qLx2Wd",
"object": "paper",
"livemode": true,
"title": "Physics Paper 2 - Mock exam",
"subject_id": "subj_8Hn2Qx5Lw1",
"status": "ready",
"failure": null,
"warnings": [],
"question_paper": { "file_id": "file_Qp4Ys8Lm1R", "pages": 16 },
"marking_scheme": { "file_id": "file_Ms7Tg3Kd9P", "pages": 12 },
"question_count": 11,
"total_marks": 90,
"results_release": "automatic",
"grading": {
"strictness": "standard",
"feedback": "standard",
"instructions": "Accept answers in SI or derived units."
},
"billing": { "status": "charged", "pages": 28, "credits": 28 },
"submission_counts": {
"queued": 2, "processing": 5, "graded": 0,
"released": 41, "failed": 1, "canceled": 0
},
"external_id": "MOCK-PHY-P2-2026",
"metadata": { "course": "IGCSE Physics", "term": "Autumn 2026" },
"created_at": "2026-10-06T09:00:00Z",
"approved_at": "2026-10-06T09:10:12Z",
"updated_at": "2026-10-06T11:02:45Z"
}
Field Type Description
status string See Paper statuses.
failure object { "code", "message" } when status is failed, otherwise null.
warnings array Codes for things your reviewer should check. See Paper warnings.
question_paper, marking_scheme object The File behind each document, with its page count. For a document sent as a link, file_id and pages are null until we’ve downloaded it.
question_count integer How many questions we read. null while processing.
total_marks number The most a student can score, after any choice rules your reviewer sets. null while processing.
billing object See The billing object.
submission_counts object How many of the paper’s submissions are in each status.
approved_at timestamp When the paper was approved, or null.

A paper can reach awaiting_review with things we weren’t sure of. Your reviewer should check each one before approving.

Warning Meaning
questions_may_be_incomplete The paper is long, and we may not have read every question. Compare the question list with the paper.
answer_keys_missing Some questions have no answer key, or the marking scheme may not belong to this paper. A question without a key is marked on our examiner’s judgement.
scheme_instructions_not_used We couldn’t use the general instructions printed in the marking scheme, because they were unreadable or too long.

POST /v1/papers/{id}/review_links

Parameter Required Description
reviewer Yes The name or email of the person you’re sending the link to, up to 100 characters. It is shown in the workspace and recorded against every change they make.
expires_in_hours No From 1 to 24. Default 24.

Response 201:

{
"object": "review_link",
"paper_id": "pap_3fT9qLx2Wd",
"reviewer": "Ms Rahman",
"url": "https://learningaide.ai/review#…",
"expires_at": "2026-10-07T09:06:00Z"
}

A review link opens our marking workspace for this one paper. Your reviewers don’t need an AIDE AI account.

  • While the paper is awaiting_review, reviewers can open the question paper and marking scheme while they check what we read. They can correct any question, mark or answer key, set choice rules (for example “answer any three of questions 5 to 8”), and approve the paper.
  • While the paper is ready, reviewers can check each graded script, adjust marks and feedback, and release results. On an automatic paper this applies only to scripts with no readable answers.
  • Anyone who has the link can do all of the above. Send it only to the reviewer, and never post it anywhere public.
  • Send the link whole: the part after # is what opens the paper.
  • A browser that opens a link stays on that paper until the link expires or the reviewer leaves the review.
  • To withdraw every link for a paper at once, call POST /v1/papers/{id}/review_links/revoke. It returns 200 with { "object": "review_link_revocation", "paper_id": "…", "revoked": 2 }.
  • A link for a processing or failed paper gets 409 review_link_unavailable.

POST /v1/papers/{id}/approve

Approves a paper that is awaiting_review: it becomes ready, and we send paper.ready. Use this when you’ve checked the paper yourself, for example with GET /v1/papers/{id}/questions. It returns the paper. Approving a paper that is already ready returns it unchanged; a processing or failed paper gets 409 paper_not_awaiting_review. A paper with a question that has nothing to mark, such as one left empty while editing in the review workspace, gets 409 paper_has_empty_question, naming the question: fill it in or remove it in the workspace, then approve again. The workspace’s own Approve refuses it the same way.

GET /v1/papers/{id}/questions returns every question in paper order, in a single list.

{
"object": "list",
"data": [
{
"id": "q_4Ws9Tz1Bx6",
"object": "question",
"number": "3",
"section": "Section A",
"type": "written",
"text": "A student connects a lamp to a $6\\,\\text{V}$ battery through a variable resistor.",
"marks": 6,
"answer_key": null,
"options": null,
"correct_option": null,
"parts": [
{
"key": "a",
"label": "a",
"text": "State what happens to the current when the resistance is increased.",
"marks": 2,
"answer_key": "Current decreases (1). Because resistance increases (1)."
},
{
"key": "b_i",
"label": "b (i)",
"text": "Calculate the power of the lamp when the current is $0.5\\,\\text{A}$.",
"marks": 4,
"answer_key": "$P = IV$ (1); $6 \\times 0.5$ (1); $3$ (1); W (1)."
}
]
},
{
"id": "q_9Zc2Xv7Bn4",
"object": "question",
"number": "4",
"section": "Section A",
"type": "multiple_choice",
"text": "Which quantity is a vector?",
"marks": 1,
"answer_key": null,
"options": [
{ "label": "A", "text": "Mass" },
{ "label": "B", "text": "Velocity" },
{ "label": "C", "text": "Energy" },
{ "label": "D", "text": "Temperature" }
],
"correct_option": "B",
"parts": []
}
],
"has_more": false,
"next_cursor": null
}
Field Type Description
id string Unique ID, prefix q_. Results refer to questions by this ID.
number string The question’s position in the paper: "1", "2", "3" and so on.
section string The paper section, or null.
type string multiple_choice for a question that is a single multiple-choice item; otherwise written.
text string The question as we read it, in our text format. Diagrams aren’t included.
marks number Marks available, as printed. Usually the sum of its parts, but less where students choose among the parts.
answer_key string The marking scheme’s answer for the whole question. null for multiple choice (see correct_option) and for a question with parts (each part has its own).
options array For multiple choice, the options with their labels. Otherwise null.
correct_option string For multiple choice, the label of the correct option, or null if the marking scheme gives none.
parts array The question’s marked parts as a flat list, in order, each with key, label, text, marks and answer_key. key shows the nesting: b_i is part (b)(i). A multiple-choice item inside a question with parts appears as an ordinary part. Empty when the question has no parts.
Endpoint Description
GET /v1/papers/{id} Retrieve a paper.
GET /v1/papers List papers. Filter by status, subject_id or external_id, plus the list parameters.
PATCH /v1/papers/{id} Change title, external_id or metadata. Nothing else can change. Returns the paper.
DELETE /v1/papers/{id} Delete a paper with all its submissions, results and reports. Returns 204. Refused with 409 paper_in_progress while the paper is processing or any of its submissions is queued or processing. Credits already charged are not returned.