Webhooks
Webhooks deliver the result of asynchronous work (quiz, exam, flashcard generation; marking) to your server the moment it finishes — no polling required. Configure a URL per event family in the admin console; we POST a signed JSON body to it.
Event families
| Family | Configured URL key | Events |
|---|---|---|
| Quiz | quiz |
quiz.completed, quiz.failed |
| Marking | marking |
marking.completed, marking.failed |
| Exam | exam |
exam.completed, exam.failed |
| Study | study |
study.flashcards.completed, study.flashcards.failed |
| NAPLAN | naplan |
naplan.completed, naplan.failed |
| Assessment | assessment |
assessment.review_ready, assessment.published, assessment.extraction_failed |
| — | default |
Fallback when no specific URL is set |
If a marking URL is configured, marking runs asynchronously and returns 202; without one, essay marking runs synchronously and returns the full result inline.
Signature verification
Each request carries X-IntuAI-Timestamp and X-IntuAI-Signature. Recompute the signature and compare it constant-time:
Your signing secret is shown (and rotatable) in the admin console.
Example payloads
Addressing a marking afterwards
Marking reads are scoped to the learner the submission was created with, so a
request only finds a submission when it carries the same user_id. You never
have to guess which one: every marking event carries the owning learner as
user_id, and that is exactly the value to send back. Store it alongside
submission_id when the marking is announced and address it directly ever
after. A submission created without a user_id reports null, and is reached
by omitting the parameter.
Assessment events carry no user_id: a paper belongs to your account, not to
one student.
Retries
Deliveries that don’t get a 2xx are retried with exponential backoff, up to 3 attempts. Respond 200 quickly and process asynchronously on your side. Delivery URLs are validated against SSRF (private/internal addresses are refused).