Skip to main content
Manage webhook endpoints that receive real-time notifications when license events occur.

Create a webhook

POST
Register a new webhook endpoint for an application.

Path parameters

ParamTypeDescription
appIdstringThe application ID

Request body

FieldTypeRequiredDescription
urlstringYesHTTPS endpoint URL to receive events
eventsstring[]YesArray of event names to subscribe to
enabledbooleanNoWhether 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

HTTPCodeCause
400bad_requestInvalid URL, empty events array, or invalid event name
403forbiddenThe app doesn’t belong to your account
400bad_requestMax 5 webhooks per app exceeded

List webhooks

GET
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

PUT
Update the URL, events, or enabled status of an existing webhook.

Path parameters

ParamTypeDescription
appIdstringThe application ID
webhookIdstringThe webhook ID

Request body

All fields are optional — only included fields are updated.
FieldTypeDescription
urlstringNew endpoint URL
eventsstring[]New event subscriptions
enabledbooleanEnable 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)

{ "ok": true }

Delete a webhook

DELETE
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)

{ "ok": true }

Test a webhook

POST
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.

Webhook payload format

Every webhook delivery sends an HTTP POST with these headers and body:

Headers

HeaderValue
Content-Typeapplication/json
X-AuthForge-EventEvent name (e.g., license.revoked)
X-AuthForge-TimestampISO 8601 timestamp
X-AuthForge-SignatureHMAC-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.