CI test: assert Seedance 2.5 and Wan 3.0 still list 30 seconds

Fail a build when your 30-second video code outlives the catalog. A short Python test reads supported_durations from GET /v1/videos/models and checks 30.

5 min readSume
All posts

Add one test that calls GET /v1/videos/models and checks that seedance-2.5 and wan-3.0 still list 30 in supported_durations, so a catalog change fails your build before it fails a customer's job. Your code that hard-codes duration: 30 is a contract with a provider, and the catalog is where Sume publishes that contract.

The docs state the limits today: seedance-2.5 accepts 4 to 30 seconds at 480p, 720p and 1080p, and wan-3.0 accepts 2 to 30 seconds.

What the endpoint returns

Each model entry has an id, supported_resolutions, supported_aspect_ratios, supported_durations, pricing_skus, and flags such as generate_audio and seed. The docs also say that other catalog models cap at 15 seconds, so a model-routing bug that sends 30 seconds to the wrong model fails in a different way from a retired duration.

Documented duration limits to assert, Sume Video Generation docs read 2026-10-05
ModelMinMaxResolutions
seedance-2.54 s30 s480p, 720p, 1080p
wan-3.02 s30 slisted per model in the catalog
seedance-2not stated here15 sincludes 1080p

The test

This pytest file needs requests and SUME_API_KEY. The response shape is read defensively: it accepts a bare list or an object with a data list, because the docs show the fields per entry but not the wrapper.

import os
import pytest
import requests

def models():
    r = requests.get("https://api.sume.com/v1/videos/models",
        headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}, timeout=30)
    r.raise_for_status()
    body = r.json()
    items = body["data"] if isinstance(body, dict) else body
    return {m["id"]: m for m in items}

@pytest.mark.parametrize("model", ["seedance-2.5", "wan-3.0"])
def test_thirty_seconds_still_supported(model):
    m = models().get(model)
    assert m is not None, model + " is not in the catalog"
    assert 30 in m["supported_durations"], m["supported_durations"]

def test_nothing_hardcoded_above_the_max():
    for m in models().values():
        assert max(m["supported_durations"]) >= 2

Where it fits

A failing test is not an outage. It tells you the catalog moved, and whether to change your default length, your model choice, or your cost cap.

  • Run it nightly rather than on every commit; it calls the network and needs a key.
  • Use a read-only key if your plan allows scopes, because the test only reads the catalog.
  • On failure, show the live list in the message so the fix is obvious.
  • Pair it with a price check; the same endpoint returns pricing_skus for your estimate.

Why this beats a code comment

A comment that says # Seedance goes to 30 s is true on the day it is written. A test is true every night. The catalog is the one place Sume lists duration support, so asserting against it moves the risk from a customer to your CI.

Keep the assertions small. Check the model exists, check 30 is in the list, and stop. A test that tries to mirror every field will break on harmless additions and train people to ignore it.

If a test fails because the list changed, update the default in one place, in config, rather than patching call sites. Your code should read the duration from a single setting so the fix is one line.

Reading the result

A pass means only that the catalog still lists the length. It says nothing about queue depth or your balance, so keep the price guard and the admission checks in the code that submits. This test is a smoke alarm for one specific kind of drift, and that is enough to justify its few lines.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume