Skip to content

Webhook events

MonetizeIt delivers events to your HTTPS endpoints so your billing, CRM and automation stay in sync without polling. The contract follows two open standards: the payload is a CloudEvents 1.0 envelope, and delivery is signed per Standard Webhooks.

Create a subscription from the portal’s Webhooks page or the admin API:

  • POST /api/v1/webhooks/admin/subscriptions — register an endpoint URL, the event types you want, an optional filter, and a signing secret.
  • GET /api/v1/webhooks/admin/subscriptions · GET | PATCH | DELETE …/{id} — manage them.
  • POST …/{id}/test-fire — send a sample event to your endpoint.

Every event type the platform emits is discoverable, unauthenticated, at GET /api/v1/webhooks/schemas.

A subscription matches event types exactly (Entitlement.Activated), by prefix wildcard (Entitlement.*), or all (*). You can narrow further by entity kind (entitlement, asset-usage-tracker, …), by severity (for overage events), and by attribute equality.

When you create a subscription, MonetizeIt immediately POSTs a Webhooks.Registration.Challenge to your URL. Read data.challenge, sign it with your shared secret, and return that signature in the response body. The subscription becomes Active only once you echo back the correct signature — this proves you own the endpoint. Subscriptions move through PendingVerification → Active, and can later be Disabled or Suspended.

Every delivery is a CloudEvents 1.0 JSON document:

{
"specversion": "1.0",
"id": "01J…",
"source": "urn:monetizeit:…",
"type": "Entitlement.Activated",
"time": "2026-06-16T10:00:00Z",
"subject": "",
"datacontenttype": "application/json",
"entitykind": "entitlement",
"entityid": "",
"eventversion": 1,
"data": { }
}

data is event-specific and non-strict — ignore fields you don’t recognise, so new ones never break you.

Each request carries the Standard Webhooks headers:

HeaderMeaning
webhook-idThe envelope id
webhook-timestampRFC 3339 UTC send time
webhook-signaturev1, + base64 HMAC-SHA256
webhook-event-typee.g. Entitlement.Activated
webhook-delivery-attemptRetry counter
webhook-callback-tokenOptional short-lived JWT (see below)

Recompute the signature over {webhook-id}.{webhook-timestamp}.{raw-body} and compare in constant time:

signature = "v1," + base64( HMAC_SHA256(secret, id + "." + timestamp + "." + body) )

Reject anything that doesn’t match, or whose timestamp is too old to trust.

During a rotation there is an overlap window: MonetizeIt sends both signatures, space-separated, in webhook-signature. Accept the delivery if either verifies, so you can roll keys with no dropped events.

If your subscription requests callback scopes, each delivery includes a short-lived JWT in webhook-callback-token. Use it as a bearer token to call straight back into the admin API with exactly those scopes — no separate OAuth round-trip. Only read / create / update / write verbs are allowed; delete and wildcards are not.

Delivery is at-least-once and idempotent — deduplicate on webhook-id. Failed deliveries (5xx, timeout, DNS) retry with exponential backoff; once retries are exhausted the delivery is recorded as failed and kept for inspection, and every attempt is audited.

Event typeFires when
Entitlement.ActivatedA license is activated
Entitlement.ExpiringAn entitlement is approaching expiry
Entitlement.TrialExpiringA trial is approaching its end
Entitlement.RenewedA subscription period renews
Entitlement.CancelledAn entitlement is cancelled
Entitlement.PlanAppliedA usage plan is applied or changed
MeteredUsage.OverageStatusChangedA metered asset crosses a tier (Normal / Warning / Critical / OverUsage)
DataSubjectRequest.Filed · .Approved · .Rejected · .CompletedA data-subject request changes state
User.ErasedA user is erased
Webhooks.Registration.ChallengeSent once, to verify a new subscription