Webhooks

Webhooks notify your systems about events in your Cryptlex account in real time. When a subscribed event occurs, such as a license being created or activated, Cryptlex sends an HTTP POST request with a signed JSON payload describing the event to an endpoint you specify.

When to use webhooks

Webhooks are the building block for automating communication between Cryptlex and your other systems asynchronously. You might use webhooks to:

  • Email a license key to your customer after a successful purchase.
  • Email your customer when the license expires.
  • Get notified through email or chat apps like Slack when a user activates a trial or license.
  • Any other integration your business needs.

Creating a webhook

To create a webhook, go to the Developer -> Webhooks section in the admin portal and click the Add button. A webhook form with the following fields will pop up:

Name

Name for the webhook.

URL

The endpoint which will receive the HTTP POST payload.

Token

The token is a secret that will be used to sign the payload using the HMAC SHA-256 algorithm.

Events

The list of events which trigger the POST request.

Enabled

If unchecked, the webhook will be disabled and will not send a POST request on the defined events.

Webhook payload

Each event type has a specific payload format with relevant event information. The payload is JSON, encoded as UTF-8, and is signed with the HMAC SHA-256 algorithm; the signature is included in the webhook-signature header. HTTP header names are case-insensitive, so read the header without expecting a specific casing. A typical delivery has the following structure:

POST /webhook-endpoint HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 661
webhook-signature: Bb3jMWkC1DOqEv5fAOsqwkKH7r57w9o8fZ3Jg72lNk0=

{
"id": "d9c7a3a2-4f5e-4a3b-9b2e-8f1a6c0d7e42",
"event": "license.created",
"data": {
"key": "D08B53-C564F8-463EA5-F16A15-E35D6E-D2559B",
...
},
"triggeredAt": "2018-04-20T13:11:34.6926949Z"
}

Verifying the signature

Verify the signature on every delivery to make sure the request really came from Cryptlex. The signature is computed as:

signature = Base64(HMAC-SHA256(key: webhook token, message: raw request body))

Follow these rules, which cover the most common integration bugs:

  • Hash the raw request body exactly as received, before parsing it. Parsing the JSON and re-serializing it will not reproduce the original bytes, because key order and whitespace are not preserved. This is the single most common mistake.
  • Treat the body as UTF-8 bytes. The payload is not ASCII-escaped, so values with accented characters or emoji carry raw multi-byte UTF-8. Hash the bytes as received; do not decode them to a string in another encoding and re-encode.
  • Use a constant-time comparison to compare the computed signature with the header value, not string equality.
  • Read the webhook-signature header case-insensitively.
const crypto = require("crypto");

// rawBody must be the unparsed request body as a Buffer.
// In Express, use express.raw() or the verify callback of express.json()
// to capture it before any JSON parsing.
function verifyWebhookSignature(rawBody, signatureHeader, token) {
const expected = crypto
.createHmac("sha256", token)
.update(rawBody)
.digest("base64");
const received = Buffer.from(signatureHeader ?? "");
return (
received.length === Buffer.from(expected).length &&
crypto.timingSafeEqual(received, Buffer.from(expected))
);
}

Testing a webhook

You can send a test delivery to your endpoint at any time using the Test action in the actions menu on the Developer -> Webhooks page in the admin portal.

The test sends a sample payload for an event of your choice (it defaults to the webhook's first subscribed event), signed exactly like a real delivery. The test result includes your endpoint's response along with the exact body that was signed and the signature that was sent, so you can reproduce the signature computation while debugging.

Two properties of test deliveries are worth knowing:

  • They are not recorded as webhook event logs and never affect the webhook's health or suspension.
  • The sample payload carries representative but synthetic values, including non-ASCII characters, so an endpoint that verifies signatures incorrectly fails the test instead of passing it by accident.

Delivery and retries

  • Each delivery attempt times out after 15 seconds. A delivery fails on any non-2xx response, or when no response is received.
  • A failed event is retried up to 5 attempts in total, 5 minutes apart. An event that exhausts all attempts is marked failed.

Webhook event logs

Webhook event logs show information about POST requests that were made when the webhook was triggered. You can view them on the Developer -> Webhook Event Logs page in the admin portal, and use them to see the status code returned by your endpoint, when the request was sent and received, and the reason for any retry. You can also resend a delivery using the Resend action in the actions menu of an event log.

An event log has one of the following statuses: queued, pending, retrying, succeeded, failed, or cancelled. The cancelled status means the webhook was disabled or suspended at the time the event fired, so no delivery was attempted.

Webhook health

The status property reflects the operational state of a webhook:

  • A webhook starts as Healthy. A single failed attempt does not change the status; the event simply enters its retry cycle.
  • The status transitions to Unhealthy once an event has exhausted all of its retry attempts and been marked failed.
  • The status transitions from Unhealthy to Suspended when the 50 most recent completed events have all failed. When a webhook is suspended, Cryptlex emails your account's notification address.
  • While Suspended, no automatic delivery attempts are made, but events are still logged, so they can be resent later.
  • A successful delivery, including a manual resend, immediately restores the webhook status back to Healthy.
Personal Access TokensAutomated Emails
Last updated: