callback_url or webhook_url: which field each Sume video route takes
POST /v1/videos takes callback_url; motion control, lip-sync and image routes take mode plus webhook_url. The field names and what they share.

On Sume, POST /v1/videos takes callback_url in the request body, while the avatar-type routes such as Kling 3.0 motion control and MiniMax H3 Max lip-sync take a mode field and a webhook_url. Both deliver a signed POST to your HTTPS endpoint when the job finishes. The names differ because the two families of routes were designed in different places: the video route copies the OpenRouter video API, and the other routes use Sume's own communication fields.
If you copy a body from one route to the other, the webhook field is the one most likely to be wrong, so keep the table below next to your client code.. A wrong field name is quietly dangerous because an unknown key may be ignored instead of rejected, in which case the job runs normally and no webhook ever arrives. You then see the symptom, a clip that finished but never reached your system, long after the cause is forgotten. Treat the map as part of the contract with each route and review it whenever a new route joins your client.
The field map
Every field below comes from the Sume route docs. A route that does not list a callback field in its docs is not in the table.
| Route | Field | Notes |
|---|---|---|
| POST /v1/videos | callback_url | HTTPS only, in the body |
| POST /v1/kling/3.0/motion-control | mode + webhook_url | mode selects async or waiting behavior |
| POST /v1/minimax/h3-max/lip-sync | mode + webhook_url | Same communication fields as Fabric |
| POST /v1/images | mode, webhook_url, wait_timeout_seconds | Communication additions shared by generate routes |
What stays the same
The delivery itself is shared. On /v1/videos, Sume sends its own job webhook envelope with an x-sume-webhook-signature header, not an OpenRouter video.generation.* event with an OpenRouter signature. Check the webhooks reference for the exact header set on your route before you write the verifier, and route on the job in the payload and not on the URL path.
Refuse to verify with an empty secret, and verify the raw bytes before you parse the JSON. Stored receivers are in a stdlib receiver for videos and a Kling motion control receiver.
Both requests side by side
The first request is the video route and the second is the motion control route. The model, the inputs and the webhook field are the three places the bodies differ.
# /v1/videos: callback_url
curl -X POST "https://api.sume.com/v1/videos" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"wan-3.0","prompt":"A paper boat on a pond",
"callback_url":"https://example.com/hooks/video"}'
# motion control: mode + webhook_url
curl -X POST "https://api.sume.com/v1/kling/3.0/motion-control" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url":"https://example.com/still.png",
"motion_video_url":"https://example.com/move.mp4",
"duration_seconds":5,"mode":"async",
"webhook_url":"https://example.com/hooks/video"}'One receiver for every route
Because the envelope is shared, a single endpoint can serve both families. Give each submitted job its own idempotency key, store the job id that the submit response returns, and when a webhook arrives look the job up by the id in the payload. Do not infer the route from the URL, and do not assume the order of delivery: a webhook can arrive before the submit call has returned to your code, so write the job row first or make the handler tolerant of an unknown id by retrying the lookup.
Respond with a 2xx quickly and do the heavy work, such as downloading the clip, in a queue. A handler that takes a long time invites redelivery, and a second delivery of the same event should be a no-op in your code. Keep the status check on the job as the final authority: if a webhook is lost, the poll address returns the same terminal state.
A short checklist for a mixed client
If your client builds bodies for several routes, put the field mapping in one function and test it. Three tests are enough: a video body has callback_url and no webhook_url, a motion control or lip-sync body has webhook_url and a mode, and every webhook URL in a body is HTTPS. These checks catch the copy and paste mistake before a job is reserved and billed.
When polling is still the right choice
A webhook is optional on every route. You can poll GET /v1/videos/{id} or the shared GET /v1/jobs/{id}/status and /result. The submit response carries a polling_url, so a client that cannot expose a public endpoint can poll that address until the status is terminal.
Sources
Related posts
More in Developers
- Cap Sume spend from an agent loop: dry_run, max_spend_usd and run caps
Four optional guards cap what an automated Sume caller can spend: dry_run, max_spend_usd, generation_spend_cap_usd on Formats, and a balance check.
- Captions out of sync with the audio: check STT word times and offsets
Captions running early or late usually trace to an unapplied offset. How Sume STT word times work, which offset to add, and a Python merge that applies it.
- Connect a new MCP client to Sume: five calls that prove it works
After you add https://mcp.sume.com/mcp to a new client, run mcp_health, tools_list, tools_schema, account_me and catalog_list. What each result should show.
- Convert an SRT file to Sume caption cues in Python
Sume captions take no SRT upload, but cues carry the same start, end and text. A 26-line Python script turns an SRT into cues and posts them for $0.20.
Written by Sume