Webhooks let an organization OWNER or ADMIN receive Cohorte domain events
on a public HTTPS endpoint. Every call below uses the organization-bound
x-api-key; every command also requires a stable Idempotency-Key, and a
repeated key returns the original result with replayed: true.
The lifecycle of a subscription:
pending_validation and receives nothing yet.active only if your
endpoint echoes it.pending_validation.The destination must use https://, carry no user name, password or
fragment, use a host name rather than an IP address, and resolve only to
public addresses. It is checked against private, loopback, link-local and
reserved networks at creation, at verification and before every delivery.
Redirects are never followed.
Subscription responses show the destination as scheme, host, port and path
only; its query string is kept but never returned. When updating, omit
endpointUrl to keep the complete stored destination; sending it replaces the
whole destination and requires verification again.
Verification sends this body, signed like any delivery:
{"type": "cohorte.webhook.challenge", "challenge": "opaque-value"}Return a 2xx JSON response containing the exact same challenge:
{"challenge": "opaque-value"}program.created, program.updated;cohort.created, cohort.updated;enrollment.created, enrollment.closed;submission.submitted, member_submission.validated;outcome_measure.submitted, community_thread.created.Each delivery is a POST with a JSON body:
{
"id": "0e4f8a2b-6c1d-4e3f-9a5b-7c8d9e0f1a2b",
"type": "enrollment.created",
"occurredAt": "2026-09-21T10:00:00.000Z",
"subject": {"type": "Enrollment", "id": "2f6a9c3e-1b4d-4a7e-8c0f-5d2e6b9a1c3f"},
"correlationId": "5a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"data": {}
}data depends on the event.
Each request carries:
x-cohorte-event-id: the event id, stable across retries and replays (the
subscription id for a verification challenge);x-cohorte-timestamp: Unix seconds;x-cohorte-signature: v1=<hex HMAC-SHA256>.Compute HMAC-SHA256 with the subscription secret over the exact bytes:
timestamp + "." + eventId + "." + rawRequestBodyCompare signatures in constant time, reject stale timestamps according to your clock policy, and deduplicate on the event id. Never parse and re-serialize the body before verifying the signature.
active. Events that occur
while it is pending or failed verification wait for it; events that occur
while it is paused are not queued for it.2xx within 8 seconds is a failure. Cohorte makes at
most five attempts, with backoff of 1, 2, 4 and then 8 minutes, before the
delivery becomes exhausted.authorization, cookie, password, secret, token and signature are
redacted from what the API shows; your endpoint receives the original payload.succeeded or exhausted delivery; it reuses the event id and never
creates a new domain event.An id from another organization answers the same 404 as an absent one.