Webhooks Guide

Learn how to set up and configure webhooks to receive real-time notifications about events in your LicenseChain account.

Overview

Webhooks allow you to receive real-time notifications when events occur in your LicenseChain account. Instead of polling the API, you can configure webhooks to automatically notify your application when licenses are created, updated, or revoked.

What You'll Learn

Setup & Configuration

  • Creating and managing webhooks
  • Configuring webhook endpoints
  • Setting up event subscriptions
  • Webhook security and signatures

Implementation

  • Receiving webhook events
  • Verifying webhook signatures
  • Handling webhook failures
  • Testing webhook endpoints

Creating Webhooks

1. Create a Webhook Endpoint

First, create an HTTP endpoint in your application that can receive POST requests from LicenseChain.

// Express.js Example
app.post('/webhooks/licensechain', async (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const payload = JSON.stringify(req.body);
  
  // Verify signature (see Security section)
  if (!verifySignature(payload, signature, timestamp, webhookSecret)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook event
  const event = req.body;
  console.log('Received event:', event.type, event.data);
  
  res.status(200).send('OK');
});

2. Register Your Webhook

Use the LicenseChain API to register your webhook endpoint. You'll need to provide the URL and specify which events you want to receive.

POST /v1/webhooks
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "url": "https://your-app.com/webhooks/licensechain",
  "events": ["license.created", "license.updated", "license.revoked"],
  "secret": "optional-custom-secret"
}

Note: If you don't provide a secret, LicenseChain will automatically generate one for you. Make sure to store this secret securely as you'll need it to verify webhook signatures.

3. Available Events

LicenseChain supports the following webhook events:

license.created Triggered when a new license is created
license.updated Triggered when a license is updated
license.revoked Triggered when a license is revoked or suspended
license.expired Triggered when a license expires
user.registered Triggered when a new user registers
app.created Triggered when a new app is created

Security & Signature Verification

Webhook Signatures

All webhook requests include a signature in the X-Webhook-Signature header. This signature is generated using HMAC-SHA256 with your webhook secret. Always verify the signature to ensure the request is from LicenseChain.

// Node.js Example
const crypto = require('crypto');

function verifySignature(payload, signature, timestamp, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
const isValid = verifySignature(payload, signature, null, webhookSecret);

if (!isValid) {
  return res.status(401).send('Invalid signature');
}

Request Headers

LicenseChain includes the following headers with each webhook request:

X-Webhook-Signature HMAC-SHA256 signature of the request body
X-Webhook-Timestamp Unix timestamp of when the webhook was sent
Content-Type Always application/json

Webhook Event Structure

All webhook events follow a consistent structure:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "license.created",
  "data": {
    "id": "license-id",
    "licenseKey": "ABC123...",
    "userId": "user-id",
    "productId": "product-id",
    "status": "active",
    "expiresAt": "2024-12-31T23:59:59Z",
    "createdAt": "2024-01-01T00:00:00Z"
  },
  "timestamp": "2024-01-01T00:00:00Z",
  "signature": "hmac-sha256-signature"
}

Managing Webhooks

List All Webhooks

GET /v1/webhooks?page=1&limit=10
Authorization: Bearer YOUR_API_KEY

Get Webhook Details

GET /v1/webhooks/:id
Authorization: Bearer YOUR_API_KEY

Update Webhook

PUT /v1/webhooks/:id
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "url": "https://new-url.com/webhooks",
  "events": ["license.created", "license.updated"]
}

Delete Webhook

DELETE /v1/webhooks/:id
Authorization: Bearer YOUR_API_KEY

Testing Webhooks

Send Test Webhook

You can test your webhook endpoint without waiting for a real event to occur:

POST /v1/webhooks/:id/test
Authorization: Bearer YOUR_API_KEY

This will send a test event to your webhook URL with a sample payload. Use this to verify your endpoint is working correctly.

View Webhook Logs

Check the delivery status and response for each webhook event:

GET /v1/webhooks/:id/logs?page=1&limit=10
Authorization: Bearer YOUR_API_KEY

Logs include the HTTP status code, response body, and whether the delivery was successful.

Best Practices

✅ Always Verify Signatures

Never process webhook events without verifying the signature. This ensures the request is from LicenseChain and hasn't been tampered with.

✅ Respond Quickly

Your webhook endpoint should respond within 5 seconds. For long-running operations, acknowledge the webhook immediately and process asynchronously.

✅ Handle Idempotency

Use the event ID to prevent processing the same event multiple times. Store processed event IDs and check before processing.

✅ Use HTTPS

Always use HTTPS for your webhook endpoints to ensure data is encrypted in transit.

✅ Monitor Webhook Logs

Regularly check webhook logs to identify and fix delivery issues. Set up alerts for failed deliveries.

Troubleshooting

Webhook Not Receiving Events

  • • Verify your webhook URL is accessible from the internet
  • • Check that your endpoint returns a 2xx status code
  • • Ensure the events you're subscribed to are actually occurring
  • • Review webhook logs for delivery errors

Signature Verification Failing

  • • Ensure you're using the correct webhook secret
  • • Verify you're signing the exact request body (as JSON string)
  • • Check that you're using HMAC-SHA256 algorithm
  • • Make sure headers are being read correctly (case-sensitive)

Timeout Errors

  • • Optimize your webhook handler to respond quickly
  • • Move heavy processing to background jobs
  • • Return 200 OK immediately and process asynchronously

Next Steps