OpenRouter video client on Sume: swap the base URL, change webhooks

A client written for OpenRouter /videos works on Sume after you change the base URL, key and model ids. The webhook body and signature are different.

5 min readSume
All posts

Change three values and an OpenRouter video client works on Sume: the base URL to https://api.sume.com/v1/videos (no /api segment), the key to a Sume key, and the model ids to Sume catalog ids. Everything else in the submit and poll path matches the OpenRouter guide field for field. The part you must rewrite is the webhook receiver, because Sume sends its own job envelope with its own signature.

What is the same

The OpenRouter guide, read today, describes POST /api/v1/videos, a poll on GET /api/v1/videos/{jobId}, content at .../content?index=0, and model discovery at .../videos/models. Sume serves the same four routes. The 202 reply is {id, polling_url, status, model}, and the poll states are pending, in_progress, completed, failed and cancelled.

OpenRouter and Sume video routes, read 2026-10-08
ItemOpenRouterSume
SubmitPOST /api/v1/videosPOST /v1/videos
Model idsorg/slugBare ids such as seedance-2, kling-3
Webhook fieldcallback_urlcallback_url, HTTPS only
Eventsvideo.generation.*job.completed, job.failed, job.canceled
SignatureX-OpenRouter-Signature: t=,v1=x-sume-webhook-signature: sume-v1=
Idempotency<job_id>-<status> header on deliveryIdempotency-Key on submit

What differs and fails loudly

Sume returns 400 unsupported_parameter for size, for seed, and for a non-empty provider.options, because every v1 model reports supported_sizes: null, seed: false and an empty passthrough list. Use resolution plus aspect_ratio instead. Sume also adds model: "sume/auto", which lets Sume pick the family.

Sume does not list Veo 3.1 or Happy Horse 1.1 in the v1 catalog. Call GET /v1/videos/models for the live list before you hard-code an id.

A submit that works

This call uses only documented fields. The Idempotency-Key header makes a retry safe: a replay returns the original job.

curl -X POST "https://api.sume.com/v1/videos" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "model": "seedance-2",
    "prompt": "A ceramic mug on a desk, slow push-in",
    "resolution": "720p",
    "aspect_ratio": "16:9",
    "callback_url": "https://example.com/hooks/sume"
  }'

Port the receiver

Replace the t=,v1= parser with the sume-v1 check over <timestamp>.<raw_body>, route on event, and dedupe on job_id. Video generation is not eligible for Zero Data Retention on either service, and Sume has no ZDR toggle.

Checks before you switch traffic

Run the models call first. Compare supported_resolutions, supported_aspect_ratios and supported_durations for each model you use, because the limits differ by model: seedance-2.5 accepts 4 to 30 seconds, wan-3.0 2 to 30 seconds, minimax-h3 5 to 15 seconds at native 480p or 768p, and most other models stop at 15 seconds.

Then check the poll response. On Sume, a completed job has unsigned_urls that point at the content route, and usage.cost is the billable amount. Sume reserves the provider list price times 1.25 at submit. Do not copy a price from another service into your cost code.

The same job can be read at GET /v1/jobs/{id}/status and GET /v1/jobs/{id}/result, with next_poll_after_seconds and result_ready. A client that outgrows the OpenRouter shape can move to that route without resubmitting anything.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume