PHP2Shell: Is Your Joomla Site Safe? What to Do Today Introducing Next Boards: Kanban project and task boards for Joomla Next Exams 6.2.0: Exam Studio, six visual question types, exam embeds and six new languages Building the Future of Joomla Extensions
NextSoftware

Endpoint details

Every endpoint, the scope it needs, and what to know before calling it. The API Reference section has the full field-by-field description of each one, generated from the OpenAPI document.

All paths below follow https://your-site.example/api/index.php/v1/nextexams.


Endpoints

Method Path Scope Does
GET /subjects subjects:read List subjects
POST /subjects subjects:write Create a subject
GET /subjects/{id} subjects:read Get a subject
PATCH /subjects/{id} subjects:write Update a subject
DELETE /subjects/{id} subjects:delete Delete a subject
POST /subjects/{id}/status subjects:write Publish or unpublish
GET /tags questions:read List tags
POST /tags questions:write Create a tag
GET /tags/{id} questions:read Get a tag
PATCH /tags/{id} questions:write Update a tag
DELETE /tags/{id} questions:delete Delete a tag
POST /tags/{id}/status questions:write Publish or unpublish
GET /questions questions:read List bank questions
POST /questions questions:write Create a question
GET /questions/{id} questions:read Get a question with its options
PUT /questions/{id} questions:write Replace a question
DELETE /questions/{id} questions:delete Delete (or retire) a question
POST /questions/{id}/status questions:write Publish or unpublish
GET /questions/{id}/versions questions:read A question's saved versions
GET /question-types lookups:read The question types this site offers
GET /exams exams:read List exams
GET /exams/{id} exams:read Get an exam with its structure
DELETE /exams/{id} exams:delete Delete an exam
POST /exams/{id}/status exams:publish Publish or unpublish
GET /attempts attempts:read List attempts
GET /attempts/{id} attempts:read Get an attempt with every response
GET /reports/{exam_id}/overview reports:read Pass rate and score distribution
GET /reports/{exam_id}/items reports:read Item analysis
GET /reports/{exam_id}/students reports:read One row per examinee

The scope is the first check. The token owner's role is checked as well: listing attempts also needs the role's attempts.view, deleting an exam its exams.delete, and so on.


Subjects

Subjects form a tree. parent_id is 0 at the top level. path is the ids from the root down, joined by /, and level counts from 1.

Moving a subject (a PATCH with a new parent_id) rebuilds the path of its whole subtree. A move under one of its own descendants is refused.

curl -X POST https://your-site.example/api/index.php/v1/nextexams/subjects \
  -H "Authorization: Bearer nxk_your_token" \
  -H "Content-Type: application/json" \
  -d '{"title": "Algebra", "parent_id": 0, "code": "MATH-ALG"}'
{ "data": { "id": 42 } }

Questions

Lists show the bank

GET /questions lists bank questions. Two kinds are left out:

  • Questions private to one exam, made in the Exam Studio with Keep in bank off. They are part of that exam and appear in its structure.
  • Retired versions, kept only so old attempts can still be read. owner_exam_id is -1 on these.

GET /questions/{id} reads any question by id, whichever kind it is.

Where the answer lives

Question types The answer is in
Multiple choice, true/false, image choice, ordering options: each option's is_correct (and its order, for ordering)
Matching, EMQ options, with each item's partner in match_key
Short answer answer_key: accepted (a list), plus case_insensitive, trim, numeric / tolerance, use_regex
Essay Graded by a person. answer_key holds word limits and grading notes
Cloze, range, hotspot, image marking, graph, puzzle answer_key, in the type's own shape

The surest way to learn a type's shape is to build one such question in the editor and read it back with GET /questions/{id}. That body is exactly what POST and PUT accept.

GET /question-types lists every question_type value, with its label in the site language. The advanced and visual types can be switched off in the App Manager; creating a new question of a switched-off type is then refused, while existing ones keep working.

Creating one

curl -X POST https://your-site.example/api/index.php/v1/nextexams/questions \
  -H "Authorization: Bearer nxk_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Two plus two",
    "question_type": "mcq_single",
    "stem": "<p>What is 2 + 2?</p>",
    "default_points": 1,
    "difficulty": 1,
    "tags": ["Arithmetic"],
    "options": [
      { "option_text": "3", "is_correct": false },
      { "option_text": "4", "is_correct": true }
    ]
  }'

tags takes tag ids, tag titles, or {id, title} objects. A title no tag has yet creates the tag.

Replacing one

Read it, change it, send the whole thing back. See Create, update and replace for why questions are replaced rather than patched, and Questions that have been answered for what Next Exams protects once attempts exist.

curl https://your-site.example/api/index.php/v1/nextexams/questions/42 \
  -H "Authorization: Bearer nxk_your_token" > q.json

# edit q.json: data.title, data.stem, …  then send data back
jq '.data' q.json | curl -X PUT https://your-site.example/api/index.php/v1/nextexams/questions/42 \
  -H "Authorization: Bearer nxk_your_token" \
  -H "Content-Type: application/json" \
  --data-binary @-

Deleting one

The question is Result
Used by an exam Refused, 409 QUESTION_IN_USE, with the exams in meta
Only referenced by past attempts Retired, not deleted, so those attempts keep their record. Answers 204
Unused Deleted. Answers 204

Exams

GET /exams/{id} returns the exam's settings and its structure:

  • sections, each one either fixed (the questions placed in it, in questions) or pool (drawn at random by its pool_rules).
  • in_progress_attempts: how many people are sitting it right now.

Exams are built in the Exam Studio. Through the API you can read them, publish and unpublish them, and delete them.


Attempts

GET /attempts lists attempts newest first, and filters by exam_id and status:

Status Meaning
in_progress Being sat now (a paused attempt is still in_progress)
submitted Handed in; a question still waits for a person to grade it
graded Fully graded. score, percent and passed are final
locked_review Handed in and locked by the exam's lock policy: the examinee cannot start another attempt until it is released
abandoned Closed without being handed in

GET /attempts/{id} adds every response — what was answered, whether it was right, the points, and whether a person or Next Exams graded it — and the attempt's integrity signals.

Integrity signals are detection only. Focus losses, pastes, tab switches and fullscreen exits are counted, never judged. Treat them as a reason to look, not as a verdict.

A guest's attempt has user_id: null and carries the name and email the guest gave, if the exam asked for them.


Reports

All three take the exam's id in the path, and count graded attempts.

Endpoint Returns
/reports/{exam_id}/overview Attempts, pass count and rate, mean, median, minimum, maximum and standard deviation of the percent, average time, and a histogram in 10-percent bands
/reports/{exam_id}/items Per question: responses, difficulty (share answered correctly, 0 to 1), the same as a percent, discrimination (item-total Pearson correlation, −1 to 1), average time
/reports/{exam_id}/students Per examinee: attempts, best and average percent, passing attempts. Guests are grouped into one row with no user id

A question with low or negative discrimination is one that strong candidates get wrong as often as weak ones, which usually means it is ambiguous or mis-keyed.

Reports need the Analytics app. With it off they answer 403 APP_DISABLED.


See also

All Extensions