Shotstack's callback is in the edit; Sume's webhook_url is outside

Shotstack puts a callback URL inside the edit JSON. Sume puts webhook_url on the request and signs deliveries. What changes in your code.

5 min readSume
All posts

In Shotstack the callback URL is a field of the edit itself, next to the timeline and output, while in Sume the webhook URL is a field of the request and has nothing to do with the render document. That matters when you store, version or hash your edit documents, because a Shotstack callback changes the document and a Sume one does not.

Shotstack's details are from its API reference, read 2026-10-10. Sume's are from the Webhooks and Jobs and results docs.

Where the URL lives

The Shotstack page describes POST /render on production at https://api.shotstack.io/edit/v1/render and on stage at https://api.shotstack.io/edit/stage/render, an x-api-key header, a poll at GET /render/{id} whose status runs through values such as rendering and done, and a callback field in the edit JSON that Shotstack calls when the render ends.

On Sume a Timeline render is POST /v1/timeline-1.0/render. To get a callback you add mode: "webhook" and a public HTTPS webhook_url beside the document, not inside it. If you send webhook_url (or its alias callback_url) without a mode, you get webhook mode.

Shotstack from its API reference (read 2026-10-10); Sume from the Webhooks and Jobs docs.
QuestionShotstackSume
Where the callback goescallback inside the edit JSONwebhook_url beside the document
PollGET /render/{id}GET /v1/jobs/:id/status
Auth headerx-api-keyAuthorization: Bearer or x-api-key
Test environmentA separate stage URLNone found in the docs read
Delivery proofNot read from the pageSigned: timestamp plus HMAC-SHA256 header
EventsNot read from the pagejob.completed, job.failed, job.canceled only
RetriesNot read from the pageUp to 10, 30 s apart; manual redeliver endpoint

Consequences for your code

If you cache or deduplicate renders by hashing the edit JSON, a Shotstack callback URL that includes a per-job id makes every hash unique. On Sume the document hash is independent of the delivery address, so two renders of the same document differ only by their Idempotency-Key, which Timeline requires on every render.

Sume's delivery is signed. Verify x-sume-webhook-signature over <timestamp>.<raw_body> and reject anything outside five minutes. The page I read for Shotstack did not describe signing, so I make no comparison on that point beyond what the table says.

Keeping the poll as a backup

Whichever vendor you use, a callback is an optimisation. Sume's docs say so directly: after ten refused attempts you have a failed delivery and a job that still finished, so keep status polling available. A small job table keyed by job id, updated by both the webhook and a slow sweep of unfinished rows, handles it.

Shotstack has a separate stage environment, per the page I read, which is handy for test renders. I found no equivalent environment in the Sume docs I read for this post, so plan tests with small renders and the unbilled POST /v1/timeline-1.0/plan check instead.

Porting the handler

Move the URL out of the document and into the request, then change the handler. Verify the signature first, using the raw body and the timestamp header. Route on the event field, and dedupe on job_id. Success arrives as status: OK with the artifacts under payload, and failure as status: ERROR with an error object.

Keep your old status poller for a while as a safety net. Sume's statuses are queued, processing, completed, failed and canceled, so a map from Shotstack's values to those is a few lines. Run both vendors side by side on a copy of real traffic before you switch.

Sources

Related posts

More in Comparisons

All Comparisons posts

Written by Sume