Contents
On this page

Create Exam - Plugixa Exam

POST /plugixa-exam/v1/exams

Create an exam, with its settings and, optionally, its sections and questions in one call.

Scope exams:write; the token’s user needs the exams:create permission. Creating it already published also needs the exams:publish scope and the user’s exams:publish permission.

Note. An exam created without published is unpublished. Sending "published": true publishes it at once, which needs exams:publish as well; without it the request answers 403 and nothing is created. Since 1.4.1: before, exams:write alone could publish.

Request

POST https://your-site.example/wp-json/plugixa-exam/v1/exams

Request body

Content type: application/json

Only title is required. Every other field has a default, and an enumerated field sent with a value outside its list quietly takes its default instead of failing. “Site default” means the value set under Plugixa Exam -> Settings; the default shown in brackets is the one a new install starts with.

Basics

Field Type Required Description
title string Yes Must not be blank.
slug string No The exam’s address on your site. Made from the title when empty. Made unique by appending -2, -3, …
description string No Plain text. HTML tags are removed.
intro string No HTML shown before the exam starts. Tags outside the question-text allow-list are stripped.
subject_id integer No The subject the exam belongs to. Defaults to 0. Not checked for existence.
published boolean No Defaults to false. Accepts true/false, and also "1"/"0" or "yes"/"no". true needs exams:publish.
certificate_template_id integer No The certificate template to issue. Defaults to 0.

Timing and attempts

Field Type Required Description
time_limit integer No Minutes. 0 (the default) for an untimed exam.
max_attempts integer No Attempts allowed per person. 0 (the default) for unlimited.
cooldown_minutes integer No Minutes to wait between attempts. Defaults to 0.
open_from string No When the exam opens, as a date and time (2026-11-16 08:00:00). Stored in UTC. A value that cannot be read as a date is stored as no date.
open_until string No When the exam closes. Must be after open_from when both are set.
window_close_action string No When a timed attempt would run past open_until: close cuts it off at the closing time, run_out lets the person keep their full time. Site default (close).
attempt_mode string No exam or practice. Site default (exam).
practice_reveal string No For practice mode: on_submit or per_question. Site default (on_submit).

Who may sit it

Field Type Required Description
access_type string No One of the values below. Defaults to access_level.
access_level string No Only kept when access_type is access_level: a WordPress role or capability the person must hold. Empty means any signed-in user.
access_code string No The code people must enter when access_type is code. Only changed when the field is in the body. An empty value clears the code, except on an exam whose access_type is code. Never returned.
access_type Who may sit the exam
access_level Signed-in users, limited by access_level when it is set
open Anyone. Visitors without an account are handled by the site’s anonymous-attempts setting
guest Anyone. Visitors without an account always give a name and email first
code Anyone who enters the access code
restricted Signed-in users who match the exam’s access rules PRO. Without the Cohorts app, only administrators

Results

Field Type Required Description
pass_mark number No Percent needed to pass, 0 to 100, rounded to 2 decimals. Defaults to 50.
result_release string No When people see their result: immediate, after_close (once open_until has passed), scheduled (once release_at has passed) or manual (held back until you change the rule). Site default (immediate).
release_at string No Date and time for scheduled release. Stored in UTC.
show_answers boolean No Show the correct answers with the result. Defaults to true.
pass_message string No HTML shown on a pass. Tags outside the question-text allow-list are stripped.
fail_message string No HTML shown on a fail. Same rules.
lock_policy string No When a finished attempt is locked for review: auto (when something awaits manual marking or the attempt limit is reached), cap_only (only when the attempt limit is reached), manual or never. Practice attempts never lock. Site default (auto).

The paper

Field Type Required Description
layout string No single_page or one_per_page. Site default (single_page).
shuffle_questions boolean No Defaults to false.
shuffle_options boolean No Defaults to false.
review_before_submit boolean No Site default (true).
allow_early_finish boolean No Site default (true).
require_answer string No For unanswered questions: off, warn or block. Site default (off).
fullscreen_mode string No off, offered or required. Site default (off).
allow_pause boolean No Site default (false).
max_pauses integer No 0 to 100. Defaults to 0.
max_pause_minutes integer No 0 to 1440. Defaults to 0.
track_integrity boolean No Site default (true).

Unfinished attempts

Field Type Required Description
auto_close_action string No What happens to an attempt closed for the person: submit or abandon. Site default (submit).
idle_timeout_minutes integer No Minutes without activity before an open attempt is closed, 0 to 525600. Site default (1440).
auto_close_held boolean No Whether an attempt an invigilator has put on hold may still be closed automatically. Defaults to false.
auto_close_time_spent string No Time recorded for an attempt closed automatically: capped (at most the time allowed) or wallclock. Site default (capped).
auto_close_notify string No auto, normal or silent (no email when an attempt is closed automatically). Site default (auto).

Sections, settings and custom fields

Field Type Required Description
sections object[] No The paper’s sections, in order. See below. Leave it out for an exam with no questions yet.
settings object No Extra per-exam flags, as a flat object of strings, numbers and booleans (or the same as a JSON string). Nested values are dropped, text values are cut to 500 characters, at most 50 keys are kept.
custom_fields object No PRO Custom field values, when the Custom Fields app is on.

Each section:

Field Type Description
title string Optional
description string Optional
section_type string fixed (the default) lists its questions; pool draws them at random by rules
points_per_question number Optional points for every question in the section
questions array fixed only. Question ids, or {"question_id": 41, "points": 2} objects to set the points for one question. Repeats and 0 are skipped. The ids are not checked for existence
rules object[] pool only. Each: subject_id (includes its child subjects), difficulty, question_type, tag_ids (array), all optional, plus draw_count (at least 1, default 1) and optional points_per_question

The settings keys lms_provider, lms_course_id, lms_step_id and lms_completes_course link the exam to an LMS course PRO, and are checked when the LMS Bridge app is on.

{
  "title": "Algebra Midterm",
  "description": "Linear equations and inequalities.",
  "intro": "<p>You have 45 minutes. Calculators are allowed.</p>",
  "subject_id": 12,
  "time_limit": 45,
  "max_attempts": 2,
  "cooldown_minutes": 60,
  "open_from": "2026-11-16 08:00:00",
  "open_until": "2026-11-20 18:00:00",
  "pass_mark": 60,
  "shuffle_questions": true,
  "access_type": "code",
  "access_code": "ALG-2026",
  "result_release": "after_close",
  "pass_message": "<p>Well done, you passed.</p>",
  "layout": "one_per_page",
  "sections": [
    {
      "title": "Part A",
      "section_type": "fixed",
      "questions": [41, { "question_id": 42, "points": 2 }]
    },
    {
      "title": "Part B",
      "section_type": "pool",
      "points_per_question": 1,
      "rules": [
        { "subject_id": 15, "question_type": "mcq_single", "draw_count": 5 }
      ]
    }
  ]
}

Responses

201 Created. data is the new exam, with its sections.

{
  "success": true,
  "data": {
    "id": 7,
    "title": "Algebra Midterm",
    "slug": "algebra-midterm",
    "description": "Linear equations and inequalities.",
    "intro": "<p>You have 45 minutes. Calculators are allowed.</p>",
    "subject_id": 12,
    "time_limit": 45,
    "max_attempts": 2,
    "cooldown_minutes": 60,
    "open_from": "2026-11-16 08:00:00",
    "open_until": "2026-11-20 18:00:00",
    "pass_mark": 60,
    "shuffle_questions": true,
    "shuffle_options": false,
    "access_type": "code",
    "access_level": null,
    "result_release": "after_close",
    "release_at": null,
    "show_answers": true,
    "pass_message": "<p>Well done, you passed.</p>",
    "fail_message": "",
    "lock_policy": "auto",
    "attempt_mode": "exam",
    "practice_reveal": "on_submit",
    "layout": "one_per_page",
    "review_before_submit": true,
    "allow_early_finish": true,
    "fullscreen_mode": "off",
    "require_answer": "off",
    "allow_pause": false,
    "max_pauses": 0,
    "max_pause_minutes": 0,
    "auto_close_action": "submit",
    "idle_timeout_minutes": 1440,
    "window_close_action": "close",
    "auto_close_held": false,
    "auto_close_time_spent": "capped",
    "auto_close_notify": "auto",
    "track_integrity": true,
    "certificate_template_id": 0,
    "settings": null,
    "custom_fields": null,
    "published": false,
    "created_at": "2026-11-12 09:30:00",
    "modified_at": "2026-11-12 09:30:00",
    "created_by": 1,
    "modified_by": 1,
    "deleted_at": null,
    "sections": [
      {
        "id": 21,
        "exam_id": 7,
        "title": "Part A",
        "description": "",
        "ordering": 1,
        "section_type": "fixed",
        "points_per_question": null,
        "questions": [
          { "id": 101, "exam_id": "7", "section_id": 21, "question_id": 41, "ordering": 1, "points": null },
          { "id": 102, "exam_id": "7", "section_id": 21, "question_id": 42, "ordering": 2, "points": 2 }
        ],
        "rules": []
      },
      {
        "id": 22,
        "exam_id": 7,
        "title": "Part B",
        "description": "",
        "ordering": 2,
        "section_type": "pool",
        "points_per_question": 1,
        "questions": [],
        "rules": [
          {
            "id": 9,
            "section_id": 22,
            "subject_id": 15,
            "difficulty": null,
            "question_type": "mcq_single",
            "draw_count": 5,
            "points_per_question": null,
            "tag_ids": []
          }
        ]
      }
    ],
    "has_access_code": true
  }
}
Field Type Meaning
data.id integer The new exam’s id
data.slug string The exam’s address on your site, made unique
data.access_level string|null null unless access_type is access_level
data.published boolean false unless you sent published
data.settings object|null The extra flags, null when none were sent
data.custom_fields object|null Custom field values PRO
data.sections[].section_type string fixed or pool
data.sections[].questions object[] Questions placed in a fixed section, in order. points is null when the question keeps its own points. exam_id arrives as a string here
data.sections[].rules object[] Draw rules of a pool section
data.has_access_code boolean Whether an access code is set. The code itself is never returned

Errors

Status Code When
403 plugixa_exam_forbidden published is true and the token lacks exams:publish, or the user the publish permission.
400 plugixa_exam_title_required title is missing or blank.
400 plugixa_exam_bad_window open_until is not after open_from.
400 plugixa_exam_lms_link_invalid PRO settings link to an LMS provider, course or step that is unknown, inactive or invalid.
500 plugixa_exam_insert_failed The exam could not be saved.

Plus the errors every endpoint can return.

Examples

curl -s -X POST "https://your-site.example/wp-json/plugixa-exam/v1/exams" \
  -H "Authorization: Bearer $PLUGIXA_EXAM_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Algebra Midterm","subject_id":12,"time_limit":45,"pass_mark":60,"access_type":"code","access_code":"ALG-2026","sections":[{"title":"Part A","questions":[41,{"question_id":42,"points":2}]}]}'
<?php
$ch = curl_init('https://your-site.example/wp-json/plugixa-exam/v1/exams');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . getenv('PLUGIXA_EXAM_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'title'       => 'Algebra Midterm',
        'subject_id'  => 12,
        'time_limit'  => 45,
        'pass_mark'   => 60,
        'access_type' => 'code',
        'access_code' => 'ALG-2026',
        'sections'    => [
            [
                'title'     => 'Part A',
                'questions' => [41, ['question_id' => 42, 'points' => 2]],
            ],
        ],
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
const response = await fetch('https://your-site.example/wp-json/plugixa-exam/v1/exams', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PLUGIXA_EXAM_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: 'Algebra Midterm',
    subject_id: 12,
    time_limit: 45,
    pass_mark: 60,
    access_type: 'code',
    access_code: 'ALG-2026',
    sections: [
      { title: 'Part A', questions: [41, { question_id: 42, points: 2 }] },
    ],
  }),
});
const { data } = await response.json();

Quick Links

Share