Integrations & webhooks — connect StaticOwl to other systems

StaticOwl has three ways to wire your site to the systems around it:

Direction Use it for
Integrations Outbound A simple "when X happens, post to Slack / Discord / a webhook" rule.
Outbound webhooks Outbound Signed, retried event delivery to your own endpoint.
Inbound webhooks Inbound Let an external system POST events into your site.

All three are site-scoped and admin-gated. Outbound delivery is best-effort — a failing endpoint is counted, never allowed to break a publish or a visitor's request.


Integrations — "when X happens, do Y"

An integration binds a trigger (a site event) to a destination (Slack, Discord, or a generic webhook) with a URL and an optional message template. When the event fires, StaticOwl posts a formatted message to the destination.

Triggers

An integration can listen for any of these events:

Destinations

The message text is a default summary of the event, or — if you set a template — your own string with {{field}} placeholders filled from the event ({{event}} plus the payload fields). The destination URL must be https://.

Create one

curl -X POST https://app.staticowl.com/api/integrations \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: site:mysite" \
  -H "Content-Type: application/json" \
  -d '{"type":"slack","trigger":"form.submitted","url":"https://hooks.slack.com/…",
       "template":"New submission on {{page}}: {{email}}"}'

GET /api/integrations/meta returns the valid triggers and types. Posting the same rule again (same id) overwrites it.

Test and verify

API and MCP reference

Route MCP tool
GET /api/integrations/meta integrations_list_types
GET /api/integrations integrations_list
POST /api/integrations integrations_create
PUT /api/integrations/{id}/enabled integrations_toggle
DELETE /api/integrations/{id} integrations_delete
POST /api/integrations/{id}/test integrations_test
GET /api/integrations/{id}/deliveries integrations_deliveries

Outbound webhooks

An outbound webhook is a raw, signed event feed to your own endpoint. Where an integration formats a message for Slack or Discord, a webhook delivers the event as JSON and lets you decide what to do with it — and it is retried on failure.

Subscribe

curl -X POST https://app.staticowl.com/api/webhooks \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: site:mysite" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hook","events":["content.published","site.deployed"],"secret":"my-shared-secret"}'

Events StaticOwl fires include: content.published, content.unpublished, deployment.deployed, deployment.rolled_back, site.deployed, feedback.created, newsletter.subscribed, comment.created, consent.withdrawn, consent.config_changed, dsar.submitted, dsar.completed, data.deleted, and form.submitted. Subscribe to ["*"] if you want to receive new event types as they're added.

The delivery

Each delivery is a POST with a JSON body:

{
  "event": "content.published",
  "siteId": "site:mysite",
  "at": "2026-10-16T12:00:00.000Z",
  "data": { "...": "event-specific fields" }
}

with two headers:

Retries

Delivery is retried with exponential backoff (plus a little jitter) on transient failures — a network error, a timeout, HTTP 429, or any 5xx. A non-2xx 4xx (the receiver rejected the payload) is treated as permanent and not retried. Dispatch runs detached from the request that triggered it, so retries never delay a visitor.

API and MCP reference

Route MCP tool
GET /api/webhooks webhooks_list
POST /api/webhooks webhook_create
DELETE /api/webhooks/{id} webhook_delete

Inbound webhooks

An inbound webhook is a receiver external systems POST into — the reverse of an outbound webhook. Use it to push events from another tool into your site.

Create a receiver

curl -X POST https://app.staticowl.com/api/webhooks/inbound \
  -H "Authorization: Bearer $STATICOWL_API_KEY" \
  -H "X-Site-Id: site:mysite" \
  -H "Content-Type: application/json" \
  -d '{"name":"Orders from Shopify","slug":"shopify-orders"}'

The response includes the signing secret — shown once, at creation. Record it now; it isn't retrievable later. The slug is lowercase letters, digits, and hyphens (1–42 characters) and becomes part of the public receiver URL.

The public URL and signing

External systems POST to:

POST https://app.staticowl.com/api/hooks/<siteId>/<slug>

There's no API key or token on this URL — the signature is the authentication. The caller signs the raw request body with HMAC-SHA256 using the receiver's secret and sends it as:

X-Webhook-Signature: sha256=<hex>

The receiver verifies the signature against the exact body bytes and responds:

Every event is stored with its payload (up to 200 KB) and the X-* and content-type request headers, so you can inspect exactly what arrived.

Manage, inspect, and replay

API and MCP reference

Route MCP tool
GET /api/webhooks/inbound webhook_inbound_list
POST /api/webhooks/inbound webhook_inbound_create
DELETE /api/webhooks/inbound/{id} webhook_inbound_delete
POST /api/webhooks/inbound/{id}/rotate-secret webhook_inbound_rotate_secret
GET /api/webhooks/inbound/{id}/events webhook_inbound_events
POST /api/webhooks/inbound/events/{eventId}/replay webhook_inbound_replay

See also

Related docs

Resolved at build time via {% similar %} — cosine similarity over embeddings, not tag overlap. Zero arguments.

Forms — collect submissions from any page
67% match
Distribution — web push & scheduled social posts
65% match
HTTP API
64% match