Documentation menu

Guides

Webhooks

Get notified on your own server when licenses are created, activated, renewed, or revoked.

Set up an endpoint

  1. Open Webhooks and add your server's HTTPS URL.
  2. Choose the events you want, or leave the selection empty to receive all of them.
  3. Copy the signing secret (whsec_…). It's shown only once.
  4. Verify each request's signature and respond with any 2xx status.

Events

EventSent when
license.createdA license is issued.
license.updatedEntitlements, metadata, or the device limit change.
license.activatedA device activates the license.
license.deactivatedA device is released.
license.renewedThe license gets a new expiry date.
license.suspendedThe license is suspended.
license.reinstatedA suspended license is reinstated.
license.revokedThe license is revoked.
license.expiredA check finds the license past its expiry and grace period.
activation.limit_reachedA device is refused because every slot is in use.
customer.createdA new customer is created along with a license.
customer.updatedA customer's details change when a license is issued.
Example payload
{
  "id": "evt_...",
  "type": "license.activated",
  "created_at": "2026-10-24T09:12:44.000Z",
  "environment_id": "env_...",
  "data": {
    "license": { "id": "lic_...", "status": "active", "entitlements": { "plan": "pro" } },
    "activation": { "id": "act_...", "device_id": "install_9f2c", "status": "active" }
  }
}

Verify the signature

Each request has an Atlas-Signature header. Check it before trusting the request, using the raw body exactly as received.

Express
import express from "express";
import { verifyWebhook } from "@atlas/sdk";

app.post("/atlas/webhooks", express.raw({ type: "application/json" }), async (req, res) => {
  const result = await verifyWebhook(
    req.body.toString("utf8"),
    req.headers,
    process.env.ATLAS_WEBHOOK_SECRET!,
  );
  if (!result.valid) return res.status(400).send(result.reason);

  if (result.event.type === "license.revoked") {
    await disableAccount(result.event.data.license.id);
  }
  res.sendStatus(200);
});
Verifying without the SDK

The header looks like t=1761100800,v1=5f2c…. Compute HMAC-SHA256 of `${t}.${rawBody}` with your signing secret, hex-encode it, and compare it to v1 with a constant-time comparison. Reject requests where t is more than five minutes old.

Deliveries and retries

  • Any 2xx response counts as delivered. Respond quickly and do slow work afterwards.
  • Failed deliveries are retried after 30 seconds, 5 minutes, 30 minutes, 3 hours, and 12 hours.
  • You may occasionally receive an event twice. Use the event ID (also sent as Atlas-Event-Id) to skip duplicates.
  • Each endpoint's page shows every delivery attempt, and you can resend any of them.

Rotating the secret

If a secret leaks or is lost, rotate it from the endpoint page. The new secret applies from the next delivery, so update your server straight away.