Webhooks
Webhooks are available on the Enterprise plan.
Webhooks let you receive an HTTP POST request to your own server whenever a specific event occurs in the platform. Use them to sync data with external systems such as HubSpot, Slack, or your HRMS — without polling the API.
Available events
| Event | Triggered when |
|---|---|
user.enrolled | A student is enrolled in a course |
user.completed | A student completes a course (100% progress) |
certificate.issued | A certificate is generated for a student |
user.invited | An admin sends an invitation email to a new user |
user.registered | A new user completes registration |
plan.upgraded | Your organization upgrades to a higher plan |
batch.student_added | A student is added to a batch |
quiz.passed | A student passes a quiz |
quiz.failed | A student fails a quiz |
Add an endpoint
- Go to Settings → Webhooks
- Click Add Endpoint
- Enter the URL of your server endpoint (must be HTTPS)
- Select the events you want to receive
- Click Save
There's currently no automatic test ping sent when you save an endpoint — trigger a real event (e.g. enroll a test student) and check the delivery logs to confirm it's reachable.
Payload format
Each webhook is an HTTP POST with a JSON body:
{
"id": "a1b2c3d4-...",
"event": "user.enrolled",
"createdAt": "2026-05-09T10:34:00Z",
"data": {
"student_id": "usr_abc123",
"student_email": "jane@example.com",
"student_name": "Jane Smith",
"course_id": "crs_xyz789",
"course_title": "Onboarding 101",
"enrolled_at": "2026-05-09T10:34:00Z"
}
}
The data object contains fields relevant to the event type. id uniquely identifies this delivery attempt (also sent as the X-LMS-Delivery header — useful for de-duplication). All timestamps are ISO 8601 in UTC.
Two more headers are sent alongside the body: X-LMS-Event (the event name, same as the event field) and X-LMS-Signature (see below).
Verifying the signature
X-LMS-Signature is an HMAC-SHA256 signature of the raw request body, signed with your endpoint secret, in the form sha256=<hex digest> — note the sha256= prefix.
To verify on your server:
- Copy the secret shown on the endpoint detail page in Settings
- Compute
HMAC-SHA256(secret, rawRequestBody) - Prefix your result with
sha256=and compare it to theX-LMS-Signatureheader - If they match, the request is genuine
Example in Node.js:
const crypto = require('crypto');
function verifySignature(secret, rawBody, headerSignature) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(headerSignature)
);
}
Always verify the signature before processing a webhook. Reject requests that fail signature verification.
Delivery logs and retry
The platform logs every delivery attempt. To view logs:
- Go to Settings → Webhooks → [Your endpoint]
- Click the Delivery Logs tab
Each log entry shows the event, timestamp, HTTP response code your server returned, and delivery status.
Retry policy: Each delivery attempt times out after 10 seconds. If your server returns a non-2xx response or times out, the platform retries with exponential backoff — up to 3 attempts total, spaced 2 seconds and then 8 seconds apart. If all 3 fail, the delivery is marked as failed; there's no further retry after that.
Recommended use cases
- HubSpot / CRM — create a contact activity when
user.enrolledoruser.completedfires - Slack — post a message to a channel when
certificate.issuedfires - HRMS / HR systems — sync course completions to your training records system
- Zapier — use webhooks as a trigger in a Zap to connect to 5,000+ apps