Skip to main content
Webhooks let your server react to course lifecycle events without polling the 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_secret of your choice (32+ random bytes, base64 or hex)
Self-serve webhook configuration is on the roadmap.

Event types

Payload shape

All course events share the same envelope: top-level metadata plus a nested data object carrying course fields.
data always includes course_id, title, status, created_at, and sandbox. Event-specific additions:
  • course.ready: adds module_count
  • course.failed: adds error_message
  • course.module_ready: adds module_index (0-based) and, when available, video_url (signed, 24-hour TTL)
  • quota.exceeded: adds module_count and overage_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 your webhook_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

Always verify the raw request body, not the parsed JSON. Different JSON serializers produce different byte sequences, which breaks the signature.

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/courses to 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-level id field (e.g. wh_1a2b3c4d5e6f7a8b) as a dedup key in your processing.

Sandbox webhooks

Sandbox runs (with sk_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.