Verify a Sume avatar video webhook in Python (HMAC SHA-256)
A Python verifier for avatar video webhooks: timestamp tolerance, rotation-safe comparison, and a hard refusal when the signing secret is empty.
To verify a Sume webhook in Python, compute an HMAC SHA-256 over <timestamp>.<raw_body> with your workspace signing secret, prefix the hex digest with sume-v1=, and compare it in constant time with every sume-v1= entry in the x-sume-webhook-signature header. Reject the request if the timestamp is more than five minutes old, and reject it outright if your secret is empty. An empty secret signs nothing, but an attacker can sign with an empty key, so a verifier that does not check for it will accept forged bodies.
Avatar videos take longer than the 30-second wait that sync mode allows, so a webhook is the natural way to learn that a render finished. Keep the verifier in its own module with a unit test for the three cases that matter: a valid signature passes, a one-character change to the body fails, and an empty secret fails even when the signature was computed with an empty key.
The verifier
This follows the scheme documented on the Sume webhooks page. It accepts a rotating secret: during rotation the header carries one entry per live secret, comma-separated.
import hashlib
import hmac
import time
def verify(raw_body: bytes, timestamp: str, header: str,
secret: str, tolerance: int = 300) -> bool:
if not secret:
return False # never verify against an empty secret
try:
ts = int(timestamp)
except ValueError:
return False
if abs(int(time.time()) - ts) > tolerance:
return False
mac = hmac.new(secret.encode(), digestmod=hashlib.sha256)
mac.update(f"{ts}.".encode() + raw_body)
expected = "sume-v1=" + mac.hexdigest()
ok = False
for entry in header.split(","):
if hmac.compare_digest(entry.strip(), expected):
ok = True
return okWire it to the request
Sume sends only terminal events for generation jobs: job.completed, job.failed and job.canceled. Failed and canceled events carry status: "ERROR" and an error object.
- Read the raw bytes of the body before any JSON parsing. Re-serialized JSON will not match the signature.
- Pass the headers
x-sume-webhook-timestampandx-sume-webhook-signature. - Get the secret from the Webhooks tab of the dashboard or
GET /v1/webhooks/signing-secret, and store it inSUME_COM_WEBHOOK_SIGNING_SECRET. - Persist the event, then return any
2xx. Usejob_idas your idempotency key because the same event can arrive more than once.
Submit the job with a webhook
Send mode: "webhook" and a public HTTPS webhook_url when you create the avatar video. Localhost, private-network and non-HTTPS URLs are rejected.
| Behavior | Value |
|---|---|
| Attempts | Up to 10 |
| Spacing | Fixed delay, 30 seconds by default |
| Per-attempt timeout | 10 seconds |
| Replay window to enforce | 5 minutes is a reasonable default |
| After attempts run out | Job keeps its real state; use Redeliver or poll status_url |
Limits
A webhook is an optimization, never your only recovery path. Keep polling status_url for events that never arrive, and treat a failed signature check as a reason to compare the x-sume-webhook-secret-fingerprint header with the fingerprint in the dashboard, not as a reason to disable verification. A job that reached completed while your endpoint was down can be re-sent with POST /v1/jobs/{job_id}/webhook/redeliver.
Sources
Related posts
More in Developers
- low_confidence_long_video: why video_frames warns past 90 seconds
Sume's video_frames returns the low_confidence_long_video warning when the source runs over 90 s. The job still succeeds; the hard cap is 300 s. What to do.
- Check has_audio first: video_inspect frames false before STT or detach
A free probe-only video_inspect tells you probe.has_audio before you reserve STT or run audio detach, so silent clips never hit the no-audio errors.
- video_inspect silence_split_seconds: sentence segments for captions
How silence_split_seconds (0.2 to 3) shapes Sume video-inspect sentence segments, the 0.5 s default in the repo, and turning segments into caption cues.
- Voice API deadlines, October 2026 to February 2027
A calendar of voice and transcription API changes from vendor pages: Gemini TTS price rise, OpenAI transcription shutdown, and the xAI voice alias move.
Written by Sume