Skip to main content
Every request on this page requires a Bearer API key. With these endpoints your system can set an exam up from start to finish without opening the admin panel: create the exam with its tests and sessions, assign a question package to each session, check that the exam is ready, and run the IRT calculation once participants have finished.

Flow

  1. Prepare question packages through the Question Import API and store question_bank.id, or pick an existing question package with GET /question-banks.
  2. Create the exam with its tests and sessions in one POST /exams request.
  3. Check GET /exams/{exam}/readiness until ready is true.
  4. Register participants and create access links through Exam Registration and Access Links.
  5. For tests scored with IRT, run POST /exams/{exam}/irt-calculations once participants have finished. Scores are sent through the exam_result.scored webhook and are available in the Exam Results API.

Rules

  • Kind of exam. Exams created through the API take no payment inside the CBT and are not multi-level. Multi-level exams and exams with payment inside the CBT that were created in the admin panel can still be read, but can only be changed or deleted in the admin panel. Manual-answer tests (essay/file upload) are created in the admin panel; through the API only their name, instructions and sessions can change.
  • Edition (edition):
    • standard (Standard Exam): up to 4 tests, without CAT and without camera, screen or dual-monitor proctoring.
    • professional (Professional Exam): up to 30 tests, with every feature.
    • Credit is used when a participant starts a test, not when the exam is created. A professional exam uses professional credit; a standard exam uses free credit first, then professional credit. Without credit an exam can still be created, but participants cannot start its tests.
  • Times are sent in ISO 8601 with an offset, for example 2026-11-10T08:00:00+07:00 or 2026-11-10T01:00:00Z, and are returned in WIB (+07:00). A time without an offset, such as 2026-11-10 08:00:00, is refused with 422. An exam’s end_at is at most one year from now.
  • Sessions must sit inside the exam’s time range and last at least as long as their test. A session’s question package must belong to the project, match its test’s type (CBT/CAT for CBT and CAT tests, manual answer for manual-answer tests) and hold at least one question; for a CAT test every question needs a difficulty level.
  • Automatic sessions (is_auto_assign_session, default true): registered participants get the first (earliest-created) session of every test. Participants registered before a test had a session get that session automatically when it is created.
  • Test order follows the order in which the tests were created. When is_must_be_in_order is true, participants must finish the tests in that order.
  • Participants see an exam while it is inside its time range and not archived. A test can only be started during a session that has a question package.

What is locked

Error format

Invalid input is returned with status 422 in the same error format as other endpoints. Error keys name the field, nested fields included, for example exam_quizzes.0.sessions.1.end_at.
A change the exam’s current state does not allow is returned with status 409 and a code field:

Test settings

Exam endpoints

The whole request is checked first; if anything is wrong, nothing is stored. Tests and sessions are optional and can be added later.

Parameters

Example request

Example response

Status 201. The body is the same as the exam details, including exam_quizzes and sessions with their IDs. Store the exam, test and session IDs for later changes.
The example above is shortened; the full response carries every exam, test and session field.
Only the fields sent change. The fields are the same as POST /exams without exam_quizzes. The endpoint also accepts the PUT method.
  • The new time range must still contain every session; change the sessions first when needed.
  • Changing edition to standard is refused when the exam has more than 4 tests or a test that uses a professional feature.
  • Changing final_score_type recalculates the participants’ final scores.
  • Turning is_auto_assign_session on places participants without a session in the first session of every test right away.

Example request

The response holds the updated exam, in the same shape as POST /exams.
Refused with 409 (attempt_started) once a participant has started a test. Multi-level exams and exams with payment inside the CBT can only be deleted in the admin panel.

Test endpoints

The body is the same as one exam_quizzes item of POST /exams, sessions included. The new test goes last in the order. Participants already registered get the new test straight away, and its session when automatic sessions are on.
Status 201; the response holds the test with its sessions.
Only the fields sent change: name, exam_type, duration_minutes, score_type, description and the is_* settings. A new duration cannot be longer than the test’s existing sessions. On a manual-answer test only name and description can change; other fields are refused with 422. The endpoint also accepts the PUT method.
Refused with 409 (participants_registered) once participants are registered for the exam. The test’s sessions are deleted with it.

Session endpoints

Status 201:
Participants still working when the session ends are finished automatically by the system.
Only the fields sent change and are checked, so renaming a session does not recheck its schedule and question package. Refused with 409 while a participant is working in this session, and the question package cannot be replaced once a participant has started. To switch to a new question package revision before the exam starts, send the new question_bank_id. The endpoint also accepts the PUT method.
Refused with 409 (participants_registered) once participants are placed in this session.

Readiness and scoring

Lists what keeps participants from taking the exam. ready is true when there is no issue with severity error; a warning flags something to look at that does not block the exam.
Calculates the scores of every IRT test of the exam, like Calculate Score → IRT Calculation in the admin panel. It can run once a participant has finished a test and nobody is still taking one. It can run again, for example after late participants finish; every score change sends the exam_result.scored webhook. While a calculation is still queued or running, another request is refused with 409 (calculation_running).
Status 202:
The status of the latest calculation of every IRT test:

Question packages

The project’s question packages, to assign to sessions. A question package created by an import has is_locked: true and a source naming its package and revision.