How to do it
- Add a webhook Create a webhook with the target URL and the events you want. The URL must resolve to a public address.
- Save the signing secret The secret is shown once. Store it where your receiver can read it.
- Verify each delivery Compute an HMAC-SHA256 of the raw request body with the secret and compare it to the sha256= value in the signature header.
- Send a test Use the test action to send a signed post.published sample.
- Return 2xx quickly Reply with a 2xx status as soon as the delivery is verified, then do the work.
Events
| Event | Sent when |
|---|---|
post.published | A network accepted the post |
post.failed | A publish failed and will not be retried, or was dead-lettered |
approval.requested | A new draft is waiting in the inbox |
Payload
Each delivery is a POST with a JSON body:
{ "id": "…", "event": "post.published", "createdAt": "…", "data": { } }Headers carry the event name and the signature, sha256= followed by the hex HMAC of the raw body.
Retries
Any non-2xx response is retried by the worker. Use the delivery id to ignore repeats, so a retry never triggers your workflow twice. See idempotency.
Private addresses
Webhook targets on loopback, private, or link-local addresses are refused with a 400. Self-hosted servers can allow them with SOCIALHANDOFF_ALLOW_PRIVATE_URLS=1 for testing.
Ideas
- Post
approval.requestedto a team channel so reviewers see new drafts. - Log
post.publishedURLs to a spreadsheet through Zapier or n8n. - Page someone on
post.failed.
Webhooks need Redis on a self-hosted server. The webhook glossary entry explains the basics.