Webhooks
Webhooks are the meta-integration. Subscribe a URL to specific events (or all events), and Drumroll POSTs a signed JSON payload to it the moment those events happen. Pair with Zapier, n8n, Make, IFTTT, or your own server to wire Drumroll into anything we don't ship natively.
Create a subscription
- Open Settings → Integrations in your workspace admin.
- Scroll to the Webhooks card.
- Click Add webhook.
- Paste your receiver URL. Must be https (or http://localhost for testing).
- Optionally label it (e.g. "Production Zapier", "Slack bridge").
- Pick which events should fire it. Leave all unchecked to subscribe to every event - including ones added later.
- Submit.
The signing secret is shown exactly once, on creation. Copy it immediately to your receiver's environment variables. If you lose it, delete the webhook and create a fresh one - we can't show it again.
Payload shape
Every event is delivered as JSON in this envelope:
{
"event": "entry.published",
"delivered_at": "2026-05-14T03:14:00.000Z",
"data": {
"entry": {
"id": "01H8…",
"title": "v1.4 launch",
"bodyHtml": "<h2>New features</h2>…",
"tags": ["release"],
"entryDate": "2026-05-14",
"publicUrl": "https://acme.usedrumroll.com/changelog#entry-…"
}
}
}
For guide.published, data is { guide: { id, title, slug, bodyHtml, tags, publicUrl } }. For the test event, data is { workspace_name }.
Headers
Content-Type: application/jsonX-Drumroll-Event- the event kind, same as theeventfield in the bodyX-Drumroll-Signature-sha256=<hex>, where<hex>is the HMAC-SHA256 of the raw request body using your signing secret as the key
Verifying the signature
Always verify before acting. Otherwise an attacker who guesses your endpoint URL could feed your system fake events.
Node.js
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(
Buffer.from(header),
Buffer.from(expected),
);
}
Python
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(header, expected)
Bash (for quick debugging)
echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex
# prepend "sha256=" and compare to X-Drumroll-Signature
Verify against the raw request body, not the parsed JSON. JSON re-serialization in your language won't produce byte-identical output, which breaks the HMAC.
Retry semantics
- 10-second timeout per attempt.
- Up to 3 attempts total per delivery.
- Backoff between attempts: 1 second, then 5 seconds.
- 4xx responses are treated as permanent failures - no retry. Fix the receiver and re-fire via the test button.
- 5xx responses and network errors retry up to the attempt cap.
- After the cap, the delivery is marked
failed_permanentlyand visible in the admin UI for that webhook.
Test before relying on it
Each webhook row in the admin UI has a Send test button. It dispatches a synthetic test event (no real entry/guide data) and surfaces the receiver's HTTP response inline. Use this to confirm signature verification works before you publish real events.
Idempotency
Drumroll doesn't currently send an idempotency key on retries. If your retry policy hits (the receiver returned 5xx on the first attempt but the work succeeded), you might get duplicate deliveries. Receivers should be idempotent on the entry.id / guide.id field.
Rotating a signing secret
v1 doesn't support in-place rotation. To rotate: create a new webhook with the same URL and event filter, copy the new secret to your receiver, delete the old webhook. Update receiver code if needed to accept both old and new signatures during the cutover window.