Settings: webhooks¶
Outbound lifecycle notifications: one JSON POST per successful config change.
| Field | Type | Notes |
|---|---|---|
webhooks |
[]WebhookConfig | Outbound lifecycle notifications (below). |
WebhookConfig (webhooks[])¶
| Key | Type | Default | Required | Description |
|---|---|---|---|---|
name |
string | none | yes | Name-safe identifier, used in the status and test endpoints and in logs. |
url |
string | none | yes | Absolute http/https endpoint the event is POSTed to. |
secret |
Secret | none | no | Placeholder-resolved shared secret, sent as the X-GPM-Webhook-Secret header. |
disabled |
bool | false |
no | Keep the target configured without firing it. A disabled target is still reachable through the test endpoint. |
Payload and delivery¶
After every successful config change gpm POSTs a JSON event
{"action","kind","name","commit","time"} to each enabled target. action is one
of save | delete | restore | revert | settings | ingress-discovery | docker-discovery. Delivery is asynchronous
and best-effort under a 10s timeout: a slow or unreachable endpoint never blocks
or fails the config write, it is only logged. Because targets are admin-configured
URLs, delivery is SSRF-bounded as defense in depth: redirects are never
followed (a 3xx counts as a failed delivery, so a receiver cannot bounce gpm to
a URL the admin didn't configure) and link-local destinations are refused at
connect time, post-DNS (blocking cloud-metadata pivots such as
169.254.169.254 even via a rebinding resolver). Private/LAN targets remain
allowed: they are the normal self-hosted case.
Delivery is bounded, and drops rather than queues. At most 8 deliveries are
in flight at once. An event that would exceed that bound is dropped for that
target with a WARN, not queued: delivery is best-effort and must never block
or slow a config write. A target that is consistently dropping events is a
receiver that cannot keep up, not a gpm backlog to drain.
Checking a target. Delivery being fire-and-forget used to make a receiver that had been failing for weeks look identical to a working one:
GET /api/webhooks/status: one row per configured target with the outcome of its most recent attempt (lastAttempt,status,durationMs,ok,error). In-memory and per-process: it is an operational hint, not config, and it resets on restart.POST /api/webhooks/{name}/test: sends a synthetic{"action":"test","kind":"Webhook","name":"<target>","time":"<RFC3339>"}event and waits up to 5s for the answer. A disabled target is still tested, so a receiver can be proved before it is turned on. A refused or timed-out delivery comes back as200withok: false; only an unknown target name is a404.