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).

5 min readSume
All posts

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.

Webhook signing, Synthesia vs Sume (Synthesia pages read 2026-10-10; Sume per docs.sume.com/workflows/webhooks)
ItemSynthesiaSume
Signature headerSynthesia-Signaturex-sume-webhook-signature
Timestamp headerSynthesia-Timestampx-sume-webhook-timestamp
AlgorithmHMAC-SHA256HMAC SHA 256
Signed stringtimestamp.request_body<timestamp>.<raw_body>
Value formatNot stated on the page readsume-v1=<hex_signature>
Replay checkOptional; example: ignore events older than 10 minutesReject outside your window; five minutes is the suggested default
Secretsecret returned when you create the webhookDashboard Webhooks tab, or GET /v1/webhooks/signing-secret with account:read
RotationNot described on the pages readHeader carries one sume-v1= entry per live secret, newest first
Eventsvideo.completed, video.failedjob.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 ok

Where 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

All Comparisons posts

Written by Sume