Developers
Webhooks
Signed, retried, logged and replayable from the interface — because a webhook you cannot inspect is one you cannot debug.

Verify the signature before you parse
Every delivery carries X-Algoryq-Signature, an HMAC-SHA256 over the raw request body using the endpoint's secret. Compute it over the bytes you received, not a re-serialised object — a JSON round-trip can reorder keys and change whitespace, and then the signature never matches.
Compare in constant time. A naive string comparison leaks timing information, which is a small thing until somebody is patient.
X-Algoryq-Delivery is a unique id for the attempt. Store it and ignore a repeat: retries are at-least-once by design, so your handler must be idempotent.
Retries
A non-2xx response or a timeout is retried with backoff. Every attempt is written to a delivery log with its status code and response body, visible in the product and replayable by hand. If your endpoint was down for an hour, you can see what was missed and re-send it rather than reconciling by guesswork.
Ordering
Not guaranteed. Events are delivered as they happen and retries can arrive out of order, so treat each as a fact about a point in time and re-read the resource if current state matters. Anything else is a race you eventually lose.
What we will not do
- We do not follow redirects.
- We do not send to plain HTTP.
- We do not include personal data beyond identifiers and the minimum that makes the event useful. Fetch the resource with your key if you need the rest.
The events
Every mutation emits a domain event internally; the audit log and the notification fan-out both read them. These 10 are the ones exposed over webhooks today.
| Event | Fires when | Module |
|---|---|---|
enrollment.created | A learner is enrolled on a course | learn |
enrollment.completed | A learner finishes a course | learn |
lead.created | An enquiry arrives, including from web-to-lead | crm |
lead.stage_changed | An enquiry moves column | crm |
application.decided | An application is accepted or rejected | crm |
invoice.issued | An invoice is issued to a learner | finance |
payment.recorded | A payment is recorded against an invoice | finance |
attempt.submitted | A learner submits an assessment attempt | assess |
certificate.issued | A certificate is issued | cert |
certificate.revoked | A certificate is withdrawn | cert |
The rest of the developer surface
Authentication, the response envelope, the public endpoints and their threat model, and how to run the platform yourself.
Or open the sandbox (opens in a new tab) and click around first. No form.