Tests

Create a test

Create a sitting of an approved question paper. One paper can back multiple tests.

The paper must already be APPROVED — approve it in the Acadine dashboard first. A paper in any other status is rejected with 409 rather than approved automatically, so machine-extracted questions are never put in front of students unreviewed.

By default the test is scheduled for every batch on the question paper's course. Pass batch_ids to narrow it to specific batches; each must be on that same course. Scheduling a test for a batch notifies its students, so pass an explicit list if the default is wider than you intend. The batches actually used come back on the response.

A test is always scheduled for at least one batch: an empty batch_ids is rejected, and a course with no batches gets one named Default created for it.

Scheduling and timing

Every test runs over an availability window: starts_at and ends_at are both required, and ends_at must be after starts_at. The window may be in the past, so a test that has already been sat can be recorded after the fact.

duration_mins is what makes the test timed. It is a per-student clock that starts when each student starts, so the window says when the test is open and duration_mins says how long any one student gets:

Windowduration_minsResult
09:00–12:00omittedThree hours, open to all — students may use the whole window.
09:00–12:0060A one-hour test that can be started any time between 09:00 and 12:00.

An attempt ends at whichever comes first: the student's own clock or ends_at.

How students answer

Pick at most one of these — a test is answered one way, so combining them is rejected:

FlagHow answers reach us
(none set)Students write on paper; you upload the scanned sheets.
is_cbtStudents answer on screen in the app. Nothing is scanned.
is_omrStudents fill a paper bubble sheet; you upload the scans.
allow_student_answer_sheet_uploadStudents photograph and upload their own sheets.
post/v1/tests

Request

  • Base URL: https://api.acadine.ai (the document declares no server; this is the origin it was published from)
  • URL: https://api.acadine.ai/v1/tests
  • Auth: API key in header X-API-Key

Request body

question_paper_idstring required

From GET /v1/question-papers. Must be APPROVED — a paper in any other status is rejected with 409. Papers are approved in the Acadine dashboard.

namestring required

Display name for this sitting.

batch_idsstring[] nullable

Which batches sit this test. Omit to schedule it for every batch on the course the question paper belongs to. Pass an explicit list to narrow it — each id must be a batch on that same course, or the request is rejected. The list cannot be empty: a test is always scheduled for at least one batch.

Students in the scheduled batches are notified that the test has been scheduled.

If the course has no batches at all, one named Default is created and the test is scheduled for it, so the call still succeeds.

starts_atstring date-time required

When the test opens. Students may begin any time from here until ends_at. May be in the past — useful for recording a test that has already been sat.

ends_atstring date-time required

When the test closes — a hard cutoff for everyone, however late they started. Must be after starts_at, and may also be in the past.

duration_minsinteger nullable

How long each student gets, in minutes — this is what makes the test timed. The clock is personal: it starts when that student starts, not when the window opens, so students who begin at different times each get the full duration. Their attempt ends at whichever comes first, their own clock running out or the window closing at ends_at.

Omit it and there is no personal clock — students may use the window right up to ends_at. So a 3-hour window with duration_mins: 60 is a one-hour test students can start any time within three hours; the same window without it is a three-hour test.

Must be at least 1 and cannot exceed the window length (ends_at − starts_at) — a longer value is rejected, since a student could never use the extra time.

is_cbtboolean

Students answer on screen, in the app — nothing is written or scanned. Answers are submitted digitally and graded immediately, so the paper must be entirely multiple choice, multiple select, or numeric-answer questions; a paper containing anything that cannot be auto-graded is rejected.

is_omrboolean

Students fill in a paper OMR (bubble) sheet, which you scan and upload. Grading reads the darkened bubbles rather than marking written answers.

shuffle_questionsboolean

Shuffle question order per student, so no two see the same sequence. The question paper itself is unchanged.

allow_student_answer_sheet_uploadboolean

Students photograph and upload their own handwritten answer sheets, instead of you uploading scans on their behalf. Uploads are collected until the test closes at ends_at and evaluated together shortly after.

external_test_refstring nullable

Your own identifier for this test. Opaque to Acadine — stored as-is and echoed back on GET /v1/tests/{test_id} and GET /v1/tests/{test_id}/results/{student_ref}, so you don't have to cross-reference our test_id for support/reconciliation.

Example request

{
  "duration_mins": 180,
  "ends_at": "2026-03-14T12:00:00Z",
  "name": "Physics Term 1 — Morning",
  "question_paper_id": "QPR_2msnplIgOEXImjfvuihUqhIqNJO",
  "starts_at": "2026-03-14T09:00:00Z"
}

Response

Successful Response

test_idstring required
namestring required
status'CREATED' | 'COMPLETED' | 'CANCELLED' required

Lifecycle of a test. Mirrors the internal TestStatus one-for-one.

question_paper_idstring required
course_idstring required
subject_idstring required
total_marksnumber required

Copied from the question paper.

starts_atstring date-time nullable
ends_atstring date-time nullable
duration_minsinteger required

The per-student clock actually applied — the full window length when none was given.

batch_idsstring[] required

The batches this test is scheduled for.

is_cbtboolean required
is_omrboolean required
shuffle_questionsboolean required
allow_student_answer_sheet_uploadboolean required
created_atstring date-time required
external_test_refstring nullable

Your own identifier for this test, if you set one at creation.

Example response

{
  "test_id": "TST_2msnplIgOEXImjfvuihUqhIqNJO",
  "name": "Physics Term 1 — Morning",
  "question_paper_id": "QPR_2msnplIgOEXImjfvuihUqhIqNJO",
  "course_id": "ORG_CRS_2msnplIgOEXImjfvuihUqhIqNJO",
  "subject_id": "ORG_SUB_2msnplIgOEXImjfvuihUqhIqNJO",
  "total_marks": 100,
  "duration_mins": 180,
  "batch_ids": [
    "BCH_2msnplIgOEXImjfvuihUqhIqNJO"
  ],
  "created_by": {
    "id": "USR_2msnplIgOEXImjfvuihUqhIqNJO",
    "name": "Anita Sharma"
  },
  "external_test_ref": "their-test-4471"
}

Changes

No recorded changes to this operation across all 1 revision of this API.