Set up webhooks for content events
How to wire SGEN content events to an outbound destination, with retry and a delivery log to debug from.
Webhooks let outside systems react to what happens inside SGEN. When a page publishes, a post saves, a form submits, or a user signs in for the first time, SGEN can send a small message to a URL you control. The system at the other end picks up the message and does whatever it needs to do — push a notification to a team channel, refresh a search index, mirror the change into a CRM, trigger a downstream build.
The page walks the full configuration cycle. Picking the event types that matter, pointing each event at the right destination, watching what gets delivered, and recovering when a destination is down.
What is this for?
Use this page when you need to send SGEN events to another system. Common destinations are a team-channel notification surface, a serverless function, an automation tool, an internal listener the team runs, or a search index that needs to know when content changed.
The page covers the customer-facing webhook surface — event catalog, destination configuration, delivery rules, and the debug log. It does not cover the inbound direction (other systems calling SGEN); that is the Integrations Reference surface and lives in a separate page.
Webhooks fit best for asynchronous, fire-and-forget integrations where the receiver does not need to block the SGEN action that produced the event. For synchronous, blocking handoffs, the integration shape is different — see the Integrations Reference for the right pattern there.
Good use cases
- A team channel needs a message every time a blog post publishes, with the post title and the public URL.
- An internal CRM needs a contact record created the moment a form submits.
- A search index needs an invalidation signal when a page updates.
- An external monitoring service needs to know when a site's settings change.
- A staging-to-live release needs a downstream build triggered when the site moves out of maintenance state.
What NOT to use this for
- Pulling data on a schedule. Webhooks fire on events, not on a clock. For a scheduled pull, use the read API on a cron the receiver controls.
- Heavy data transfer. Webhook payloads are intentionally small. If a downstream system needs the full body of a post, the payload carries the ID and the system fetches the body via API.
- High-stakes synchronous flow. Webhooks are at-least-once, asynchronous. A receiver that must respond before the SGEN action proceeds is the wrong pattern; that needs a different integration shape.
How this connects to other features
- Integrations Overview — the parent page for every outbound and inbound integration surface.
- Automation Trigger Model — the shared event model that webhooks subscribe to.
- Integration-Driven Automation — internal automations that respond to the same events without leaving SGEN.
- Audit Log — webhook configuration changes and delivery summaries appear here.
Scope
This page covers the customer-facing webhook surface — event catalog, destination configuration, delivery rules, retry policy, and the delivery log. It applies to outbound webhooks only (SGEN fires events to an external URL). Inbound direction (other systems calling SGEN) is covered in the Integrations Reference. Webhooks are scoped per site; account-wide configuration is not available.
Before you start
- You are signed in as a user with integrations-admin permission on the site.
- The destination URL accepts secure requests and returns a successful response within the delivery timeout.
- A shared secret is ready, if you intend to sign requests for receiver-side verification.
- The receiver is prepared for at-least-once delivery — duplicate messages must be idempotent on the receiving end.
- The receiver's expected message shape is documented somewhere the team can reach, so the wiring on both sides matches without guesswork.
Where to find it
Open the admin → Integrations → Webhooks. The page opens to the webhook index, listing every configured webhook on the site with its name, the events it subscribes to, the destination URL host, and the last-delivery status.
A second surface, Delivery Log, sits as a tab on the same page. It shows every delivery attempt across every webhook, with filters for event type, status, and date range.
For a portfolio of sites, each site carries its own Webhooks surface — webhooks are scoped per site, not org-wide. A team that wants the same integration across many sites configures each site separately, ideally using a documented template so the wiring stays consistent.
Steps
The setup cycle has four parts — create the webhook, pick the events, configure delivery and retry, and read the log to confirm. The steps below cover a fresh setup from scratch.
1. Create a webhook
From the Webhooks index, click New Webhook in the top right. The configuration panel opens.
Enter a Name that describes the integration in human language — slack-#editorial, crm-contact-mirror, search-index-invalidation. The name appears in the index and the log; it is for operator clarity and is not sent to the destination.
Enter the Destination URL. SGEN accepts HTTPS destination URLs; non-secure URLs are rejected at save. The host is shown abbreviated in the index, so the full URL stays on the configuration page.
Optionally enter a Shared Secret. When present, SGEN signs every request with this secret and includes the signature in the request header. The receiver verifies the signature to confirm the request came from SGEN. The secret never leaves the configuration page; it is stored encrypted and cannot be retrieved after save — only replaced.
Click Save Draft. The webhook now exists in the index with status Draft — no events selected. Configuration of events happens in the next step.
For team coordination, the index also shows a created-by attribution on the row. The Audit Log carries the same record so a reviewer can trace who set up a webhook and when.
2. Pick the event types
Open the webhook from the index. The detail panel opens with the Events tab selected.
The event catalog is grouped by source. The customer-facing groups are:
- Content —
page.published,page.updated,post.published,post.updated,post.deleted,template.updated. - Commerce —
order.created,order.paid,order.refunded,product.updated,product.out_of_stock. - Identity —
user.created,user.deactivated,user.role_changed,user.first_sign_in. - Forms —
form.submitted,form.fields_changed. - Site state —
site.entered_maintenance,site.left_maintenance,site.settings_changed. - Backups —
backup.completed,backup.failed,restore.completed.
Tick the events the destination cares about. Tick as few as possible — every event sent is delivery cost, log entries, and noise on the receiving side. A typical team-channel notification subscribes to two or three events, not the whole catalog.
Click Save Events. The webhook moves from Draft to Active. The next time any subscribed event fires, the webhook delivers.
For event types that need additional context — such as the field-level diff on a page.updated — tick the Include detail payload option on the same panel. The detail payload increases message size but reduces the lookups the receiver has to do. Match the option to the receiver's preferred shape.
3. Configure delivery and retry
Open the Delivery tab on the webhook detail.
Timeout sets how long SGEN waits for the destination to respond before marking the attempt as failed. Default is 10 seconds. Maximum is 30 seconds. Shorter is better — a slow receiver should accept the request and process it asynchronously, not hold the connection open.
Retry Policy controls what happens after a failed attempt. The default is exponential backoff with five retries, spaced at 30 seconds, 2 minutes, 10 minutes, 1 hour, and 6 hours. After the fifth failure, the delivery is marked Permanently failed and surfaces on the index as an alert.
Failure mode sets how SGEN behaves when a webhook is in a failing state. The two options are Continue (keep sending new events even while old ones retry) and Pause (stop sending new events to this webhook until the operator clears the alert). Use Pause when delivery order matters; use Continue for fire-and-forget destinations.
Headers lets you add fixed headers that every request to this destination carries — useful for routing hints, tenant identifiers, or destination-side dispatch values. Headers are stored encrypted on save.
Click Save Delivery. The new policy applies to all future deliveries; in-flight retries continue under the policy that was active when they started.
4. Read the log and debug a failed delivery
Open the Delivery Log tab on the Webhooks page. The log shows the most recent deliveries across every webhook, newest first. Each row carries the timestamp, the event type, the webhook name, the destination host, the response indicator returned by the destination, and the delivery state — Delivered, Retrying, Permanently failed.
Use the filter row to narrow. Status filters to permanent failures, retries, or successful deliveries. Event narrows to one event type. Webhook scopes to a single configured webhook.
Click a row to expand the delivery. The expanded view shows the request body that was sent, the request headers, the response body the destination returned, the response indicator, and the timing breakdown — request prepared, sent, response received, total elapsed.
For a permanent failure the most useful field is the response body the destination returned on the last attempt. Common patterns and fixes:
- Response is an authentication-related rejection → the shared secret or auth header is wrong. Update the configuration.
- Response indicates the destination is unhealthy → wait, then click Retry on the row to attempt manual redelivery.
- Response is empty and timing shows the timeout was hit → the destination did not respond in time. Raise the timeout, or speed up the receiver.
- No response and timing shows network unreachable → the destination URL is wrong, or name-resolution for the host fails from the platform. Confirm the host resolves.
After a fix, click Replay on a permanently failed row. SGEN re-sends the original payload as a new delivery; the original row stays in the log as historical evidence.
The Delivery Log also supports an Export action. Use it to capture a slice of delivery history for the team's own archive, especially after a significant incident worth preserving in detail.
What success looks like
A webhook is correctly configured when the index shows it as Active, the Delivery Log shows recent successful deliveries, and the destination system confirms it received the expected payloads.
A debugging session is successful when the failed delivery has a clear cause noted on the row, the underlying issue is fixed, and a Replay returns a successful response.
A healthy long-running webhook also shows a steady cadence in the log. If the cadence is wildly inconsistent — long quiet stretches followed by bursts — investigate whether the upstream event is firing as expected. Steady cadence is the simplest health signal you can read at a glance.
What to do if it does not work
- **No deliveries arrive at the destination, but the index shows Active.**
Confirm the webhook subscribes to at least one event that fires. A webhook with no events selected stays Active and silent. Open the Events tab and confirm.
- Deliveries fail with an authentication-related rejection.
The shared secret or auth header is wrong, or the destination has changed its verification. Rotate the secret on both sides; replay the failed deliveries after the fix.
- Deliveries time out intermittently.
The destination is slow under load. Raise the timeout in Delivery settings or change the receiver to accept and process asynchronously.
- Receiver is processing the same event twice.
Webhooks are at-least-once. The receiver must deduplicate by event ID, which is included in every payload. Add idempotency on the receiver side.
- A site is generating thousands of deliveries per day.
A high-volume event such as page.updated may be unintended. Narrow the subscription to a smaller set, or batch on the receiving side.
- Replay produces a duplicate side effect on the receiver.
The receiver is not deduplicating by event ID. Add an ID check on the receiving side; once deduplication is in place, Replays are safe to run as often as needed.
- Headers added in configuration do not appear on the receiving side.
Confirm the header name is one the receiver accepts. Some receiver platforms strip or rename headers in flight. Switch to a header name the receiver recognizes, then save.
- Webhook keeps moving to Pause state on its own.
Failure mode is set to Pause and the delivery error rate is crossing the auto-pause threshold. Open Delivery Log, fix the root cause of the failures, then clear the pause from the webhook detail panel.
Examples
Example A — team-channel notification on blog publish. Operator creates a webhook named slack-#editorial. Destination URL is the team-channel incoming-webhook URL. Subscribed events: post.published. Delivery timeout 10 seconds, default retry, failure mode Continue. The first blog post publishes; the Delivery Log shows a successful response in 380 milliseconds; the team channel shows the post title and URL within two seconds of publish.
Example B — CRM mirror on form submission. Operator creates a webhook named crm-contact-mirror. Destination is the internal listener URL of a CRM. Shared secret is set; the CRM verifies the signature. Subscribed events: form.submitted. Failure mode Pause — the team prefers to fix the CRM first, then replay rather than lose ordering. A CRM outage causes five permanent failures; the operator fixes the CRM, opens the Delivery Log, and clicks Replay on each row in chronological order. The CRM receives them in submission order with no duplicates because the CRM dedupes by event ID.
Example C — search-index invalidation across many event types. Operator creates a webhook named search-index-invalidation. Destination is a serverless function that triggers a reindex. Subscribed events: page.published, page.updated, post.published, post.updated, post.deleted, template.updated. Custom header carries a routing value. Delivery timeout 5 seconds — the serverless function accepts and queues. The function returns an accepted response within 150 milliseconds on every event, and the search index stays fresh.
Example D — order-paid mirror into an accounting system. A commerce operator wires order.paid events to an automation tool that creates a draft entry in their accounting system. The webhook destination is the automation tool's listener URL; the shared secret is set on both sides; failure mode is Pause because order ordering matters. The first paid order produces a successful delivery in 420 milliseconds. A week later the accounting system is briefly unreachable; six events queue into retry. When the system recovers, the retries deliver in order; the operator's accounting matches the order log with no missing entries.
Example E — maintenance-window broadcast across team channels. A multi-team agency needs every team channel to know when a managed site enters or leaves maintenance. The operator creates two webhooks — one per team channel — each subscribed to site.entered_maintenance and site.left_maintenance. Custom headers route the messages to the right channel topic on the receiving end. The Delivery Log confirms successful delivery to both channels every time a maintenance window opens or closes. The team channels carry consistent, near-real-time visibility without anyone polling the dashboard.
Plan for high-volume and multi-site webhook deployments
A single webhook on a small site is a comfortable setup. A portfolio of busy sites, each with several webhooks, is a different scale of operation. The mechanics stay the same; the planning gets sharper.
Volume budgeting
Estimate the delivery volume before you turn a webhook on. The number of deliveries per day equals the number of subscribed events times the daily event rate on the site. A busy publishing site that fires page.updated on every editorial save can generate thousands of events per day. Multiply by the number of webhooks subscribed to that event and the receiving side is now responsible for tens of thousands of messages.
For volumes above a few thousand deliveries per day per destination, plan the receiving side around queue-and-process rather than fan-out. The destination accepts the message in milliseconds, queues it, and processes asynchronously. This shape protects against retries-piling-on-retries during a downstream slowdown.
For volumes that would spike during launches — large product imports, bulk content rebuilds, mass template updates — coordinate the spike with the receiving team. A search reindex listener that handles fifty events per minute on a normal day may stall at five hundred per minute during a bulk republish. Either dial back the subscription temporarily or schedule the bulk action for a quiet window.
Receiver-side resilience
The webhook subsystem is the SGEN side of the contract. The other side — the receiver — has to hold up its end. Three habits keep receivers healthy.
First, deduplicate by event ID. Every payload carries a stable event ID. The receiver records the IDs it has already processed and ignores repeats. This single habit removes the entire class of at-least-once duplicate failures.
Second, return fast. A receiver that takes ten seconds to respond is a receiver that will time out under load. The pattern is: accept the request, return a successful response indicator, and process asynchronously on the receiver's own schedule.
Third, monitor the failure rate. The Delivery Log carries the signal, but the receiver should also carry its own metric — accepted messages per minute, processed messages per minute, queue depth. A growing gap between accepted and processed is the early warning that the receiver cannot keep up.
Multi-site portfolio rollouts
For an agency rolling the same integration across many sites, the org-level approach saves time. The pattern: build the integration on one pilot site, validate the Delivery Log for one full week, then replicate to the rest of the portfolio with the same configuration. Use the per-site Webhooks surface to register the same destination URL, the same events, and the same delivery policy on each site.
For receivers that need to know which site sent which event, include the site identifier in a fixed header or as part of the destination URL path. The receiver routes incoming messages to the right per-site processing without having to parse payloads.
Decommissioning a webhook
Webhooks accumulate over time as integrations come and go. A site that has run for several years can carry webhooks the team no longer remembers wiring. Run a yearly cleanup — open the index, sort by last-delivery timestamp, and remove any webhook that has not delivered in the last quarter. The cleanup keeps the surface small and the Audit Log clean.
To decommission a webhook, open it from the index and click Pause first. Wait for any in-flight deliveries to settle. Confirm the receiver is no longer expecting messages. Click Delete Webhook. The configuration is removed; the historical log entries remain, so the evidence of what the webhook did is preserved.
Reference — payload shape and signature header
Every webhook delivery carries a small, consistently shaped message. The shape below is the canonical reference for what the receiver reads.
{"event_id": "evt_2026_05_22_a4b1c9d2","event_type": "post.published","fired_at": "2026-05-22T14:03:18Z","site": {"id": "site_yoursite","slug": "yoursite","host": "yoursite.com"},"actor": {"id": "user_ada","email": "ada@yoursite.com"},"target": {"type": "post","id": 4421,"title": "Spring 2026 product update","url": "https://yoursite.com/blog/spring-2026-product-update"}}When a shared secret is set, SGEN signs every request with an X-SGEN-Signature header. The signature is a hex-encoded HMAC of the raw request body using the shared secret. A receiver verifies by recomputing the same HMAC over the incoming body and comparing.
A typical receiver-side verification reads as follows.
header X-SGEN-Signature t=1716394998,v1=8a3f...e0c4header X-SGEN-Event post.publishedheader X-SGEN-Event-Id evt_2026_05_22_a4b1c9d2header X-SGEN-Delivery dlv_5c2a91The t= value is the delivery timestamp. The v1= value is the signature. Receivers reject any request where the timestamp is older than five minutes; this prevents an old captured payload from being replayed by anything that is not SGEN.
Reference — event catalog populated table
The catalog below lists every customer-facing event with its typical use, shown for a typical SGEN site.
| Event family | Event type | Fires when | Typical receiver action |
|---|---|---|---|
| Content | page.published | A page moves from draft to live | Reindex search, ping team channel |
| Content | page.updated | A live page is edited and saved | Reindex search, update CDN tag |
| Content | post.published | A blog post publishes | Post to #editorial, email subscribers |
| Content | post.updated | A live post is edited | Reindex search |
| Content | post.deleted | A post is removed from the index | Remove from search, remove from feed |
| Content | template.updated | A theme template changes | Trigger downstream rebuild |
| Commerce | order.created | A new order is placed (any state) | Notify fulfillment, write to ledger |
| Commerce | order.paid | Payment captured on an order | Create accounting entry, notify shipping |
| Commerce | order.refunded | Refund issued on an order | Adjust ledger, notify customer service |
| Commerce | product.updated | A product changes (price, variant, copy) | Reprice external storefront, refresh cache |
| Commerce | product.out_of_stock | A product hits zero stock | Pull from external listings, alert buyer |
| Identity | user.created | An account is created on the site | Mirror to CRM, send welcome email |
| Identity | user.deactivated | An account is deactivated | Revoke external access, archive |
| Identity | user.role_changed | A user's role changes | Sync permissions to external systems |
| Identity | user.first_sign_in | A user signs in for the first time | Trigger onboarding sequence |
| Forms | form.submitted | A site form is submitted | Create CRM contact, notify owner |
| Forms | form.fields_changed | A form definition is edited | Refresh downstream schemas |
| Site state | site.entered_maintenance | Site enters maintenance mode | Broadcast to team channels |
| Site state | site.left_maintenance | Site exits maintenance mode | Confirm restored to team channels |
| Site state | site.settings_changed | A site setting is edited | Audit-trail mirror, refresh dependent systems |
| Backups | backup.completed | A backup reaches Ready | Update backup-status dashboard |
| Backups | backup.failed | A backup fails | Alert on-call |
| Backups | restore.completed | A restore finishes | Notify team, validate site |
Reference — populated delivery log row
A delivery row in the log carries the same fields the API does, in a compact shape.
| Field | Example value |
|---|---|
| Delivery ID | dlv_5c2a91 |
| Webhook | slack-#editorial |
| Event type | post.published |
| Destination host | hooks.slack.com |
| State | Delivered |
| Response | 200 OK (success indicator) |
| Latency | 380 ms |
| Attempt | 1 of 5 |
| Triggered at | 2026-05-22 14:03:18 UTC |
| Actor | ada@yoursite.com |
The same shape carries through to the expanded detail panel. A failed row replaces the response indicator with the destination's rejection message and the state with Retrying or Permanently failed.
Reference — recommended timeout and retry pairings
A short table to size delivery policy by receiver type.
| Receiver type | Recommended timeout | Retry policy | Failure mode |
|---|---|---|---|
| Team-channel notification (Slack, Teams) | 10 s | Default exponential | Continue |
| Serverless function (accept-and-queue) | 5 s | Default exponential | Continue |
| CRM listener (write to system of record) | 15 s | Default exponential | Pause |
| Accounting mirror (financial system) | 15 s | Default exponential | Pause |
| Search reindex worker | 5 s | Default exponential | Continue |
| Internal monitoring webhook | 10 s | Aggressive (3 retries, 30 s apart) | Continue |
| Legacy on-prem listener | 30 s | Default exponential | Pause |
Pair the policy to the cost of a duplicate, not to a single ideal. A receiver where duplicates are free (search reindex) can run Continue. A receiver where duplicates create a real problem (accounting double-entry) needs Pause and a receiver-side idempotency check.
Common questions about webhooks
How quickly does a webhook fire after the event? Within a few seconds for most events. The webhook subsystem queues the event the moment it is recorded, and delivery starts almost immediately. Heavy load on the receiving side can stretch the perceived delay; the SGEN side is consistently fast.
Are webhooks signed? Only when a shared secret is configured on the webhook. With a secret, every request carries a signature header that the receiver verifies. Without a secret, requests are unsigned. For any destination that processes content changes or money flow, set a shared secret.
What if the destination URL has to change? Open the webhook, update the Destination URL, click Save. Future deliveries route to the new URL. In-flight retries from before the change use the old URL one more time, then move to the new URL on subsequent retries. If you want every retry to use the new URL immediately, mark the failed deliveries as resolved and Replay them under the new URL.
Can a webhook send the full body of a post? No. Payloads are intentionally small and carry the IDs and key fields, not the full content body. The receiver looks up the full body via the read API when it needs it. This shape keeps webhook delivery fast and avoids encoding large payloads in flight.
How are secrets rotated? Open the webhook configuration, enter a new value in the Shared Secret field, save. The new secret applies to all future deliveries. Coordinate the rotation with the receiver — both sides need to switch at the same moment, or set up the receiver to accept either the old or the new secret for a short overlap window.
Where do I see delivery history older than the visible Log? The Delivery Log retains entries for the platform-baseline window. For longer-horizon history, schedule a regular export from the log; the exports stay available for download for seven days each. For evidence-grade retention, copy the exports to the team's own archive on the cadence that matches the retention obligation.
