Webhook Configuration
Receive real-time event notifications from Thought Industries
Webhooks let your application react to platform events in real time — enrollments, course completions, purchases, and more. Instead of polling APIs, you configure an HTTPS endpoint and Thought Industries will POST event payloads to it as they happen.
Prerequisites
A publicly accessible HTTPS endpoint
Ability to verify HMAC-SHA256 signatures
Admin access to Thought Industries webhook settings
A server that can respond within 5 seconds
Create a Webhook Endpoint
You can register webhooks via the admin panel or programmatically via the REST API:
POST /incoming/v2/webhooks
Authorization: Bearer {API_KEY}
Content-Type: application/json
{
"url": "https://your-app.com/webhooks/ti",
"events": [
"enrollment.created",
"course.completed",
"order.completed"
],
"secret": "whsec_your_webhook_secret",
"active": true
}Verify Signatures
Every webhook request includes an X-TI-Signature header. Always verify it before processing the payload to prevent replay attacks and spoofing:
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
);
}
// Express middleware example
app.post('/webhooks/ti', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-ti-signature'];
if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process event...
res.status(200).send('OK');
});Use crypto.timingSafeEqual to prevent timing attacks. Never use simple string comparison for signature validation.
Handle Retries
If your endpoint returns a non-2xx status or times out (30s), the platform retries with exponential backoff over 24 hours:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 24 hours |
After 5 failed attempts, the event is marked undeliverable. Consistently failing endpoints may be automatically disabled. Return 200 immediately and process asynchronously.
Event Types
Common events you can subscribe to. See the Webhooks documentation for the full event catalog and payload schemas.
enrollment.createdLearner enrolled in contentcourse.completedLearner finished all required itemscourse.progress_updatedProgress percentage changedcertificate.issuedCertificate generated on completionuser.createdNew account registeredorder.completedPurchase transaction finalizedBest Practices
Return 200 quickly
Respond within 5 seconds. Use a message queue for heavy processing.
Handle duplicates
Events may be delivered more than once. Use idempotency keys based on event ID + timestamp.
Use HTTPS only
The platform refuses to deliver to HTTP endpoints. TLS 1.2 or higher is required.
Monitor delivery logs
Check the admin panel for failed deliveries and retry status.