Test your Sume webhook receiver locally: openssl and curl
Sign a fake job.completed body with openssl, post it with curl and confirm your receiver answers 200 for valid, and 401 for stale and forged Sume deliveries.

You can test a webhook receiver without spending a generation. A Sume delivery is an HTTP POST with two headers and a JSON body, and the signature is plain HMAC-SHA256, so openssl and curl are enough to fake a delivery on your laptop. That lets you prove three things before the first real job: a valid delivery returns 2xx, a stale one is rejected and a forged one is rejected.
The scheme, from the webhook guide, is HMAC-SHA256(secret, "<timestamp>.<raw_body>"), hex encoded, sent as x-sume-webhook-signature: sume-v1=<hex> with the Unix timestamp in x-sume-webhook-timestamp.
The script
Set SUME_WEBHOOK_SECRET to the same value your receiver reads and pass your receiver URL as the first argument. The body mirrors the documented job.completed payload: event, request_id, job_id, status and payload.artifacts[] with id, url, type and content_type. The script prints one status code per case.
set -euo pipefail
: "${SUME_WEBHOOK_SECRET:?set SUME_WEBHOOK_SECRET}"
URL="${1:-http://localhost:3000/sume/webhook}"
BODY='{"event":"job.completed","request_id":"job_test","job_id":"job_test","status":"OK","payload":{"artifacts":[{"id":"artf_test","url":"https://example.com/out.mp4","type":"video","content_type":"video/mp4"}]}}'
sign() {
printf '%s.%s' "$1" "$BODY" | openssl dgst -sha256 -hmac "$SUME_WEBHOOK_SECRET" -hex | sed 's/^.* //'
}
send() {
curl -sS -o /dev/null -w '%{http_code}\n' -X POST "$URL" \
-H 'content-type: application/json' \
-H "x-sume-webhook-timestamp: $1" \
-H "x-sume-webhook-signature: sume-v1=$2" \
--data-binary "$BODY"
}
TS=$(date +%s); OLD=$((TS - 400))
echo "valid: $(send "$TS" "$(sign "$TS")")"
echo "stale: $(send "$OLD" "$(sign "$OLD")")"
echo "forged: $(send "$TS" "$(printf '0%.0s' {1..64})")"What you should see
| Case | What changes | Expected status |
|---|---|---|
| valid | Fresh timestamp, correct signature | 200 |
| stale | Timestamp 400 seconds old, correctly signed | 401 with a 300 second window |
| forged | Fixed all-zero signature | 401 |
The stale case is signed correctly over its own old timestamp. That isolates the replay window: a receiver that checks only the HMAC returns 200 here, and a receiver that enforces 300 seconds returns 401.
Test a secret rotation too
During a signing-secret rotation Sume sends one entry per live secret in a single header, comma-separated, as sume-v1=<new>,sume-v1=<previous>. Change the send function to pass sume-v1=$2,sume-v1=$3 with one wrong and one right signature. A receiver that accepts when any entry matches returns 200, and one that reads only the first entry returns 401 whenever the wrong one comes first. Run the case before the day you rotate, not during it.
Pitfalls
- Use
--data-binary. Plain-dstrips newlines and can change the bytes you signed. - Sign the exact string you send. If your receiver parses and re-serialises JSON before verifying, the valid case fails.
- Depending on the OpenSSL version,
openssl dgst -hexmay print a prefix such asSHA2-256(stdin)=, so thesedstrips everything up to the last space. - A real delivery also includes
x-sume-webhook-secret-fingerprint, which you can ignore in a local test.
The header list and rotation rule are in the webhook guide. Once the receiver passes, keep status polling as a backup for deliveries you miss.
Sources
Related posts
More in Developers
- Test two caption looks on one Reel with source_caption_id
Restyling captions with source_caption_id reuses the first caption job's video and word timings, so no second transcription runs. Billing stays one render each.
- How to test a webhook URL before a Sume Format run uses it
POST /v1/webhooks/test-deliveries sends a signed webhook.test event to your URL. See the scope, the response fields, and the secret check, with no paid run.
- TikTok 23-60 fps and 360-4096 px: Sume Timeline and Trim conform
TikTok accepts 23 to 60 fps and 360 to 4096 pixels per side. Sume Timeline fps is 24, 25, 30 or 60 and size is 256-2160; Trim conform needs exact mode.
- TikTok 4 GB file cap: the average bitrate for 10, 30 and 60 minutes
4 GB over 3,600 seconds leaves about 8.9 Mbps on average. Here is the arithmetic for 10, 30 and 60 minutes and what to check on a Sume render before upload.
Written by Sume