Overview
POST licensing events to your own endpoints or a Discord channel in real time.
Webhooks push events to a URL you own so you can react in real time: revoke a seat when a license expires, alert a channel when a key is rejected, or sync a record on a new activation.
This extension uses core when present. See the
Configuration for the settings and the
API Reference for the endpoints. The delivery payload
and signature are described below.
How it works
- Add a webhook from the Webhooks dashboard page (or the API) with a target URL and the events you want.
- Kora
POSTs each event as JSON, signed with anx-kora-signatureHMAC over the raw body. - Return any
2xxto acknowledge. On a bad status or timeout Kora retries, then records the failure. - Every attempt is kept in the deliveries log. You can rotate the secret or send a test event anytime.
The delivery
Each event is a JSON POST to your URL:
{
"event": "license.validated",
"timestamp": 1700000000000,
"data": { "license": "LICENSE-KEY", "product": "Your Product", "customer": "Some Customer" }
}| Header | Value |
|---|---|
x-kora-event | The event name, for routing without parsing the body. |
x-kora-signature | HMAC-SHA256 of the raw body, signed with the webhook secret. |
Anyone can POST to your URL, so verify every delivery: recompute the signature over the raw body (the bytes must match, not a re-serialized object) and compare it in constant time.
import crypto from "crypto";
const expected = crypto.createHmac("sha256", SECRET).update(rawBody).digest("hex");
const signature = request.header("x-kora-signature") ?? "";
const ok = expected.length === signature.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));Discord
Paste a Discord webhook URL as the target and Kora sends each event as a color-coded embed, with no relay or signature handling on your side.
Events
license.created, license.updated, license.deleted, license.validated, license.rejected,
license.expired, session.opened, session.closed, session.limit_exceeded. Leave a webhook's
event list empty to receive all of them.

