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, monitored-asset, …), by severity (for overage events), and by attribute equality.

When you create a subscription, MonetizeIt immediately POSTs a Webhooks.Registration.Challenge to your URL. Respond 2xx with a JSON body echoing the challenge — {"challenge": "<data.challenge>"} — and a webhook-signature response header signed with your shared secret over {webhook-id}.{webhook-timestamp}.{your response body}. The subscription becomes Active only once both check out — this proves you own the endpoint and hold the secret. Subscriptions move through PendingVerification → Active, and can later be Disabled or Suspended. The receiving side, with code, is in Receiving webhooks.

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. Test deliveries (sent from the portal or the test-fire endpoint) carry "_test": true in data; gate on it so test events never touch real state.

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 plan is applied or changed
MeteredUsage.OverageStatusChangedA monitored asset crosses a quota tier (Normal / Warning / Critical / OverUsage)
CreditBalance.StatusChangedA prepaid credit balance crosses a threshold — e.g. running low or depleted — so you can prompt a top-up before work is blocked
DataSubjectRequest.Filed · .Approved · .Rejected · .CompletedA data-subject request changes state
User.ErasedA user is erased
Webhooks.Registration.ChallengeSent once, to verify a new subscription