Webhooks

Register an outbound URL per tenant. On each committed event, the service POSTs the EventRecord JSON to matching endpoints asynchronously. Endpoint signatures and curl examples: HTTP API → Webhooks.

How it works

Failed deliveries retry 3 times with a 2s pause. events lists event types to forward, ["*"] for all subscribed event types. List endpoints with GET /webhooks; remove with DELETE /webhooks/{id}. POST /webhooks returns a secret once — store it securely; GET /webhooks never returns the secret.

Signature verification

The delivery body is the raw EventRecord (same shape as GET /events). Verify every delivery with the Billing-Webhook-Signature header: v1 = HMAC-SHA256(secret, "<unix>.<raw body>"). Reject requests older than ~5 minutes.

On retry the body is identical — deduplicate by event_id and return 2xx without re-processing duplicates.

Typical subscriptions

  • subscription.created, subscription.canceled — sync CRM or access control
  • subscription.period_rolled — trigger invoice generation at period end
  • usage.recorded — near-real-time metering dashboards (high volume; filter in your handler)
  • usage.threshold_crossed — plan alert fired (once per period); see payload
  • invoice.generated, invoice.finalized, invoice.paid — payment collection downstream
  • user.blocked, user.unblocked — dunning / access control
  • adjustment.posted, refund.issued — reconcile credits and refunds

Plan alerts

Define threshold notifications on a plan with alerts[] (create plan / pricing package) or PUT /plans/{id}/alerts. Unlike hard limits (action: reject), alerts only notify — they never block ingest.

json
{
  "scope": "metric",
  "metric_code": "api_requests",
  "percent": 80,
  "baseline_units": 100,
  "action": "webhook"
}
FieldDescription
scopemetric or metric_group
metric_code / groupTarget of the alert
percent1–100; fires when period usage crosses this % of baseline
baseline_unitsOptional. If omitted: matching reject limits[].max_per_period, else included_units
actionOnly webhook (default)

Crossing emits usage.threshold_crossed once per (subscription, alert, billing period) and delivers it through that tenant’s /webhooks subscribers. API reference: HTTP API → Plan alerts.

Payload: usage.threshold_crossed

Deduplicate by event_id.

json
{
  "event_id": "evt_...",
  "type": "usage.threshold_crossed",
  "source": "system",
  "occurred_at": "2026-07-15T10:00:00Z",
  "accepted_at": "2026-07-15T10:00:00Z",
  "data": {
    "user_id": "usr_...",
    "subscription_id": "sub_...",
    "plan_id": "pln_...",
    "plan_code": "sandbox",
    "plan_name": "Sandbox",
    "metric_id": "met_...",
    "metric_code": "api_requests",
    "alert_percent": 80,
    "current_units": 80,
    "threshold_units": 80,
    "quantity": 100,
    "period_start": "2026-07-01T00:00:00Z",
    "period_end": "2026-08-01T00:00:00Z"
  }
}
FieldMeaning
alert_percentConfigured percent on the alert
current_unitsPeriod usage after the crossing event
threshold_unitsceil(baseline × percent / 100)
quantityBaseline units used for the percent calculation
period_start / period_endActive subscription billing period