Next Exams REST API
The integration surface for Next Exams: subjects, tags and questions you can create and edit, exams you can read, publish and delete, attempts and per-exam reports you can read — enough to sync a question bank from another system, feed a gradebook or a BI tool, or automate publishing.
Authentication. Every request carries a Next Exams API token, created under
Next Exams → API tokens. A token is shown once and stored only as a hash. It
acts as the user who created it, and is limited three ways at once: by the
scopes it was given, by that user's Next Exams role, and by Joomla's
core.manage permission on Next Exams. A scope a token lacks is refused with
403 MISSING_SCOPE, whatever the role allows.
It is off when the API Tokens app is off. Next Exams → App Manager →
API tokens is the kill switch: with it off, every request answers
403 API_DISABLED. Apps that are switched off answer 403 APP_DISABLED.
Responses are projections, not table rows: each resource returns exactly the fields documented here, with real booleans and numbers, and dates as ISO 8601 in UTC. Secrets the administrator screens carry — a guest's result token, an exam's access code — are never returned.
Base URL
{protocol}://{host}{basePath}/api/index.php
| Variable | Meaning | Example |
|---|---|---|
{protocol} |
Use http only for local development. | https |
{host} |
The host your Joomla site runs on. | your-site.example |
{basePath} |
Empty when Joomla is installed at the domain root. Otherwise the subfolder it is installed in, with a leading slash and no trailing slash — for example /exams. | (empty) |
Authentication
Authorization: Bearer <your-api-token>
X-NextExams-Token is accepted as an alternative — The same token in a custom header. Some Apache/PHP setups strip the
Authorization header before PHP sees it; a custom X- header always
arrives. Use this when bearer requests answer 401 MISSING_TOKEN.
Authorization: Bearer nxk_… — a token from Next Exams → API tokens.
Endpoints
| Method | Operation | Purpose | Group |
|---|---|---|---|
GET |
/v1/nextexams/subjects |
List subjects | Subjects |
POST |
/v1/nextexams/subjects |
Create a subject | Subjects |
GET |
/v1/nextexams/subjects/{id} |
Get a subject | Subjects |
PATCH |
/v1/nextexams/subjects/{id} |
Update a subject | Subjects |
DELETE |
/v1/nextexams/subjects/{id} |
Delete a subject | Subjects |
POST |
/v1/nextexams/subjects/{id}/status |
Publish or unpublish a subject | Subjects |
GET |
/v1/nextexams/tags |
List tags | Tags |
POST |
/v1/nextexams/tags |
Create a tag | Tags |
GET |
/v1/nextexams/tags/{id} |
Get a tag | Tags |
PATCH |
/v1/nextexams/tags/{id} |
Update a tag | Tags |
DELETE |
/v1/nextexams/tags/{id} |
Delete a tag | Tags |
POST |
/v1/nextexams/tags/{id}/status |
Publish or unpublish a tag | Tags |
GET |
/v1/nextexams/questions |
List bank questions | Questions |
POST |
/v1/nextexams/questions |
Create a question | Questions |
GET |
/v1/nextexams/questions/{id} |
Get a question | Questions |
PUT |
/v1/nextexams/questions/{id} |
Replace a question | Questions |
DELETE |
/v1/nextexams/questions/{id} |
Delete a question | Questions |
POST |
/v1/nextexams/questions/{id}/status |
Publish or unpublish a question | Questions |
GET |
/v1/nextexams/questions/{id}/versions |
List a question's versions | Questions |
GET |
/v1/nextexams/question-types |
List question types | Questions |
GET |
/v1/nextexams/exams |
List exams | Exams |
GET |
/v1/nextexams/exams/{id} |
Get an exam | Exams |
DELETE |
/v1/nextexams/exams/{id} |
Delete an exam | Exams |
POST |
/v1/nextexams/exams/{id}/status |
Publish or unpublish an exam | Exams |
GET |
/v1/nextexams/attempts |
List attempts | Attempts |
GET |
/v1/nextexams/attempts/{id} |
Get an attempt | Attempts |
GET |
/v1/nextexams/reports/{exam_id}/overview |
Exam overview | Reports |
GET |
/v1/nextexams/reports/{exam_id}/items |
Item analysis | Reports |
GET |
/v1/nextexams/reports/{exam_id}/students |
Per-student summary | Reports |
Webhook events
Outbound events. When an exam event happens, Next Exams sends an HTTP POST to each endpoint subscribed to it, so another system can react without polling.
A webhook says something happened; the REST API reads the full record. A gradebook typically listens for attempt.graded, then fetches the attempt if it needs every response.
| Event | When |
|---|---|
attempt.submitted |
An attempt is handed in |
attempt.graded |
An attempt's grade is final |
certificate.issued |
A certificate is issued |
ping |
You press Send test |
Errors
| Status | Code | When |
|---|---|---|
401 |
INVALID_TOKEN |
No token (MISSING_TOKEN), or one that is wrong, expired, revoked, or whose owner can no longer sign in (INVALID_TOKEN). |
403 |
MISSING_SCOPE |
The token is valid but this request is not allowed, and code says why: MISSING_SCOPE (the token lacks the scope), FORBIDDEN (the owner's role does not allow it), ACCESS_DENIED (the owner cannot manage Next Exams), API_DISABLED (the API Tokens app is off), APP_DISABLED (the feature's app is off — meta.app names it), ACCOUNT_UNUSABLE (the owner is blocked or must reset their password), DEMO_LOCKED (a demo site). |
400 |
BAD_REQUEST |
The body failed validation, or is not a JSON object (INVALID_JSON). |
404 |
NOT_FOUND |
No record has this id. |
409 |
The save or delete would break something that depends on the record: QUESTION_IN_USE, ANSWERED_NEEDS_VERSION, TYPE_LOCKED, STALE. meta carries the details (for example the exams that use a question). |
|
422 |
The request is well formed but would lose data (OPTIONS_REQUIRED). |
See also
- Getting Started guide — enabling the API, screenshots and a worked end-to-end example