Manage webhook endpoints that receive real-time notifications when license events occur.
Create a webhook
Register a new webhook endpoint for an application.
Path parameters
| Param | Type | Description |
|---|
appId | string | The application ID |
Request body
| Field | Type | Required | Description |
|---|
url | string | Yes | HTTPS endpoint URL to receive events |
events | string[] | Yes | Array of event names to subscribe to |
enabled | boolean | No | Whether the webhook is active (default true) |
Available events
license.validated, license.created, license.revoked, license.activated, license.hwid_bound, license.hwid_reset, license.deleted
Example
curl -X POST https://api.authforge.cc/v1/apps/YOUR_APP_ID/webhooks \
-H "Authorization: Bearer af_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/authforge",
"events": ["license.created", "license.revoked"],
"enabled": true
}'
Response (201)
{
"webhookId": "wh_a1b2c3d4e5f6",
"appId": "YOUR_APP_ID",
"url": "https://your-server.com/webhooks/authforge",
"events": ["license.created", "license.revoked"],
"enabled": true,
"secret": "whsec_7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c",
"createdAt": "2026-04-10T12:00:00.000Z"
}
The secret field is returned only on creation. Store it securely — you’ll need it to verify webhook signatures. It cannot be retrieved again.
Errors
| HTTP | Code | Cause |
|---|
| 400 | bad_request | Invalid URL, empty events array, or invalid event name |
| 403 | forbidden | The app doesn’t belong to your account |
| 400 | bad_request | Max 5 webhooks per app exceeded |
List webhooks
List all webhooks for an application.
Example
curl https://api.authforge.cc/v1/apps/YOUR_APP_ID/webhooks \
-H "Authorization: Bearer af_live_your_key"
Response (200)
{
"webhooks": [
{
"webhookId": "wh_a1b2c3d4e5f6",
"appId": "YOUR_APP_ID",
"url": "https://your-server.com/webhooks/authforge",
"events": ["license.created", "license.revoked"],
"enabled": true,
"lastDeliveryAt": "2026-04-10T15:30:00.000Z",
"lastDeliveryStatus": 200,
"createdAt": "2026-04-10T12:00:00.000Z"
}
]
}
The secret field is not returned in list responses for security.
Update a webhook
Update the URL, events, or enabled status of an existing webhook.
Path parameters
| Param | Type | Description |
|---|
appId | string | The application ID |
webhookId | string | The webhook ID |
Request body
All fields are optional — only included fields are updated.
| Field | Type | Description |
|---|
url | string | New endpoint URL |
events | string[] | New event subscriptions |
enabled | boolean | Enable or disable the webhook |
Example
curl -X PUT https://api.authforge.cc/v1/apps/YOUR_APP_ID/webhooks/wh_a1b2c3d4e5f6 \
-H "Authorization: Bearer af_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"events": ["license.created", "license.revoked", "license.validated"],
"enabled": true
}'
Response (200)
Delete a webhook
Permanently delete a webhook endpoint.
Example
curl -X DELETE https://api.authforge.cc/v1/apps/YOUR_APP_ID/webhooks/wh_a1b2c3d4e5f6 \
-H "Authorization: Bearer af_live_your_key"
Response (200)
Test a webhook
Send a test event to the webhook endpoint. Returns the HTTP status code from your server.
Example
curl -X POST https://api.authforge.cc/v1/apps/YOUR_APP_ID/webhooks/wh_a1b2c3d4e5f6/test \
-H "Authorization: Bearer af_live_your_key"
Response (200)
{
"ok": true,
"statusCode": 200
}
The test sends a license.validated event with sample data to your endpoint, signed with the webhook’s secret.
Every webhook delivery sends an HTTP POST with these headers and body:
| Header | Value |
|---|
Content-Type | application/json |
X-AuthForge-Event | Event name (e.g., license.revoked) |
X-AuthForge-Timestamp | ISO 8601 timestamp |
X-AuthForge-Signature | HMAC-SHA256(secret, body) as hex |
Body
{
"event": "license.revoked",
"timestamp": "2026-04-10T15:30:00.000Z",
"data": {
"licenseKey": "A3K9-BFWX-7NP2-QHDT",
"appId": "YOUR_APP_ID",
"status": "revoked"
}
}
The data object varies by event type but always includes licenseKey and appId.
Signature verification
const crypto = require("crypto");
const signature = req.headers["x-authforge-signature"];
const expected = crypto
.createHmac("sha256", webhookSecret)
.update(rawBody)
.digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
See Webhooks for full verification examples in Node.js and Python.