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

EventSent when
release.pending_approvalA release is submitted for review.
release.publishedA release is approved and goes live.
release.rejectedA reviewer rejects a release.
Body (release.published)
{
  "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:

verify.js (Node)
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)
  })
}
Verify against the raw request body, before any JSON parsing.

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.