Webhook Setup Guide
Webhook Setup Guide
Learn how to configure webhooks to receive real-time notifications from the SCORM API.
Table of Contents
- Overview
- What are Webhooks?
- Setting Up Webhooks
- Webhook Events
- Security
- Testing Webhooks
- Troubleshooting
Overview
Webhooks allow the SCORM API to send real-time notifications to your application when events occur, such as:
- Package processing completed
- Package processing failed
- Session completed
- Session progress updated
What are Webhooks?
Webhooks are HTTP callbacks that the SCORM API sends to your application when specific events occur. Instead of polling the API for updates, webhooks push notifications to your server.
Benefits
- Real-time Updates: Get notified immediately when events occur
- Reduced API Calls: No need to poll for status updates
- Better Performance: Lower latency than polling
- Event-Driven Architecture: Build reactive systems
Setting Up Webhooks
Step 1: Create a Webhook Endpoint
Create an HTTP endpoint in your application that can receive POST requests:
// Example: Next.js API route
// app/api/webhooks/scorm/route.ts
export async function POST(request: Request) {
const body = await request.json();
// Process webhook event
console.log('Webhook received:', body);
return new Response('OK', { status: 200 });
}
Step 2: Register Webhook with SCORM API
Via Dashboard
- Sign in to your SCORM API dashboard
- Navigate to Dashboard → Webhooks
- Click "Create Webhook"
- Enter your webhook URL
- Select event type(s)
- (Optional) Add a secret for signature verification
- Click "Create"
Via API
curl -X POST https://scorm-api.allurelms.com/api/v1/webhooks \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://your-app.com/api/webhooks/scorm",
"secret": "your-webhook-secret",
"event_type": "package.processing.completed"
}'
Response:
{
"id": "webhook_abc123",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://your-app.com/api/webhooks/scorm",
"event_type": "package.processing.completed",
"is_active": true,
"created_at": "2025-01-15T10:30:00.000Z"
}
Step 3: Verify Webhook Endpoint
Your endpoint should:
- Accept POST requests
- Return 200 status code for successful processing
- Respond within 30 seconds
- Handle errors gracefully
Webhook Events
Available Event Types
| Event Type | Description | When Triggered |
|---|---|---|
package.processing.completed | Package processing finished | After package is successfully processed |
package.processing.failed | Package processing failed | When package processing encounters an error |
session.created | New session created | When a learner starts a course |
session.completed | Session completed | When a learner completes a course |
session.progress | Session progress updated | When CMI data is updated (frequent) |
Event Payload Structure
All webhook events follow this structure:
{
"event": "package.processing.completed",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"package_id": "pkg_abc123",
"title": "Introduction to Safety Training",
"version": "1.2",
"revision": 1
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Package Processing Completed
Triggered when a package finishes processing successfully.
Payload:
{
"event": "package.processing.completed",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"package_id": "pkg_abc123",
"title": "Introduction to Safety Training",
"version": "1.2",
"scorm_version": "1.2",
"revision": 1,
"launch_url": "index.html",
"file_size_bytes": 5242880
},
"timestamp": "2025-01-15T10:30:00.000Z"
}
Package Processing Failed
Triggered when package processing fails.
Payload:
{
"event": "package.processing.failed",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"package_id": "pkg_abc123",
"error": "Invalid SCORM manifest",
"error_code": "INVALID_MANIFEST"
},
"timestamp": "2025-01-15T10:30:00.000Z"
}
Session Created
Triggered when a new learning session is created.
Payload:
{
"event": "session.created",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"session_id": "session_abc123",
"package_id": "pkg_abc123",
"user_id": "user_xyz789"
},
"timestamp": "2025-01-15T10:30:00.000Z"
}
Session Completed
Triggered when a learner completes a course.
Payload:
{
"event": "session.completed",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"session_id": "session_abc123",
"package_id": "pkg_abc123",
"user_id": "user_xyz789",
"completion_status": "completed",
"success_status": "passed",
"score": {
"scaled": 0.85,
"raw": 85,
"max": 100
},
"time_spent_seconds": 3600
},
"timestamp": "2025-01-15T10:30:00.000Z"
}
Session Progress
Triggered when session CMI data is updated (can be frequent).
Payload:
{
"event": "session.progress",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"session_id": "session_abc123",
"package_id": "pkg_abc123",
"user_id": "user_xyz789",
"completion_status": "incomplete",
"score": {
"scaled": 0.65,
"raw": 65
},
"time_spent_seconds": 1800
},
"timestamp": "2025-01-15T10:30:00.000Z"
}
Security
Signature Verification
Always verify webhook signatures to ensure requests come from the SCORM API.
How It Works
- SCORM API creates HMAC-SHA256 signature of request body using your webhook secret
- Signature is sent in
X-Allure-Signatureheader - Your endpoint verifies the signature matches
Implementation
import crypto from 'crypto';
export async function POST(request: Request) {
const signature = request.headers.get('X-Allure-Signature');
const algorithm = request.headers.get('X-Allure-Signature-Algorithm') || 'sha256';
const body = await request.text();
// Get your webhook secret (from environment or database)
const secret = process.env.WEBHOOK_SECRET!;
// Compute expected signature
const expectedSignature = crypto
.createHmac(algorithm, secret)
.update(body)
.digest('hex');
// Verify signature
if (signature !== expectedSignature) {
return new Response('Invalid signature', { status: 401 });
}
// Process webhook
const event = JSON.parse(body);
await handleWebhookEvent(event);
return new Response('OK', { status: 200 });
}
Python Example
import hmac
import hashlib
import json
def verify_webhook_signature(signature, body, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
body.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
@app.route('/webhooks/scorm', methods=['POST'])
def webhook_handler():
signature = request.headers.get('X-Allure-Signature')
body = request.get_data(as_text=True)
secret = os.getenv('WEBHOOK_SECRET')
if not verify_webhook_signature(signature, body, secret):
return 'Invalid signature', 401
event = json.loads(body)
# Process event
return 'OK', 200
Best Practices
- Always Verify Signatures: Never process webhooks without signature verification
- Use HTTPS: Always use HTTPS for webhook endpoints
- Store Secrets Securely: Never commit webhook secrets to version control
- Idempotency: Handle duplicate webhook deliveries gracefully
- Rate Limiting: Implement rate limiting on your webhook endpoint
Testing Webhooks
Using ngrok (Local Development)
- Install ngrok:
npm install -g ngrok - Start your local server:
npm run dev - Expose with ngrok:
ngrok http 3000 - Use ngrok URL as webhook URL:
https://abc123.ngrok.io/api/webhooks/scorm
Manual Testing
# Test webhook endpoint directly
curl -X POST https://your-app.com/api/webhooks/scorm \
-H "Content-Type: application/json" \
-H "X-Allure-Signature: test-signature" \
-d '{
"event": "package.processing.completed",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"package_id": "pkg_abc123",
"title": "Test Package"
},
"timestamp": "2025-01-15T10:30:00.000Z"
}'
Viewing Delivery History
Check webhook delivery status in the dashboard:
curl -X GET "https://scorm-api.allurelms.com/api/customer/webhooks/webhook_abc123/deliveries" \
-H "X-API-Key: your-api-key"
Troubleshooting
Webhook Not Receiving Events
Check:
- Webhook is active in dashboard
- Webhook URL is accessible (not behind firewall)
- Webhook endpoint returns 200 status
- Event type matches subscribed events
Signature Verification Fails
Check:
- Webhook secret matches in both systems
- Request body is read as raw text (not parsed JSON)
- Signature algorithm matches (sha256)
- No body modifications before verification
Delivery Failures
Common Causes:
- Endpoint timeout (>30 seconds)
- Endpoint returns non-200 status
- Network connectivity issues
- SSL certificate problems
Solutions:
- Process webhooks asynchronously
- Return 200 immediately, process in background
- Check delivery history for error details
- Implement retry logic on your side
Related Documentation
- Webhook Events Reference - Complete event reference
- Webhook Security - Security best practices
- API Reference - Complete API documentation
Last Updated: 2025-01-15