Sume 400 unsupported_capability on 4:5: fall back to 3:4 in Python

A 4:5 request on a Sume video model returns 400 unsupported_capability before billing. Catch it in Python, resubmit at 3:4, then crop to Meta's 4:5 Feed ratio.

4 min readSume
All posts

If you send aspect_ratio 4:5 to a Sume video model that does not advertise it, the API answers 400 with code unsupported_capability and creates no job. Catch that error, resubmit at 3:4, and crop the result to the 4:5 that Meta lists for Feed.

What the docs promise

Sume's video contract says the catalog controls validation. If a model does not advertise a resolution, aspect_ratio, duration, frame_type or reference type, the value gives a 400 and the API does not silently drop the field. The error table lists 400 unsupported_capability for a value that is not in the resolved model's advertised support list, and it says error bodies keep the public error envelope, with error.code and error.message.

A 400 happens at validation, before submission to the provider. Billing reserves on a successful submit, so a rejected request is not charged.

Related Sume errors on /v1/videos, from the repo contract (read 2026-10-05)
HTTPcodeMeaningRetry?
400unsupported_capabilityValue not advertised by the modelChange the value
400unsupported_parametersize, seed or provider.options sentRemove the field
402insufficient_creditsBalance below the reserveTop up
409conflictIdempotency-Key reused with a different bodyNew key

The fallback in Python

The script tries 4:5 first with its own idempotency key, reads the error body when the call is refused, and falls back only for unsupported_capability. Any other error is re-raised so you do not mask a real problem. Different bodies need different keys, otherwise the second call would hit the 409 conflict row.

import json, os, urllib.error, urllib.request

def submit(ratio):
    body = json.dumps({
        "model": "seedance-2",
        "prompt": "A leather wallet on a desk, soft light",
        "duration": 5, "resolution": "720p",
        "aspect_ratio": ratio,
    }).encode()
    req = urllib.request.Request(
        "https://api.sume.com/v1/videos", data=body,
        headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
                 "Content-Type": "application/json",
                 "Idempotency-Key": "wallet-" + ratio.replace(":", "x")})
    with urllib.request.urlopen(req) as r:
        return json.load(r)

try:
    job = submit("4:5")
except urllib.error.HTTPError as e:
    code = json.load(e).get("error", {}).get("code")
    if code != "unsupported_capability":
        raise
    print("4:5 refused, using 3:4")
    job = submit("3:4")
print(job["id"], job["status"])

After the fallback

Poll the job, then crop with video-filter: x 0, y 0.03125, width 1, height 0.9375, which turns 3:4 into 4:5. Run the free check endpoint first. The crop post shows the numbers.

If the model you pinned does advertise 4:5 someday, the first call succeeds and the fallback never runs, so the code stays correct as the catalog changes.

Why not use sume/auto

sume/auto resolves to a model whose envelope is 16:9 or 9:16 with 3 to 10 seconds and native audio, so a 4:5 request there also returns 400. The message names sume/auto, not the resolved family, because the family stays opaque.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume