Webhooks send HTTP POST requests to your server when events happen on your licenses — creation, validation, revocation, and more. Use them to sync license state with your backend, trigger workflows, or update your database.
How it works
- You register a webhook URL in the dashboard or via the API.
- When a matching event occurs, AuthForge sends an HTTP POST to your URL with a JSON payload.
- Each request is signed with HMAC-SHA256 so you can verify it came from AuthForge.
Events
| Event | Trigger |
|---|
license.validated | Successful authentication via SDK |
license.created | License key generated (dashboard or API) |
license.revoked | License revoked |
license.activated | Revoked license re-activated |
license.hwid_bound | HWID bound to a license slot |
license.hwid_reset | HWID bindings cleared |
license.deleted | License permanently deleted |
license.validated fires on every successful SDK login. For high-traffic apps, consider subscribing only to the events you need.
Every webhook delivery sends a JSON body like this:
{
"event": "license.validated",
"timestamp": "2026-04-10T15:30:00.000Z",
"data": {
"licenseKey": "A3K9-BFWX-7NP2-QHDT",
"appId": "550e8400-e29b-41d4-a716-446655440000",
"status": "active",
"hwid": "a1b2c3d4e5f6..."
}
}
| Header | Description |
|---|
Content-Type | application/json |
X-AuthForge-Event | The event name (e.g., license.validated) |
X-AuthForge-Timestamp | ISO 8601 timestamp of the event |
X-AuthForge-Signature | HMAC-SHA256 hex digest of the request body |
Signature verification
Every webhook is signed using the secret generated when you created the webhook. Always verify the signature before processing.
The signature is computed as:
HMAC-SHA256(webhook_secret, raw_request_body)
Verification example (Node.js / Express)
const crypto = require("crypto");
app.post("/webhooks/authforge", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-authforge-signature"];
const expected = crypto
.createHmac("sha256", process.env.AUTHFORGE_WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (signature !== expected) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body);
console.log(`Received ${event.event} for ${event.data.licenseKey}`);
// Handle the event
switch (event.event) {
case "license.validated":
// Update last-seen timestamp in your DB
break;
case "license.revoked":
// Suspend user access in your system
break;
case "license.created":
// Send welcome email
break;
}
res.sendStatus(200);
});
Verification example (Python / Flask)
import hmac
import hashlib
from flask import Flask, request, abort
app = Flask(__name__)
WEBHOOK_SECRET = os.environ["AUTHFORGE_WEBHOOK_SECRET"]
@app.route("/webhooks/authforge", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-AuthForge-Signature", "")
expected = hmac.new(
WEBHOOK_SECRET.encode(),
request.data,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
abort(401)
event = request.get_json()
print(f"Received {event['event']} for {event['data']['licenseKey']}")
# Handle the event...
return "", 200
Setup
Via the dashboard
- Go to your app’s Settings → Webhooks
- Click Add Webhook
- Enter your HTTPS endpoint URL
- Select which events to subscribe to (or select all)
- Click Create
- Copy the webhook secret — it’s shown only once
Via the Developer API
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
}'
The response includes a secret field — store it securely for signature verification.
Limits
| Limit | Value |
|---|
| Max webhooks per app | 5 |
| Delivery timeout | 10 seconds |
| Retries | None (v1) |
Testing
Use the test endpoint to send a sample payload to your webhook URL:
curl -X POST https://api.authforge.cc/v1/apps/YOUR_APP_ID/webhooks/WEBHOOK_ID/test \
-H "Authorization: Bearer af_live_your_key"
This sends a test license.validated event to verify your endpoint is receiving and verifying payloads correctly.
Next steps