Webhook Events Reference
Complete reference for all webhook events sent by the SCORM API.
Table of Contents
Event Overview
All webhook events follow a consistent structure:
{
"event": "event.type.name",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
// Event-specific data
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Common Fields
- event (string): Event type identifier
- tenant_id (UUID): Tenant that triggered the event
- data (object): Event-specific payload
- timestamp (ISO 8601): When the event occurred
- delivery_id (string): Unique delivery identifier for tracking
Event Types
Package Events
package.processing.completed
Triggered when a SCORM package finishes processing successfully.
When: After package upload, validation, extraction, and database storage complete.
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",
"manifest_url": "imsmanifest.xml",
"file_size_bytes": 5242880,
"storage_path": "tenant-550e8400/packages/pkg_abc123",
"metadata": {
"identifier": "com.example.course.001",
"schema": "ADL SCORM",
"schemaversion": "1.2",
"sco_count": 5
}
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Use Cases:
- Update package status in your system
- Notify administrators of successful upload
- Trigger course availability notifications
- Update package catalog
package.processing.failed
Triggered when package processing fails.
When: During validation, extraction, or storage if an error occurs.
Payload:
{
"event": "package.processing.failed",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"package_id": "pkg_abc123",
"error": "Invalid SCORM manifest: missing imsmanifest.xml",
"error_code": "INVALID_MANIFEST",
"storage_path": "tenant-550e8400/uploads/tmp_123.zip",
"original_filename": "course.zip"
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Error Codes:
INVALID_MANIFEST- Manifest file missing or invalidINVALID_SCORM_VERSION- Unsupported SCORM versionEXTRACTION_FAILED- Failed to extract packageSTORAGE_ERROR- Storage backend errorQUOTA_EXCEEDED- Package or storage quota exceeded
Use Cases:
- Notify user of upload failure
- Log errors for debugging
- Trigger retry mechanisms
- Update package status to "failed"
Session Events
session.created
Triggered when a new learning session is created.
When: After calling /api/v1/packages/{id}/launch or /api/v1/sessions/external.
Payload:
{
"event": "session.created",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"session_id": "session_abc123",
"package_id": "pkg_abc123",
"user_id": "user_xyz789",
"launch_url": "https://app.allureconnect.com/player/session_abc123?token=eyJhbGciOi...",
"expires_at": "2025-01-15T22:30:00.000Z"
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Use Cases:
- Track course starts
- Update learner dashboard
- Send welcome notifications
- Log learning activity
session.completed
Triggered when a learner completes a course.
When: Session completion_status changes to completed.
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,
"min": 0,
"max": 100
},
"time_spent_seconds": 3600,
"attempts": 1
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Use Cases:
- Issue completion certificates
- Update grade book
- Trigger follow-up actions
- Send completion notifications
- Award badges or achievements
session.progress
Triggered when session CMI data is updated.
When: SCORM player updates progress, scores, or time spent.
Note: This event can be very frequent (multiple times per minute). Consider filtering or throttling on your end.
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",
"success_status": "unknown",
"score": {
"scaled": 0.65,
"raw": 65,
"min": 0,
"max": 100
},
"time_spent_seconds": 1800,
"version": 5
},
"timestamp": "2025-01-15T10:30:00.000Z",
"delivery_id": "delivery_xyz789"
}
Use Cases:
- Real-time progress tracking
- Live dashboards
- Progress notifications
- Analytics aggregation
Performance Note: If you receive too many progress events, consider:
- Filtering by completion status changes only
- Throttling updates in your system
- Using polling for progress instead
Delivery Guarantees
At-Least-Once Delivery
The SCORM API guarantees at-least-once delivery:
- Events are delivered at least once
- Events may be delivered multiple times (duplicates)
- Failed deliveries are retried automatically
Retry Schedule
Failed deliveries are retried with exponential backoff:
| Attempt | Delay | Total Time |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | 60s | 60s |
| 3 | 2m | 3m |
| 4 | 4m | 7m |
| 5 | 8m | 15m |
| 6 | 16m | 31m |
After 5 retry attempts, the delivery is marked as "exhausted" and an email notification is sent.
Delivery Status
- pending: Waiting for retry
- delivered: Successfully delivered (2xx response)
- failed: Delivery failed (non-2xx response)
- exhausted: Max retries exceeded
Retry Logic
Automatic Retries
The SCORM API automatically retries failed deliveries:
- Exponential backoff (60s → 2m → 4m → 8m → 16m)
- Jitter to prevent thundering herd
- Max 5 retry attempts
- 30-second timeout per attempt
Manual Retry
You can manually retry a failed delivery:
curl -X POST https://app.allureconnect.com/api/admin/webhooks/deliveries/delivery_xyz789/retry \
-H "X-API-Key: your-api-key"
Idempotency
Handling Duplicate Events
Since webhooks use at-least-once delivery, you may receive duplicate events. Implement idempotency:
const processedDeliveries = new Set<string>();
export async function POST(request: Request) {
const event = await request.json();
const deliveryId = event.delivery_id;
// Check if already processed
if (processedDeliveries.has(deliveryId)) {
return new Response('Already processed', { status: 200 });
}
// Process event
await handleEvent(event);
// Mark as processed
processedDeliveries.add(deliveryId);
return new Response('OK', { status: 200 });
}
Database-Based Idempotency
For production, use database to track processed deliveries:
async function isDeliveryProcessed(deliveryId: string): Promise<boolean> {
const result = await db.webhookDeliveries.findUnique({
where: { delivery_id: deliveryId },
});
return !!result;
}
async function markDeliveryProcessed(deliveryId: string) {
await db.webhookDeliveries.create({
data: { delivery_id: deliveryId, processed_at: new Date() },
});
}
Best Practices
- Process Asynchronously: Return 200 immediately, process in background
- Implement Idempotency: Handle duplicate deliveries gracefully
- Log All Events: Keep audit trail of all webhook events
- Handle Errors: Don't let webhook processing crash your application
- Monitor Delivery: Track delivery success rates
- Filter Progress Events: Consider filtering
session.progressevents if too frequent
Related Documentation
- Webhook Setup - How to set up webhooks
- Webhook Security - Security best practices
- API Reference - Complete API documentation
Last Updated: 2025-01-15