OpenRouter puts an idempotency key on video webhooks; Sume uses job_id

OpenRouter's video guide adds an idempotency key header to each delivery. Sume dedupes on job_id and takes Idempotency-Key on submit. Which key goes where.

5 min readSume
All posts

There are two different idempotency problems in an async video API, and the keys for them live in different places. The first is the submit: a client retries a POST and must not create (and pay for) a second job. The second is the delivery: a server retries a webhook and the receiver must not process a result twice. OpenRouter's video guide, read 2026-10-05, says each webhook delivery includes an idempotency key header so receivers can dedupe retries. Sume covers the submit with an Idempotency-Key request header on /v1/videos, and the delivery with a stable job_id in the payload.

Submit side

On Sume, Idempotency-Key on POST /v1/videos makes a retry return the original job. Reusing a key with a different body gives 409. An idempotent replay gets the same route and the same price, even for sume/auto, because the resolution is a pure function of the normalized request plus the catalog version. This is Sume's addition to the OpenRouter wire format; clients written only against OpenRouter's docs do not send it unless you add it.

Which key protects what (read 2026-10-05)
LayerProblemOpenRouter guideSume
SubmitRetried POST creates a second paid jobNot described on the fetched pageIdempotency-Key header; 409 on a different body
DeliveryRetried webhook processed twiceIdempotency key header on each deliveryDedupe on job_id (jobs) or request_id (runs)
SignatureForged deliveryX-OpenRouter-Signature, HMAC-SHA256, optionalx-sume-webhook-signature: sume-v1=..., HMAC-SHA256
Event namesBranch on outcomevideo.generation.completed and siblingsjob.completed, job.failed, job.canceled

Receiver side

If you built a receiver for OpenRouter and read the idempotency header, port it by changing the key source, not the logic. Take job_id from the Sume payload, insert it into a table with a unique constraint, and skip the work when the insert conflicts. Sume's docs say it explicitly: use job_id as the idempotency key on your side. Redeliver re-sends the real event with a new timestamp and signature, so the signature differs between deliveries while job_id stays the same, which is why the signature cannot serve as a dedupe key.

  • Do not use the signature or the timestamp as a dedupe key. Both change on every attempt.
  • Add Idempotency-Key to the submit helper, one key per clip.
  • Keep the polling fallback: GET /v1/videos/{job_id} returns the OR-shaped job object with usage.cost.
  • Map cancelled in OpenRouter-shaped responses to Sume's canceled job status.

Test both layers

Write two tests. One submits the same body twice with the same key and asserts one job id. The other delivers the same signed payload twice to your receiver and asserts one side effect. If both pass, a flaky network can no longer cost you a duplicate render or a duplicate email.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume