This guide describes the current webhook delivery system. If you have legacy webhooks and wish to move over to the new system, see Migrating your webhooks to the new infrastructure to switch over.
Subscriptions
You can set up a webhook for your company, which will deliver events for all groups within the company. If you need webhooks to be sent to different URLs for some or all groups, webhooks can also be configured for these individual groups. When a webhook is configured for a specific group, events for that group are sent to the group webhook subscription only and not the company webhook subscription. You can subscribe to webhooks in the KarmaCheck sandbox dashboard. You will need the following information:- A URL that’s configured to handle incoming HTTPS POST requests. KarmaCheck will send notifications to this URL whenever relevant events occur.
- The event types that you want to subscribe to. See Events for a list of supported events.
- The group ID of a group within your company only if you want to configure your webhook URL to receive events occurring for just that specific group. Unless specified, a webhook is usually configured to deliver events occurring for all groups within a company.
The webhook subscription link above is for your sandbox account. Use the production domain to subscribe to webhooks in production.
Webhook structure
All webhooks are delivered over HTTPS and include the following properties in a JSON payload:| Header | Purpose |
|---|---|
webhook-id | Unique message identifier (same ID if a message is retried) |
webhook-timestamp | Timestamp in seconds since epoch |
webhook-signature | Space-delimited list of versioned signatures, e.g. v1,<base64-encoded-hmac> |
Verifying signatures
KarmaCheck signs every webhook delivery using HMAC-SHA256 with the per-endpoint signing secret shown in your dashboard.
. separators; HMAC-SHA256 that string using the base64-decoded portion of the signing secret (the part after whsec_); base64-encode the result; and compare it (in constant time) against each signature in the header, stripping the v1, prefix. Reject the message if no signature matches or if the timestamp is outside a small tolerance window (5 minutes is a reasonable default).
Pass the raw request body bytes. JSON middleware that parses before your verification step may reorder keys or alter whitespace and break the signature. The header may contain multiple signatures during a key rotation window — accept if any one matches.
- Store the signing secret in environment variables or a secrets manager. Never hard-code or commit it.
- Rotate secrets from the dashboard when needed. During rotation, the system signs with both the old and new secret simultaneously; the verifier above already handles this by accepting either match.
Responding to webhooks
To confirm receipt of a webhook, your webhook endpoint must respond with a 2xx HTTP status code as quickly as possible. Any response codes outside of this range, including 3xx codes, will indicate that you did not receive the webhook. Any other information returned does not get processed.Retries
If your endpoint doesn’t return a 2xx response within 15 seconds, the delivery is considered failed and KarmaCheck will retry it on the following schedule:| Attempt | Delay after previous attempt |
|---|---|
| 1 | Initial delivery |
| 2 | 5 seconds |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 5 hours |
| 7 | 10 hours |
| 8 | 10 hours |
Events
The following events can trigger webhooks. KarmaCheck can configure webhooks to send either or both types of event notifications to your configured URL.| Event | Description |
|---|---|
case.statuschange | The status of a case has changed. |
casedata.statuschange | The status of a service (case data) has changed. |
Order of events
Each supported event occurs multiple times during a case’s lifecycle. As an example with thecase.statuschange event, the status of a case involving a candidate-provided PII flow could change like so:
| Event order | Case status | Description |
|---|---|---|
| 1 | caseStatus: “Pending” / secondaryStatus: “Waiting for Authorization” | Invitation sent to candidate |
| 2 | caseStatus: “Pending” / secondaryStatus: “Authorization in Progress” | Candidate started onboarding |
| 3 | caseStatus: “Pending” / secondaryStatus: null | Case is processing |
| 4 | caseStatus: “Complete” / secondaryStatus: null | Case is complete, with all screenings cleared |
GET /case/id/{caseId} whenever you receive the case.statuschange event.
Duplicate events
Webhook endpoints might occasionally receive the same notification more than once if multiple events occur within a short period of time. One way to account for duplicate events is to log the events that you have processed so that you can avoid reprocessing them. For example, when receiving acase.statuschange event, compare the following properties to those of your logged events:
id: The case IDcaseStatusIdandsecondaryCaseStatusId: The case statusmodStamp: The timestamp for the case modification
Missed events
Some issues that might occur, such as server errors, could lead to missed webhook notifications. To account for the possibility of missed events, you can build a function to check if a type of event notification hasn’t been received for a specific length of time. When this happens, fetch the latest data related to the missed event.KarmaCheck webhooks are powered by Svix. For more information, check out their documentation.