Webhooks

SoftLicense POSTs a JSON event to your endpoint when licenses, activations or customers change. Add endpoints under Developers → Webhooks, or with POST /api/v1/webhooks.

Payload

POST https://your-app.example.com/softlicense
SoftLicense-Signature: t=1719000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
SoftLicense-Event-Id: whe_…
SoftLicense-Event-Type: license.revoked

{ "id": "whe_…", "type": "license.revoked", "created_at": "…", "organization_id": "…",
  "data": { "license": { "id": "lic_…", "key": "ACME-…", "status": "revoked", ... }, "reason": "chargeback" } }

Verifying signatures

Compute HMAC-SHA256(secret, t + "." + rawBody) and compare it to v1 with a constant-time comparison. Reject if t is more than five minutes old. Use the raw request body, not a re-serialised one.

import { createHmac, timingSafeEqual } from "node:crypto";
const [t, v1] = header.split(",").map((kv) => kv.split("=")[1]);
const expected = createHmac("sha256", SECRET).update(`${t}.${rawBody}`).digest("hex");
if (!timingSafeEqual(Buffer.from(expected), Buffer.from(v1))) throw new Error("bad signature");

Delivery and retries

  • Respond with any 2xx within 10 seconds. Anything else is retried with backoff: 1m, 5m, 30m, 2h, 12h, then 24h, up to 10 attempts.
  • Endpoints that fail continuously for 7 days are disabled and your team is emailed. Re-enable from the dashboard; failed deliveries can be retried individually.
  • Deliveries are at-least-once. Use SoftLicense-Event-Id to de-duplicate.
  • Endpoints must be public https URLs; private and internal addresses are rejected.

Events

TypeWhen
license.createdA license was issued
license.updatedLicense details, expiry or entitlements changed
license.renewedA license was renewed or extended
license.suspendedA license was suspended
license.reinstatedA suspended license was reinstated
license.revokedA license was revoked
license.expiredA license passed its expiry date
license.expiring_soonA license will expire within the configured notice window
activation.createdA machine activated a license
activation.deletedA machine was deactivated
activation.lease_expiredA floating lease or heartbeat lapsed and the seat was freed
customer.createdA customer record was created
customer.updatedA customer record was updated