status endpoint. Configure one webhook URL per account.
Setup
Webhook URL and secret are configured per account. Contact your account manager with:- The HTTPS URL to deliver events to
- A
webhook_secretof your choice (32+ random bytes, base64 or hex)
Event types
Payload shape
All course events share the same envelope: top-level metadata plus a nesteddata object carrying course fields.
data always includes course_id, title, status, created_at, and sandbox. Event-specific additions:
course.ready: addsmodule_countcourse.failed: addserror_messagecourse.module_ready: addsmodule_index(0-based) and, when available,video_url(signed, 24-hour TTL)quota.exceeded: addsmodule_countandoverage_hours
language and external_ref are NOT included in the payload. If you need them, fetch the course with GET /api/v1/courses/{course_id}.
Signing and verification
Every delivery is signed with HMAC-SHA256 using yourwebhook_secret. Two headers are included:
The signed content is
<timestamp>.<raw_request_body>. Recompute the HMAC and compare in constant time.
Python verification
Node.js verification
Retry behaviour
Deliveries that fail to reach your endpoint are not automatically retried in the current API version. If your endpoint is down, you will miss events. Mitigations:- Make your webhook handler highly available (queue + background processor pattern).
- Implement a periodic reconciliation job that calls
GET /api/v1/coursesto catch missed events. - Automatic retries with exponential backoff are on the roadmap.
Idempotency
Your handler must be idempotent. Even with retries off, network reasons may cause duplicate deliveries. Use the top-levelid field (e.g. wh_1a2b3c4d5e6f7a8b) as a dedup key in your processing.
Sandbox webhooks
Sandbox runs (withsk_test_ keys) fire webhook events with "sandbox": true in the data envelope. Branch on this field if your downstream effects (e.g. emailing the customer) should not run in sandbox.