Skip to content

Webhooks ​

A webhook is a subscription to log events: the server posts each matching event to an HTTPS receiver you name, as signed JSON, with retries. It is the "wake me up" half of the automation contract: an orchestration tool or an AI agent no longer polls the server, the server calls it. Webhooks are available from release 8.9.0 and need the automation license capability (Professional and Ultimate).

Every log record the server writes that carries an event ID can be delivered. The record travels untouched inside an envelope, so a receiver gets exactly what the log holds, plus the context it needs to tell nodes, processes and sites apart.

Two scopes ​

  • Global webhooks are created by SuperAdmins and see every event on the node: the console's own records and those of every virtual site.
  • Site webhooks are created by a virtual site's Admins (permission Webhooks) and see only that site's events. SuperAdmins may list a site's webhooks for oversight but do not manage them.

A dispatcher runs in every process of the product: the management console and each virtual site's worker. A worker delivers its own records to the global webhooks and to its site's; the console delivers the console's records to the global webhooks and the site records it writes itself (operator changes, for example) to the matching site webhooks. In a cluster every node delivers on its own, so the same replicated change can produce one delivery per node; the envelope's node field tells them apart.

Selecting events ​

A webhook names the events it wants as a list of event IDs, a list of whole blocks (1000, 2000, ... 9000), or both. A block subscription also covers the events a later release adds to that block. A minimum level drops records below it even when their event is selected; the default is info.

The registry of IDs, names, levels and fields is served by the API at GET /api/v1/sa/events/catalog and GET /api/v1/adm/events/catalog, and printed in Log event IDs.

The delivery ​

POST <url>
Content-Type: application/json
User-Agent: SyncplifyServer-Webhook/<version>
X-Syncplify-Timestamp: <unix seconds>
X-Syncplify-Signature: <hex HMAC-SHA256 of "<timestamp>.<body>" with the webhook secret>
X-Syncplify-Event: 3102
X-Syncplify-Event-Name: SignInWrongPassword
X-Syncplify-Delivery: <delivery ID, the same across the retries of one delivery>
X-Syncplify-Webhook: <webhook ID>
X-Syncplify-Node: <node ID>
Authorization: <the configured authorization header, when set>
json
{
  "specVersion": 1,
  "deliveryId": "3LEwTzTbcNyhubUyD4dA8EAkwiY",
  "attempt": 1,
  "eventId": 3102,
  "event": "SignInWrongPassword",
  "level": "warn",
  "time": "2026-10-26T15:04:05.123Z",
  "node": "node1",
  "process": "ss-wrk-default",
  "vsite": "default",
  "webhook": { "id": "...", "name": "ops", "scope": "global" },
  "record": { "...": "the log record exactly as written" }
}

specVersion changes only when a field changes meaning; new fields may appear at any time. time is when the dispatcher saw the record, in UTC; the record's own time field is the logger's. process is ss-webrest for the console and ss-wrk-<site> for a worker. vsite is the site the record belongs to, empty for a record of the console that belongs to no site.

Verifying a delivery ​

Compute HMAC-SHA256 over the string <timestamp>.<body> with the webhook secret, compare it in constant time with X-Syncplify-Signature, and refuse a timestamp older than a few minutes. Use X-Syncplify-Delivery to ignore a retry of a delivery you already processed.

What the receiver answers ​

Receiver's answerWhat the server does
Any 2xxDelivered.
408, 425, 429, any 5xx, no responseTried again with exponential backoff (one second doubling up to one minute), up to the webhook's retries.
Any other status, including a redirectGiven up at once. Redirects are never followed.

A delivery that was given up is kept on the node that attempted it, with the status, the error and the number of attempts, for the policy's retention period; the consoles show it under the webhook's deliveries, with the node's counters (delivered, failed, dropped). A WebhookDeliveryFailed event (9070) is written at most once a minute per webhook. The record about a webhook is never delivered to that webhook, so a failing receiver cannot produce an endless chain of failures about itself.

Ordering is not guaranteed. Each webhook has a bounded queue on each node (the webhook's queue size); when a receiver is slower than the events arrive the newest records are dropped, counted, and a WebhookQueueOverflow event (9071) is written at most once a minute. Records over 64 KiB are not delivered.

Receivers the server refuses ​

A webhook URL must be absolute and use HTTPS. The policy (Global Configuration, Advanced settings, Webhooks) may allow plain HTTP, and may allow private or link local addresses; a webhook that wants a private receiver must ask for it as well, so that both the SuperAdmin and the webhook's owner agreed. Loopback is never admitted, whatever the policy says. The check happens on the address actually dialed, every time: a name that resolves to a public address when the webhook was saved and to a private one later is refused at that moment. The server never follows a redirect and never uses a proxy for deliveries.

Testing a webhook ​

The consoles offer a test delivery: a WebhookTest event (9072) is sent to that one webhook, once, with the same signature, headers and client rules as a real delivery, and the receiver's answer is shown with the latency. The event is written to the log too, so other webhooks subscribed to it receive it as well. The API route is POST .../webhooks/{id}/test.

The API ​

Both planes offer the same routes under /api/v1/sa and /api/v1/adm: GET and POST /webhooks, GET, PUT and DELETE /webhooks/{id}, POST /webhooks/{id}/test, GET /webhooks/{id}/deliveries, and GET /events/catalog. SuperAdmins also have GET /vsites/{id}/webhooks. Creating and updating support dry runs, creating takes an idempotency key, reads carry an ETag and writes honour If-Match. Secrets are never returned: an answer carries them redacted, and an update that sends them back redacted keeps the stored ones.

A webhook is created enabled with three retries unless the body says otherwise. The per scope limit, the retention of delivery records and the largest queue a webhook may ask for are set in the policy.