Skip to content
Login

Webhooks

Webhooks let Coassemble send server-to-server POST requests to your endpoint when important course events happen.

If you are embedding Coassemble in an iframe and want browser-side events instead, see Events.

Events you can subscribe to

EventFires when
course.createdA new course is created.
course.commencedA learner first commences a course tracking record.
course.completedA learner first completes a course tracking record.

Delivery format

Coassemble sends webhooks as POST requests with Content-Type: application/json.

Request headers

HeaderDescription
X-Coassemble-EventEvent name, e.g. course.completed.
X-Coassemble-DeliveryUnique delivery ID (UUID). Use this for idempotency.
X-Coassemble-TimestampUnix timestamp (seconds) used for signature verification.
X-Coassemble-SignatureHMAC SHA-256 signature in the format sha256=<hex>.

Request body

{
  "id": "17fd9df8-c77a-4b7d-a281-267b74f8cbf3",
  "type": "course.completed",
  "occurredAt": "2026-02-22T10:15:30.000Z",
  "workspaceId": 1234,
  "data": {
    "course": {
      "id": 4321,
      "title": "Security Basics",
      "key": "security-basics",
      "clientIdentifier": "course_abc"
    },
    "tracking": {
      "id": 8888,
      "identifier": "user_123",
      "email": "user@example.com",
      "commenced": "2026-02-22T10:01:00.000Z",
      "completed": "2026-02-22T10:15:30.000Z",
      "totalTime": 870
    }
  }
}

Signature verification

Each webhook endpoint has its own signing secret generated when the endpoint is created.

Signatures are created with: sha256 = HMAC_SHA256(secret, "<timestamp>.<raw_request_body>")

Example

Node.js

import crypto from 'crypto';

function verifyWebhookSignature({ rawBody, timestamp, signatureHeader, secret }) {
    const expected = `sha256=${crypto
        .createHmac('sha256', secret)
        .update(`${timestamp}.${rawBody}`)
        .digest('hex')}`;

    if (!signatureHeader || signatureHeader.length !== expected.length) return false;

    return crypto.timingSafeEqual(
        Buffer.from(signatureHeader, 'utf8'),
        Buffer.from(expected, 'utf8')
    );
}

Use the raw request body string when verifying signatures (before JSON parsing).

Retry and failure behavior

  • A delivery is considered successful only when your endpoint returns a 2xx status.
  • Coassemble uses a 10s request timeout.
  • Failed deliveries are retried up to 4 total attempts.
  • Backoff delays are approximately 1 minute, 5 minutes, then 30 minutes.
  • Delivery attempts include the same X-Coassemble-Delivery ID so you can deduplicate safely.

Setup

  1. Build an HTTPS endpoint in your app that accepts POST JSON and returns 2xx quickly.
  2. In Coassemble authoring, go to Settings -> Webhooks.
  3. Create a webhook endpoint URL and select one or more events.
  4. Send a test delivery to confirm your receiver logic (data.test is true on test payloads).
  5. Validate signatures, deduplicate using X-Coassemble-Delivery, then process asynchronously.

Managing webhooks

Webhook endpoints are currently managed in the Coassemble app.

  • Go to Settings -> Webhooks to create, edit, test, enable/disable, or delete endpoints.
  • Webhook endpoint URLs must use https://.