TikTok publish webhooks vs Sume run webhooks: wire both safely
TikTok sends webhooks for failed, complete, inbox, public and removed posts. Sume signs its own run webhook separately. Keep two receivers and verify Sume's.

A TikTok video pipeline that uses Sume receives two unrelated webhooks: TikTok's, which report what happened to a post, and Sume's, which report that a run you started has finished. Run them on separate endpoints, because they are signed and shaped by different systems, and verify Sume's with the sume-v1 HMAC check before you trust the body.
What events does TikTok send?
The Get Post Status page lists webhook events for failed publishes, completed posts, inbox delivery, public availability and removal from public view. That page does not describe the signature scheme in the part read, so check TikTok's own webhook docs before you build verification for it.
| Source | Tells you | Signed how |
|---|---|---|
| TikTok | Failed, complete, inbox, public, removed | See TikTok's docs |
| Sume | A Format run is terminal (format.run.terminal) | HMAC-SHA256 as sume-v1 in x-sume-webhook-signature |
How does Sume's webhook work?
Per the Sume docs, a run created with communication.webhook_url receives one signed POST when it completes or fails, with up to 10 delivery attempts. The signature is HMAC-SHA256 over <timestamp>.<raw_body>, sent as sume-v1=<hex>, with headers x-sume-webhook-timestamp and x-sume-webhook-signature. The SDK's verifyWebhook does the check and its replay window defaults to 300 seconds.
Read the raw body before parsing JSON, return a fast 2xx, and dedupe on request_id. A delivery outcome never changes the run; if delivery fails, read the receipt from result_url.
import { verifyWebhook } from "@sume-com/sdk";
export async function POST(request: Request) {
const secret = process.env.SUME_COM_WEBHOOK_SIGNING_SECRET;
if (!secret) return new Response("no secret", { status: 500 });
const body = await request.text();
const ok = await verifyWebhook({ body, headers: request.headers, secret });
if (!ok) return new Response("bad signature", { status: 401 });
const event = JSON.parse(body);
// hand event.request_id to your uploader, then reply fast
return new Response(null, { status: 204 });
}How should the two meet?
Use Sume's run webhook as the trigger that says a file is ready, then start your TikTok upload, and let TikTok's webhooks or status polling close the loop. Keep a table keyed by your own post ID with the Sume run ID and TikTok publish ID side by side.
If a Sume webhook never arrives, polling is the documented backup: Runs and results covers reading the receipt directly.
What does Sume not do?
Sume does not call TikTok or forward TikTok events. Rotating the Sume signing secret opens a 24-hour window with two signatures in one header, so upgrade your receiver to the current SDK before you rotate, as Verifying webhooks warns.
Sources
Related posts
More in Integrations
- Val Town free 1-minute timeout: a Sume webhook receiver val
Val Town's free plan stops a val at 1 minute and runs crons every 15 minutes at best. Submit Sume jobs async, then take the result by webhook or a slow cron.
- Vercel Workflow createWebhook is token-only: verify Sume first
createWebhook trusts only the URL token. For a Sume callback, verify the sume-v1 signature in your own route, then resume a hook with resumeHook.
- VS Code mcp.json: servers or mcpServers key for Sume's hosted MCP?
VS Code's .vscode/mcp.json uses a top-level servers key; the portable .mcp.json uses mcpServers. Put Sume's entry under the key that matches its file.
- Windmill webhook token in the URL: calling it from a Sume job
Windmill prefers a bearer header, but Sume's webhook_url is just a URL, so the token must ride in the query string. How to scope it and still trust the result.
Written by Sume