Blog

Developers

Building on the Sume API: keys and hosts, jobs and runs, polling, webhooks, idempotency, errors and rate limits, the SDK, the CLI, and MCP auth.

Start with: Sume API quickstart: your first video generation call in five steps

Grok Imagine Video 1.5 Lite batch API: what xAI documents

xAI's Lite page lists a $0.02 per second price, 10 requests per second, batch support and two regions. Sume jobs are async instead; here is how they differ.

Nova 2.5 Sonic async tool calls: start a Sume job, return the job id

With asynchronous tool calling, a Nova 2.5 Sonic agent can start a Sume music or caption job, answer at once with the job id, and poll status later.

pplx-embed-v2-late for storyboard frames: Sume has no embeddings route

Perplexity's pplx-embed-v2-late embeds images and pages. Sume lists no embeddings route; use video_frames_create for stills and index them on your side.

Sume 400 invalid_request: read details.errors[].path to find the field

A Sume 400 invalid_request lists each bad field in details.errors with path, loc, message and type. Read them in Python instead of guessing from the message.

A Sume 400 that returns a job id: input rejected at provider submit

Most Sume 400s create nothing, but a provider input rejected at submit leaves a failed job, a request_id and a refund. How to read it and what key to use.

Sume 404 resource_not_found: job_not_found and model_not_found overlap

Every Sume 404 reports public_reason resource_not_found, whatever the code. Branch on error.code to tell a missing job from a bad model id or a missing asset.

Sume 409 job_not_queued: the job left the queue before it started

What the Sume 409 job_not_queued means: a submit found its job no longer queued, sent nothing to the provider, and the error is not retryable by resending.

Sume generation_capacity_exhausted: the 503, job reason and flag

Sume reports provider capacity three ways: HTTP 503 provider_capacity_exceeded, a job reason generation_capacity_exhausted, and a sync flag. All three retry.

Sume job failed artifact_too_large: shrink the output, don't rerun

A Sume job failing with artifact_too_large or artifact_upload_rejected made its file but could not store it. Make the file smaller; rerunning changes nothing.

Django view for Sume webhooks: verify request.body, then parse

A Django view that verifies a Sume webhook against request.body: csrf_exempt, 300 s replay window, empty-secret refusal, multi-signature header, 204.

EmbeddingGemma 2's 5.5-minute audio limit: cut a long track

EmbeddingGemma 2 fits 5.5 minutes of audio. A 28-minute video needs six 300-second audio detach ranges at $0.01 per job, $0.06 in total.

EmbeddingGemma 2 takes 58 video frames: sample them with Sume

EmbeddingGemma 2 fits 58 video frames in its 8K window. Sume's video inspect returns 24 stills per call, so three calls with explicit times cover it.

Fastify raw body for a Sume webhook: parseAs string and verifyWebhook

Fastify parses JSON before your handler, which breaks signatures. Use addContentTypeParser with parseAs string and verifyWebhook from @sume-com/sdk.

Flask webhook receiver for Sume job events: verify the signature

Verify a Sume job webhook in Flask: read request.get_data() raw, check the sume-v1 HMAC and 300 s window, refuse an empty secret, answer 204.

Actix Web: verify a Sume webhook from the web::Bytes extractor

Take the Sume webhook body as web::Bytes in Actix Web, verify HMAC SHA-256 with the hmac and subtle crates, and return 204 or 401.

Falcon ASGI: verify a Sume webhook with req.bounded_stream.read()

Read the raw Sume webhook body in Falcon ASGI with req.bounded_stream.read(), verify HMAC SHA-256, and set HTTP_204 or raise HTTPUnauthorized.

Go Fiber v3: BodyRaw for Sume webhooks, and copy it before you queue

Sign-check a Sume webhook in Go Fiber with c.BodyRaw() and hmac.Equal, then copy the bytes before handing them to a goroutine, since Fiber reuses them.

List Sume assets: limit, cursor, media_type and status filters

GET /v1/assets returns up to 100 assets per page, newest first, with a null next_cursor on the last page. Filters, defaults, and what a bad cursor does.

Litestar handler for Sume webhooks: await request.body() and 204

A Litestar post handler that awaits request.body(), verifies the Sume HMAC signature, sets status_code=204 explicitly, and raises 401 on a mismatch.

Phoenix: cache the raw body with Plug.Parsers body_reader for Sume

Phoenix parses JSON before your controller runs. Cache the raw bytes with a Plug.Parsers body_reader, then verify the Sume webhook HMAC signature.

Quarkus REST endpoint for Sume webhooks: @HeaderParam and byte[]

A Quarkus REST resource that takes the Sume webhook body as byte[], reads the signature headers with @HeaderParam, and answers 204 or 401.

Sanic webhook route for Sume: request.body, HMAC, empty() 204

Verify a Sume webhook in Sanic with request.body bytes and hmac.compare_digest, then return an empty 204 so the delivery counts as done.

Sume asset complete 409s: checksum, content type, wrong state

POST /v1/assets/{id}/complete checks state, expiry, content type, size and checksum in a fixed order, and deletes the object when it rejects one.

Sume asset download URL: 300 seconds and the 409 cases

GET /v1/assets/{id}/download-url returns a signed GET link that expires in 300 seconds by default, and 409s for registered URLs or assets not yet ready.

An uploaded Sume asset you never complete: what happens

A pending_upload asset has a 15-minute URL by default. After the window and a one-hour grace, a reaper deletes the object and marks the row failed.

TTS voice list returns 503: provider_unavailable vs not_configured

GET /v1/tts-router/voices can return 503 two ways on Sume. provider_unavailable is a retry; provider_not_configured is not. Cache, timeout and a retry loop.

Vapor 4: collect the body, verify a Sume webhook with swift-crypto

Use body: .collect(maxSize:) in Vapor 4, read req.body.data, and verify the Sume HMAC SHA-256 signature with swift-crypto before returning .noContent.

Vert.x Web: verify a Sume webhook after BodyHandler reads the body

Install BodyHandler before your Vert.x route, read the body as bytes, recompute HMAC SHA-256 over timestamp.body, and return 204 to a Sume delivery.

PowerShell Invoke-RestMethod: a Sume video job to replace Sora

Replace a PowerShell script that called the Sora Videos API: submit to Sume /v1/videos with Invoke-RestMethod, poll polling_url, download the mp4.

Caddy in front of a Sume webhook receiver: body limit and timeouts

Does Caddy break Sume webhook signatures? reverse_proxy passes headers and body through; set max_size above 1 MiB and an 8 s upstream timeout.

Clojure: Ring middleware that verifies a Sume webhook from raw bytes

Verify a Sume webhook in Clojure: slurp Ring's one-shot body as bytes, HMAC-SHA256 with javax.crypto, MessageDigest/isEqual, rotation entries, 300 s window.

Erlang: verify a Sume webhook with crypto:mac and crypto:hash_equals

Verify a Sume webhook in Erlang/OTP 26+: crypto:mac over timestamp.raw_body, binary:encode_hex, crypto:hash_equals, rotation entries, and an empty-secret guard.

Port a gemini-nano-banana-2.1 image call to Sume POST /v1/images

Map Google's response_format aspect_ratio and image_size, base64 output and inline inputs to Sume's aspect_ratio, resolution, data[].url and input_references.

Gleam: verify a Sume webhook with gleam_crypto and secure_compare

Verify a Sume webhook in Gleam: crypto.hmac over timestamp.raw_body as a BitArray, lower-cased base16, secure_compare, rotation entries, and a 300 s window.

Grok Imagine Video 1.5 Lite on Vercel AI Gateway vs Sume /v1/videos

Vercel added Grok Imagine Video 1.5 Lite to AI Gateway on Oct 8. What generateVideo gives you, and the equivalent text-to-video call on Sume's /v1/videos.

Julia: verify a Sume webhook with SHA.jl and a hand-rolled compare

Verify a Sume webhook in Julia: SHA.hmac_sha256 over timestamp.raw_body, a hand-rolled constant-time compare, rotation entries, and a five-minute replay window.

Nushell: submit a Sume job and poll it to a result, no jq needed

A Nushell script that POSTs a Sume image job with an Idempotency-Key, polls /v1/jobs/{id}/status by next_poll_after_seconds, then fetches the result.

Eleven rows on Sume return MP3 only: use Sonic when you need WAV

Sume's eleven-* TTS Router ids return MP3 only, and three of the five accept just one format. WAV, avatar voices and word timings belong to the sonic ids.

Inngest Bursty Concurrency 3x: will Sume answer queue_full?

Inngest can lift step concurrency 3x for 60 minutes a month. Sume's limit does not move: size bursts to accepted capacity and retry queue_full with one key.

One-job limits in Sume's TTS Router: v3 5,000, v4 10,000, Sonic 20,000

Each TTS Router id has its own max_characters. A Python planner splits a script on paragraph breaks so each request fits the row you picked.

Sonic 3.6 vs Eleven v4 Turbo: one script, one Python A/B run on Sume

Send the same text to sonic-3.6 and eleven-v4-turbo through the TTS Router with one Python script, poll both jobs, and compare the files by ear.

Sume job failed worker_job_stalled or worker_lease_expired: what now

A Sume job stuck in processing can end as worker_job_stalled or worker_lease_expired. Both are terminal job.failed events with the hold refunded. Resubmit.

Sume queue_admission_unavailable and usage_reservation_unavailable

Two Sume submit failures that are not 402 or 429: admission or the usage hold could not be evaluated. The row is failed and refunded; retry with the same key.

CircleCI no_output_timeout: poll a Sume video job without a kill

CircleCI kills a run step after 10 silent minutes. Print a status line on every poll, raise no_output_timeout, and keep one Sume Idempotency-Key per workflow.

Empty job_id next to job_ids: how Sume MCP treats placeholders

Some agent clients fill every optional tool field with empty strings, zeros and empty arrays. What Sume's MCP drops, what it keeps, and what still errors.

On a 402, try a cheaper rung: a Python ladder with fresh keys

A 402 on Sume means nothing was reserved, so a cheaper request can go straight through. Python ladder: Seedance 720p, 480p, then Wan 480p, one key per rung.

Sume failed job says [redacted_url]: what was removed

A [redacted_url] in a Sume job error is by design: URLs, provider ids, env names and secrets are masked, and the provider reason is capped at 300 characters.

Is there a lipsync-1.0 endpoint on Sume? Old paths 404; use Fabric

Sume's old /v1/lipsync-1.0 paths return 404 and its model ids return model_not_found. Send the same still and audio to veed/fabric-1.0 or H3 Max lip-sync.