Webhook Setup Guide

Webhook Setup Guide

Learn how to configure webhooks to receive real-time notifications from the SCORM API.

Table of Contents

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

  1. Sign in to your SCORM API dashboard
  2. Navigate to DashboardWebhooks
  3. Click "Create Webhook"
  4. Enter your webhook URL
  5. Select event type(s)
  6. (Optional) Add a secret for signature verification
  7. 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 TypeDescriptionWhen Triggered
package.processing.completedPackage processing finishedAfter package is successfully processed
package.processing.failedPackage processing failedWhen package processing encounters an error
session.createdNew session createdWhen a learner starts a course
session.completedSession completedWhen a learner completes a course
session.progressSession progress updatedWhen 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

  1. SCORM API creates HMAC-SHA256 signature of request body using your webhook secret
  2. Signature is sent in X-Allure-Signature header
  3. 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

  1. Always Verify Signatures: Never process webhooks without signature verification
  2. Use HTTPS: Always use HTTPS for webhook endpoints
  3. Store Secrets Securely: Never commit webhook secrets to version control
  4. Idempotency: Handle duplicate webhook deliveries gracefully
  5. Rate Limiting: Implement rate limiting on your webhook endpoint

Testing Webhooks

Using ngrok (Local Development)

  1. Install ngrok: npm install -g ngrok
  2. Start your local server: npm run dev
  3. Expose with ngrok: ngrok http 3000
  4. 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:

  1. Webhook is active in dashboard
  2. Webhook URL is accessible (not behind firewall)
  3. Webhook endpoint returns 200 status
  4. Event type matches subscribed events

Signature Verification Fails

Check:

  1. Webhook secret matches in both systems
  2. Request body is read as raw text (not parsed JSON)
  3. Signature algorithm matches (sha256)
  4. 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


Last Updated: 2025-01-15