Timeline plan as a spend gate: a 1,800 s render is at most $3.00

Call POST /v1/timeline-1.0/plan before render. It is unbilled and returns estimated_cost_usd_micros. The longest render, 1,800 s, is 30 minutes at $0.10: $3.00.

5 min readSume
All posts

POST /v1/timeline-1.0/plan compiles a Timeline document without creating a job, reserving credits or downloading media, and returns estimated_cost_usd_micros. Timeline 1.0 costs $0.10 per output minute, rounded up, and audio.duration_seconds can be at most 1,800, so the most one render can cost is 1,800 / 60 = 30 minutes x $0.10 = $3.00. Use the plan response as a gate: refuse to render when the estimate is above your cap.

What the plan returns

The plan runs schema checks, Sume-host URL checks and the pure compiler. The response is object: timeline_plan with the fields below. It cannot predict warnings about short sources that need padding or looping, so a render can still report soft warnings. Those are not failures.

Timeline plan facts, as of 2026-10-08
ItemValue
BilledNo; no job, reservation or download
Fieldsduration_seconds, segment_count, billable_minutes, estimated_cost_usd_micros, filtergraph_summary
Rate$0.10 per ceil(output minute)
Max audio length1,800 s (30 minutes)
Max cost of one render30 x $0.10 = $3.00 = 3,000,000 micros
Slots1 to 200 video slots

Micros to dollars

A USD micro is one millionth of a dollar. A 90-second render bills ceil(90 / 60) = 2 minutes, which is $0.20, or 200,000 micros. A 61-second render also bills two minutes, because the minute count is rounded up. When you set a cap, convert dollars to micros once and compare integers.

The gate

The function below refuses to render when the estimate is above the cap. It calls the plan route only, which is free, so it is safe to run on every candidate document. The render call, which needs an Idempotency-Key, belongs after the gate passes.

import os
import httpx

def plan_cost_micros(doc: dict) -> int:
    key = os.environ.get("SUME_API_KEY", "")
    if not key:
        raise SystemExit("set SUME_API_KEY")
    r = httpx.post(
        "https://api.sume.com/v1/timeline-1.0/plan",
        headers={"Authorization": f"Bearer {key}"},
        json=doc,
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["estimated_cost_usd_micros"]

def gate(doc: dict, cap_usd: float) -> bool:
    cap = round(cap_usd * 1_000_000)
    est = plan_cost_micros(doc)
    print(f"estimate {est} micros, cap {cap} micros")
    return est <= cap

Limits of a plan

A plan checks the document, not the quality of your sources. Every URL must already be a media.sume.com artifact or asset in this workspace, so import media first. Render takes the default mode async, or sync for up to 30 seconds of waiting.

Caps at three levels

Set a cap for each render, for each day and for each project. The per-render cap catches a mistaken audio.duration_seconds. A 3,600-second value is rejected by the 1,800-second limit anyway, but 1,799 seconds still costs $3.00 and is a likely typo for 179. The daily cap catches a loop. The project cap keeps one client from using another client's budget.

Because the plan is free, run it for every document, store the estimate with the document, and sum the stored estimates to see the day's committed spend before any job exists.

The Timeline docs say the public rate is $0.10 per rounded-up output minute and that you should confirm the live rate in GET /v1/catalog. Read it there at startup and keep a unit test that fails when it changes. The reserve at render time is ceil(audio.duration_seconds / 60) minutes, so the plan and the reserve use the same rounding rule.

Sources

Related posts

More in Pricing

All Pricing posts

Written by Sume