Skip to main content
Every webhook management request requires a Bearer API key.

Webhook endpoints

Available events:
  • exam_participant.registered — a participant was registered for an exam
  • exam_participant.unregistered — a participant’s registration was cancelled
  • exam_result.completed — a participant finished a test
  • exam_result.scored — a test score was published or changed
  • question_import.completed — a question package import finished
  • question_import.failed — a question package import failed
Webhooks are sent only while the API Integration add-on is active and the endpoint is enabled.

When events are sent

  • exam_participant.registered is sent for registrations made through the API and in the admin panel. Participants who register themselves through the exam registration page don’t trigger this event.
  • exam_participant.unregistered is sent when a registration is cancelled through the API.
  • exam_result.completed and exam_result.scored come from a scan of exam results that runs every minute, so an event may arrive about 1–2 minutes after the participant finishes.
  • exam_result.completed may carry score: null for tests scored with IRT or manually. exam_result.scored follows once the score has been calculated.
  • exam_result.scored is sent again every time score or meta_score changes, for example after an IRT recalculation or a score recalculation. The same score is never sent twice.
  • question_import.completed and question_import.failed are sent when a question package import through the Question Import API finishes or fails.
  • Events are not guaranteed to arrive in order. Use updated_at from the Exam Results API to determine the latest data, and resync regularly with GET /exam-results?updated_since=... so that missed events are still handled.

Parameters

This endpoint has no parameters.

Example request

Example response

Up to five webhook endpoints per project; a sixth endpoint is rejected with status 409. The signing secret is returned only when the endpoint is created or the secret is rotated.

Parameters

Example request

Example response

This endpoint also accepts the PUT method. A new secret is returned only when rotate_secret is true. Sending is_active: true also re-enables an endpoint that the system disabled automatically, and resets consecutive_failures to 0.

Parameters

Example request

Example response

Parameters

Example request

Example response

Parameters

Example request

Example response

If event is not sent or not recognised, the default event is exam_result.completed. A test delivery uses the selected event name and the same signature as a real delivery, but data contains a test message: { "message": "...", "sent_at": "..." }. An inactive endpoint is rejected with status 409.

Parameters

Example request

Example response

Webhook payloads and signatures

Every webhook is sent as a POST with a JSON body containing event, created_at (when the event was queued) and data. The same body is resent unchanged on every retry.

Headers

exam_result.completed and exam_result.scored payload

Both events use the same data structure. The contents of meta_score for each scoring method are described in the meta_score structure section of the Exam Results API.

exam_participant.registered payload

exam_participant.unregistered payload

Verify the signature

v1 is the HMAC-SHA256 of <t>.<raw body> using the endpoint’s signing secret. The t value is regenerated on every delivery attempt. Reject requests whose signature doesn’t match or whose t differs from your server time by more than 300 seconds.

Retries

  • Respond to the webhook with a 2xx status within 10 seconds. Store the event first, then process it in the background.
  • Non-2xx responses, timeouts and connection failures are retried up to 4 attempts in total, with delays of 1 minute, 5 minutes, then 30 minutes. If the last attempt fails, the delivery status becomes failed.
  • An endpoint that fails 10 times in a row is disabled automatically (is_disabled_by_system: true), and the project owner is notified in the admin panel. Once the endpoint is fixed, re-enable it with PATCH /webhooks/{id} containing is_active: true.
  • Deliveries that are already failed are not resent. Use GET /exam-results?updated_since=... to fetch the results you missed.