Worked example and advice
A worked example
A nightly job that sends finished results to another system and keeps a subject's questions in step with a source of truth. Each step is one request.
TOKEN="nxk_your_token"
API="https://your-site.example/api/index.php/v1/nextexams"
# 1. Which exams are there?
curl -s "$API/exams?limit=100" -H "Authorization: Bearer $TOKEN"
# 2. Graded attempts at exam 7, newest first, 50 at a time.
curl -s "$API/attempts?exam_id=7&status=graded&limit=50&offset=0" \
-H "Authorization: Bearer $TOKEN"
# 3. One attempt in full: every response and how it was graded.
curl -s "$API/attempts/263" -H "Authorization: Bearer $TOKEN"
# 4. How did each question perform?
curl -s "$API/reports/7/items" -H "Authorization: Bearer $TOKEN"
# 5. Fix a typo in a question: read it, change it, send it all back.
curl -s "$API/questions/42" -H "Authorization: Bearer $TOKEN" \
| jq '.data | .stem = "<p>What is 2 + 2?</p>"' \
| curl -s -X PUT "$API/questions/42" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data-binary @-
The token for this job needs exams:read, attempts:read, reports:read, questions:read and questions:write, and nothing else.
Practical advice
- Page through lists. Read
meta.total, then stepoffsetbylimit. Do not raiselimitto fetch everything in one request on a large site. - Prefer webhooks to polling for new results.
attempt.gradedtells you the moment a result is final; then fetch that one attempt. See Setting up webhooks. - Wait for
is_graded. An attempt with an essay issubmitteduntil a person grades it, and its score is not final until then. - Keep option ids. When you replace a question, send each option's
idback. That is what keeps answers already given attached to the right option. - Send
expected_versionwhen more than one person or program may edit the same question, and handle409 STALEby reading again. - Expect
409 ANSWERED_NEEDS_VERSIONonce a question has been answered, and decide in your integration whether to create a new version or leave the question alone. - Ignore fields you do not recognise. New ones may appear in later releases.
- Match on
code, nottitle.
What the API is not
- Not a way to take exams. There is no endpoint that starts or answers an attempt. Learners sit exams on the site, or from an LMS through LTI 1.3.
- Not an exam builder. Exams are read, published and deleted here; their structure is built in the Exam Studio.
- Not a user directory. Users and groups are Joomla's, and Next Exams does not expose them.
- Not a configuration API. Settings, roles, email templates and webhooks are managed in the admin screens only.
Security notes
- One token per integration. A shared token cannot be revoked without breaking everything that uses it.
- Grant the fewest scopes that work. A reporting job needs
reports:readand nothing more. - Make the token's owner a dedicated account with a Next Exams role limited to what the integration does. The role is the ceiling, whatever the scopes say.
- Set an expiry on anything temporary, such as a migration script.
- HTTPS only. A bearer token sent over plain HTTP can be read in transit.
- Revoke when people leave, as with any credential. A token stops working when its owner is blocked.
- The emergency stop is the API Tokens app in the App Manager: switching it off refuses every token at once.