Synthesia-Signature vs Sume's webhook signature: one verifier?
Synthesia signs timestamp.request_body with HMAC-SHA256; Sume signs the same shape. Header names, prefix and tolerance differ. Compare both (read 2026-10-10).

Yes, almost: Synthesia signs timestamp.request_body with HMAC-SHA256 and Sume signs <timestamp>.<raw_body> with HMAC SHA-256, so the signed string has the same shape on both sides. What differs is the header names, the sume-v1= prefix Sume puts in front of the hex digest, and how each vendor documents tolerance and secret rotation.
The Synthesia facts below come from Verifying Synthesia Signatures, Create Webhook and Webhook Events, all read 2026-10-10. The Sume facts come from Webhooks. If you already verify Synthesia callbacks for presenter videos and want to receive Sume avatar-job callbacks, you can reuse most of the handler.
Side by side
The table lists what each page states. Where Synthesia's pages are silent, the cell says so rather than guessing.
| Item | Synthesia | Sume |
|---|---|---|
| Signature header | Synthesia-Signature | x-sume-webhook-signature |
| Timestamp header | Synthesia-Timestamp | x-sume-webhook-timestamp |
| Algorithm | HMAC-SHA256 | HMAC SHA 256 |
| Signed string | timestamp.request_body | <timestamp>.<raw_body> |
| Value format | Not stated on the page read | sume-v1=<hex_signature> |
| Replay check | Optional; example: ignore events older than 10 minutes | Reject outside your window; five minutes is the suggested default |
| Secret | secret returned when you create the webhook | Dashboard Webhooks tab, or GET /v1/webhooks/signing-secret with account:read |
| Rotation | Not described on the pages read | Header carries one sume-v1= entry per live secret, newest first |
| Events | video.completed, video.failed | job.completed, job.failed, job.canceled |
What a shared handler has to change
Three things. First, read the right header names. Second, strip the vendor prefix before comparing: Sume's value is sume-v1= plus hex, and the Synthesia page does not say whether its value carries a prefix, so test against a real delivery before you assume it matches.
Third, treat the tolerance as your choice. Synthesia's page offers 10 minutes as an example; Sume's page suggests five. A single constant in your code can serve both, but a tighter window rejects more retried deliveries, so pick the one your receiver can meet.
Always verify the raw body bytes, not a re-serialized JSON object. Both signatures cover the exact bytes the sender transmitted, so a framework that parses and re-encodes the body will break verification for either vendor.
Events do not map one to one
Synthesia documents two events, video.completed and video.failed. Sume sends three terminal job events and nothing in between: no progress, no partial results. A cancel is a first-class outcome on Sume, job.canceled, and canceled and failed deliveries carry status: "ERROR" with an error object.
Sume's page tells you to return a 2xx after you store the event durably, treat job_id as the idempotency key, and keep polling status_url as a backup, because ten failed attempts still leave a job that reached its real terminal state.
A Sume verifier in Python
This checks the timestamp window, refuses an empty secret, and accepts the delivery when any sume-v1= entry matches, so it survives a secret rotation. Feed it the raw request bytes.
import hashlib, hmac, time
def verify(raw: bytes, ts: str, header: str, secret: str, tol: int = 300) -> bool:
if not secret:
return False
try:
t = int(ts)
except ValueError:
return False
if abs(time.time() - t) > tol:
return False
mac = hmac.new(secret.encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest()
want = f"sume-v1={mac}"
ok = False
for entry in header.split(","):
if hmac.compare_digest(entry.strip(), want):
ok = True
return okWhere this fits in an avatar pipeline
A Sume avatar video is a job. Submit it with mode: "webhook" and a public HTTPS webhook_url on POST /v1/avatar-1.0/talking-video, then verify the delivery before you download the clip. See Generate avatar video for the request body and Run webhooks for the sibling event set that shares this signature scheme.
None of this makes the two products interchangeable. Sume's Avatar 1.0 is English-only and takes a script of 4 to 60 seconds estimated duration. Compare outputs and costs separately; this post covers only the callback.
Sources
Related posts
More in Comparisons
- Talking-video API status values: HeyGen, Synthesia, D-ID, Sume mapped
Four avatar-video APIs, four status vocabularies: pending, in_progress, started, queued. Map them to one state machine in your code (read 2026-10-10).
- Tavus lists 42 languages; Sume Avatar 1.0 speaks English only
Tavus video generation lists 42 languages. Sume Avatar 1.0 speaks English only. A short decision guide based on who is listening and what you can accept.
- Tavus callback_url payloads: what to check before you trust one
Tavus's webhooks page lists conversation events but no signature or retry rule. How to treat them, vs Sume's signed events (read 2026-10-10).
- Text-only hero art: Imagen 4 Ultra or Nano Banana 2.1 on Sume
Imagen 4 Ultra costs 0.075 USD, takes no references and lists 5 ratios. Nano Banana 2.1 costs 0.10 and lists 15. Which to pick for 100 hero images.
Written by Sume