Webhooks

Updated Oct 5, 2026 Markdown

/admin/webhooks lets the operator subscribe external systems (billing platforms, monitoring, custom glue) to lifecycle events without polling. Two tabs:

Endpoints

Table of registered subscribers — URL, subscribed event count (tooltip lists them), status badge (enabled / disabled / muted), last delivery outcome. Add via the "+ Add endpoint" CTA:

  • URL — https:// or http:// (both are accepted; use HTTPS for any receiver outside the host's own network, the payload carries account data); private / loopback ranges blocked by SSRF defense.
  • Events — category-grouped checkbox grid (account, domain, ssl, backup, database, email, ftp, dns, plan). At least one event is required: a subscriber of nothing is refused (400 WEBHOOK_VALIDATION), on create and on edit alike. "Select all" / "Select none".
  • Secret — optional; if omitted the server mints a cryptographically random 32-byte token. A secret you supply must be 16–128 printable ASCII characters without whitespace (an empty or shorter value is refused, on create and on edit alike). The secret is shown once in a one-shot reveal dialog after Save — copy it immediately; afterwards the API and the panel show only its last four characters. Subscriber-side HMAC verification uses this secret.
  • Description — free-form label.
  • Enabled / muted_until — soft-mute lets you pause delivery without losing the subscriber row. The dispatcher skips a muted endpoint until the timestamp passes; the value must be ISO-8601 (2030-01-01T00:00:00Z).

An edit is validated as a whole before it is written: a refused change (unknown event, private URL, weak secret, malformed mute timestamp) leaves the stored subscriber exactly as it was, and a subscriber record the server cannot read is skipped with a log line instead of breaking the list or the dispatcher.

Per-row actions: View / Edit / Test-fire / Rotate secret / Delete. Test-fire sends a synthetic event to this endpoint only — other subscribers of the same event do not receive it — and answers 409 WEBHOOK_DISABLED while the endpoint is disabled or muted. A limiter answer (429) on create, edit, test, rotate or delete is reported as an error, never as a success (the dialog stays open), and the agent's reason for a refusal reaches the toast.

Deliveries

Paginated history of every delivery attempt across all endpoints. Filter by endpoint, event, status. Each row exposes the inbound HTTP status, attempts, dispatch payload (click to open detail dialog with full request / response excerpt). While the dispatcher is still retrying, the row already reads Failed with the attempt count and the next attempt time; the final outcome (success or dead-letter) replaces it. Failed deliveries surface a one-click "Retry" button: the event is re-enqueued at the delivery's own endpoint — 404 when that endpoint has since been deleted, 409 WEBHOOK_DISABLED while it is disabled or muted. A failed read of the endpoint list, the event catalogue or the history shows an error state with a Retry button instead of an empty list.

Event catalog (25 events)

Stable, dot-notation identifiers — additive only, never renamed:

text
account.{created,suspended,unsuspended,terminated,package_changed,password_changed}
domain.{added,removed}
ssl.{issued,renewed,failed}
backup.{completed,failed}
database.{created,deleted}
email.{created,deleted}
ftp.{created,deleted}
dns.{record_added,record_updated,record_deleted}
plan.{created,updated,deleted}

The full subscriber-side guide (payload shape, header contract, signature verification with the PHP SDK or by hand) lives in docs/developer/webhooks.md.

Endpoints used: GET /system/webhooks/events, GET/POST /system/webhooks, GET/PUT/DELETE /system/webhooks/{id}, POST /system/webhooks/{id}/rotate, POST /system/webhooks/{id}/test, GET /system/webhooks/deliveries, GET /system/webhooks/deliveries/{id}, POST /system/webhooks/deliveries/{id}/retry.

Still Need Help?

Our support team is here around the clock for anything you can't find above.