What triggers an event
Every successful change made through the API becomes one event, named<resource>.<verb>, for example apps.create, apps.delete, apps.deploy, users.update. Failed requests and read requests produce no event. A subscription can list exact types, a family such as apps.*, or nothing to receive every event.
Add a webhook
From Settings, Event webhooks in the dashboard, or:levelrail-cli event-webhooks rotate-secret <id> to issue a new one.
The URL must be a public http(s) address. Internal addresses are refused unless APP_EXPORT_ALLOW_PRIVATE_NETWORKS is set. Creating webhooks needs a master key, because signing secrets are stored with envelope encryption.
Payload
Verify the signature
Every request carries these headers, with the brand short name as the prefix (shown here asX-Brand):
The signature is an HMAC-SHA256, keyed with the signing secret, over
"<t>.<raw body>". Recompute it over the raw bytes, compare in constant time, and reject timestamps older than a few minutes to stop replayed captures.
Delivery, retries and the dead letter state
A delivery succeeds on any 2xx answer. Everything else is retried with exponential backoff, doubling from 30 seconds up to one hour, for up to 8 attempts. A 4xx answer other than 408 and 429 is treated as permanent and goes straight todead, since retrying cannot fix it.
Delivery is at least once. If your endpoint accepts an event but the control plane fails to record that, the event is sent again with the same X-Brand-Event-Id, so deduplicate on it.
Test, inspect and replay
- Send test (
levelrail-cli event-webhooks test <id>) sends a signedwebhook.testevent immediately and shows the HTTP status or the error. - Delivery log (
levelrail-cli event-webhooks deliveries <id>) lists each event with its state, attempts, last HTTP status and last error. - Replay (
levelrail-cli event-webhooks replay <delivery-id>) puts a delivery back in the queue with a fresh attempt budget.
disable. Disabled webhooks do not queue new events.