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.

See every webhook attempt for a Sume video job: webhook.delivery
Did Sume reach your endpoint? Read webhook_delivery on the job and the webhook.delivery events: statuses pending to exhausted, last_error and attempt count.

Save a 30-second Seedance 2.5 clip to S3 with boto3, no temp file
Stream the finished MP4 from Sume's /content endpoint straight into S3 with boto3 upload_fileobj. Includes the 30 s price table and a short script.

Webhook before your DB row? Insert, then submit the Sume video
A Sume job webhook can beat your own write of the job id. Insert a pending row keyed by Idempotency-Key first, then upsert by job_id when the event lands.

waitForJob timeout in the Sume TypeScript SDK: keep the job id
waitForJob waits 20 minutes by default and throws SumeJobTimeoutError without cancelling the render. Catch it, store jobId, and resume later. Sume SDK 0.2.0.

Poll a Seedance 2.5 job in TypeScript: deadline and failed states
A TypeScript submit-poll-download loop for a 30-second Seedance 2.5 render on Sume: the 30 s interval, a 20-minute deadline, and the three end states.

Which API key scopes does a Sume webhook receiver need?
Verifying a Sume webhook needs no API key at all. Reading the secret, rotating it, sending a test and redelivering a job each need a different scope.

Video edit on Sume: video_url cannot ride with image fields
For gemini-omni-flash-1.1 video-to-video edit, video_url is the source, not a reference. Mixing it with image_url or reference lists fails. Fix and examples.

Ack a Sume webhook in 10 s, then copy the 30-second MP4 later
Sume gives each delivery 10 seconds. Verify, store the job id, answer 204, and let a worker download the MP4 instead of doing it inside the handler.

Test a video poll loop with a fake clock, no real waits (Python)
Inject sleep and clock into your Sume job poller so a test of a 20-minute deadline runs in milliseconds. Includes a stdlib-only script that passes.

SHA-256 manifest for a batch of 30-second clips: spot bad downloads
After downloading many 30-second Sume clips, write a manifest of size and SHA-256 per job id so a rerun skips good files and re-fetches bad ones. Python.

Price guard: refuse a 30-second Seedance 2.5 render over your cap
Compute the Sume price of a clip from model, resolution and seconds before you POST, and refuse over a cap. Python code, the rates, and the 1080p cent rounding.

curl and jq: poll a Seedance 2.5 clip from a bash script
A bash script with curl and jq that submits a 30-second Seedance 2.5 job to Sume, polls every 30 seconds and saves the MP4, with costs at three resolutions.

Check an Ideogram 4.5 edit left the rest of the image alone (Python)
Diff the source and the Ideogram 4.5 edit with Pillow, count changed pixels outside your text box, and fail the pass before it enters a chain. Code included.

Next.js Pages Router webhook for a Sume video job: bodyParser false
A Pages Router API route that reads the raw body, verifies sume-v1, acks fast and dedupes on job_id for a 30 s render. Refuses an empty secret.

Cancel a Wan 3.0 job before it starts, and what a 1080p clip reserves
A Wan 3.0 job can be canceled only before generation starts; after that you get 409 job_generation_already_started. The reserve is $7.50 for 30 s at 1080p.

automation_generation_spend_cap_exceeded: what a 402 cap error ends
The per-run cap rejects only the one generation that would cross it. current, requested and cap come back in micros so you can size the next request.

Avatar batch: which limit hits first, writes per minute or the queue?
On Pro, 300 writes/min is far above the 24 accepted jobs (4 running, 20 queued). Queue capacity limits an avatar batch first, so submit in waves of that size.

Avatar submit response: what next_action tells your client to do
next_action has three values on avatar submits: poll_status while queued or processing, fetch_result once completed, inspect_events for failed or canceled jobs.

Avatar sync wait: timed_out vs capacity_exhausted, and what to do
A sync avatar submit can return 2xx with sync.timed_out or sync.capacity_exhausted true. Both mean keep the job: poll status_url, never submit a new paid job.

Sume 501 capability_not_configured: no job started, no credits spent
501 capability_not_configured means that feature is not connected on the platform. No job starts and nothing is charged. Do not retry; contact support.

Caption cue limits: 400 characters, 200 cues, 60 seconds
A caption cue takes 1-400 characters, start of 0 or more, end above start and 60 s or less; a request holds 1-200 cues. Validate locally before the $0.20 job.

Caption job 400: words, cues, segments, script_text are exclusive
The video captions API accepts only one wording source: words, cues or segments (which skip STT), or script_text (aligned onto STT). Sending two returns a 400.

compose_duration_clamped_to_source: the banner clip came out shorter
Compose clamps video.duration to the source file and warns compose_duration_clamped_to_source. The job still succeeds; read the result length first.

DeepSeek V4.1 Flash peak pricing vs Sume spend caps for agent loops
DeepSeek bills Flash at double rates 01:00-04:00 and 06:00-10:00 UTC on weekdays. Sume spend caps cover generation only, so budget planner tokens separately.

Hash the avatar payload into your Idempotency-Key, adopt the 409 job
Hash the avatar request into the Idempotency-Key: a retry returns the same job (idempotency_hit true); a 409 names the job holding the key.

Does Dr. split a Sume STT segment? Abbreviations and sentence mode
Segmentation tests each token for a final period, so a token like Dr. or U.S. can end a segment early. Merge on your side with a small abbreviation list.

'duration_seconds must match duration': send one field, not two
Video Router accepts duration or duration_seconds as the same value. Send both with different numbers and you get a 400. Send one, or send two equal ones.

'end_image_url requires image_url': a last frame needs a first frame
A last frame without a first frame is refused on both Sume video routes. Add a first frame, or drop the end frame and describe the ending in the prompt.

'first_frame_url must match image_url': two names, one value
image_url and first_frame_url are aliases on Video Router. Send both only if the strings are identical, same for end_image_url and last_frame_url, or get a 400.

Ideogram 4.5 seed on Sume returns 400: how to repeat an edit
Ideogram's own API takes a seed for 4.5 edits, but Sume returns 400 unsupported_parameter for seed on every image model. Keep the output URL, not the seed.

Timeline invalid_fit 400: fit must be cover, contain, stretch or blur
invalid_fit means video[].fit is not cover, contain, stretch or blur. Cover is the default, so omit the field if you want it. details.allowed lists values.

Timeline invalid_fps 400: output.fps must be 24, 25, 30 or 60
invalid_fps rejects any output.fps outside 24, 25, 30 and 60. Omit the field to match the source frame rate; details.allowed lists the accepted values.

Timeline invalid_transition_type: why xfade is rejected (use fade)
transition.type accepts fade, wipeleft, wiperight, slideup, slidedown and dissolve. xfade is the internal ffmpeg name, so it returns invalid_transition_type.

Sume jobs_wait outcome: wait_slice_expired is not a failed job
jobs_wait returns outcome terminal, wait_slice_expired or operator_stopped. Only terminal means the jobs ended; an expired slice says nothing about the jobs.

MAI streaming sessions end at one hour: a chunk plan for long audio
A MAI-Transcribe-2-Streaming session lasts at most one hour; Sume STT jobs cap at 10 minutes. Plan overlap-free chunks and shift each chunk's word times.

MAI-Voice 24 kHz 160 kbps mp3 header vs Sume output_format settings
Microsoft's REST example asks for audio-24khz-160kbitrate-mono-mp3. Sume has no 160 kbps option: mp3 bit rates are 32, 64, 96, 128 or 192 kbps at up to 48 kHz.

MAI voice ids end in a model name; Sume voice ids do not
A MAI id like en-US-Harper:MAI-Voice-2.1-Flash is not a Sume voice id. Sume takes a UUID or voi_ plus 32 hex and returns 400 invalid_voice_id for anything else.

provider_submission_failed 502: Sume could not start the job, retry
provider_submission_failed is a 502 meaning the job never started. By default it is retryable with retry_after_seconds 30 and next_action retry_later.

script_run error script_tool_forbidden: discovery calls belong outside
script_tool_forbidden means a Sume script called a discovery tool (tools_list, tools_schema, mcp_health, search_tools) or script_run. Call them from the turn.

Send a WAV file to MAI-Transcribe-2-Streaming: PCM16, no WAV header
MAI streaming wants raw PCM16 mono at 16 or 24 kHz as base64 in 10-20 ms chunks, no header. Python's wave module strips it; Sume's STT shape is 16 kHz mono.

service_account_callback_domain_not_allowed 403: fix the callback host
The 403 means webhook_url's host is outside the key's allowed callback domains. An exact host or any subdomain of an allowed domain passes.

Sume 429 concurrency cap or queue cap: which service-account limit?
service_account_concurrency_cap_exceeded counts active jobs; service_account_queue_cap_exceeded counts queued ones. Both are 429. Wait for a job to finish.

service_account_idempotency_required 400: send an Idempotency-Key
Some service-account keys require an Idempotency-Key on every paid submit. The 400 means the header is missing; add a stable key per intent and resend.

Service-account 403: key revoked, account revoked or disabled
Three 403 codes stop a service-account key before any other check: key_revoked, revoked and disabled. None is retryable; create or request a replacement.

service_account_metadata_required 400: which source headers to send
The 400 lists missing fields in details.missing and the header for each in details.headers. Five x-sume-source headers exist; send the ones named.

service_account_model_not_allowed 403: the key's model allowlist
The 403 says the model, or the operation, is not on the service-account key's allowlist. details.model or details.operation names the value to add or avoid.

service_account_policy_unavailable 503: the message says temporary
The message says temporarily unavailable, but the envelope marks this 503 retryable false with contact_support. Retry cautiously and alert on repeats.

service_account_rate_limited 429: read the minute and hour headers
A service-account key has an optional minute window and hour window. The 429 names the window, and x-sume-service-account headers show what is left.