Webhook secret rotation: no downtime with a 24-hour window
After you rotate a Sume webhook signing secret, deliveries carry two signatures for 24 hours. What the header looks like and how to redeploy safely.

Rotating a webhook secret without downtime means both the old and the new secret verify for a while. Sume does this for you: for 24 hours after you rotate, it signs every delivery with both secrets and sends both signatures in one header, newest first. A receiver holding either secret passes, so you redeploy on your own schedule.
The steps below come from the Sume Verifying webhooks and Webhooks docs, read 2026-09-29. They apply to job webhooks and to run webhooks, which share one signing secret.
How do I rotate a Sume webhook signing secret?
Use **Webhooks, then Rotate secret** in the dashboard, or POST /v1/webhooks/signing-secret/rotate with an API key that carries account:write. Read the current secret on the dashboard Webhooks tab or from GET /v1/webhooks/signing-secret with a key that carries account:read.
- Before you rotate, check that your receiver accepts a header with several
sume-v1=entries (see the next sections). - Rotate. Both API responses carry
rotation.previous_valid_until, the deadline of the window; the dashboard shows it too. - Read the new secret and deploy it to your receiver's secret store as
SUME_COM_WEBHOOK_SIGNING_SECRET. - Watch deliveries verify against the new secret, then stop worrying: after the window the old secret stops verifying.
curl -X POST https://api.sume.com/v1/webhooks/signing-secret/rotate \
-H "Authorization: Bearer $SUME_API_KEY"What does the header look like during the window?
Outside a window Sume sends exactly one signature. During a window the x-sume-webhook-signature header lists one entry per live secret, newest first, separated by commas.
| Moment | What Sume sends |
|---|---|
| No rotation in progress | sume-v1=<hex> |
| Within 24 hours of a rotation | sume-v1=<new>,sume-v1=<old> |
| After the window | One signature again; the old secret no longer verifies |
| Fingerprint header | x-sume-webhook-secret-fingerprint names the new secret from the moment you rotate |
Why does my verifier fail only during rotation?
A hand-rolled verifier that compares the whole header to one expected string fails every delivery while two entries are present. The docs say to upgrade the receiver before you rotate. The docs say verifyWebhook in @sume-com/sdk 0.2.0, which they call the current release, already handles the multi-signature header.
The fix is to split the header on commas, keep the entries that start with sume-v1=, and accept the delivery if any one matches. Compare every entry in constant time, over the raw body, and refuse to run with an empty secret: an empty HMAC key would let a forged signature pass.
import hashlib, hmac, time
def verify(raw: bytes, timestamp: str, header: str, secret: str) -> bool:
if not secret:
raise ValueError("empty signing secret")
try:
ts = int(timestamp)
except ValueError:
return False
if abs(time.time() - ts) > 300:
return False
mac = hmac.new(secret.encode(), f"{ts}.".encode() + raw, hashlib.sha256)
want = ("sume-v1=" + mac.hexdigest()).encode()
ok = False
for entry in header.split(","):
ok |= hmac.compare_digest(entry.strip().encode(), want)
return okHow do I know which secret my receiver holds?
Compare fingerprints. The dashboard shows a fingerprint beside the secret, and every delivery carries the same kind of value in x-sume-webhook-secret-fingerprint; it is safe to paste into a ticket. During a window the header names the new secret, so it tells you which secret to move to, not which ones are still accepted.
What if the secret leaked?
Rotating twice inside one window retires the secret two rotations back immediately. The docs say this is what makes a leak actually stop. In practice: rotate, deploy the new secret to your receiver, then rotate again. Rotating is a signing-secret step only; if an API key leaked too, follow what to do with an exposed API key.
Sources
Related posts
More in Developers
- Webhook send test vs redeliver: which one replays a real job?
Send test posts a dummy webhook.test payload to a URL you type. Redeliver re-sends a real terminal event and does not use one of the automatic 10 attempts.
- Webhook status OK but output null? Read outcome: degraded
A Sume run webhook can say status OK while output is null. The run completed and billed; outcome is degraded and output_error says why. How to branch on it.
- OpenAI Agents API vs a custom agent API for async runs
OpenAI's Agents API keeps durable sessions; Sume Agent Completions return a 202 receipt to poll or receive by webhook. Where each fits, and how they differ.
- Which MCP server lets Claude Code or Cursor generate video and images?
MCP servers that let Claude Code and Cursor make video and images: Sume, fal, Replicate, Runway, Higgsfield. Endpoints, sign-in, billing, setup.
Written by Sume