Webhooks
Stoaken sends a signed HTTP POST when a release is submitted, published or rejected, so your pipeline can rebuild, notify or deploy.
Set up
Brand Admins add endpoints in Settings > Webhooks (or through the API and MCP). Choose the events, copy the signing secret (shown once), and use Send test to check your receiver. Webhooks are part of the Team plan.
Events
| Event | Sent when |
|---|---|
release.pending_approval | A release is submitted for review. |
release.published | A release is approved and goes live. |
release.rejected | A reviewer rejects a release. |
{
"type": "release.published",
"timestamp": "2026-10-08T09:30:00.000Z",
"data": {
"event_id": "…",
"release_id": "…",
"theme_id": "…",
"brand_id": "…",
"version": "1.4.0",
"status": "published",
"previous_status": "pending_approval",
"is_exception": false
}
}Verify signatures
Deliveries follow Standard Webhooks: headers webhook-id, webhook-timestamp and webhook-signature (v1,<base64 HMAC-SHA256> of id.timestamp.body, keyed by the bytes after whsec_). Any Standard Webhooks library works, or:
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verify(secret, headers, rawBody) {
const id = headers['webhook-id']
const ts = Number(headers['webhook-timestamp'])
if (Math.abs(Date.now() / 1000 - ts) > 300) return false // replay window
const key = Buffer.from(secret.slice('whsec_'.length), 'base64')
const expected = createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest()
return headers['webhook-signature'].split(' ').some((part) => {
const [version, sig] = part.split(',')
const got = Buffer.from(sig ?? '', 'base64')
return version === 'v1' && got.length === expected.length && timingSafeEqual(got, expected)
})
}Retries and health
A delivery counts as received on any 2xx response. Otherwise Stoaken retries with backoff. After repeated final failures an endpoint is switched off automatically; Settings > Webhooks shows why, and turning it back on resumes deliveries. Send test sends a ping event with the same signing.
Rotating secrets
Rotate secret shows a new secret once. For 24 hours deliveries carry two signatures (new and old), so you can update your receiver without missing events.