Cost per ad variant: build a ledger from usage.cost on Sume
Every completed /v1/videos poll carries usage.cost. Sum it by hook and ending to get the cost per ad variant before media spend. Node script and the caveats.

To get the cost of each ad variant on Sume, poll every job and read usage.cost from the completed response. The /v1/videos poll returns an OpenRouter-shaped object where a finished job includes usage with a cost field, and the docs define it as the Sume billable amount for that job. Sum those values grouped by your own hook and ending labels and you have a production cost per variant, before a cent of media budget is spent.
Where the number comes from
The poll body for a completed job looks like this in the contract: id, generation_id, polling_url, status completed, model, unsigned_urls and usage with cost. The cost is the billable amount, which for a standard job is the provider list price times 1.25. For a workspace that connected its own fal key during the development preview, the cost is only the Sume fee; that preview is off in production unless enabled, so for most readers the number is simply what was charged.
| Field | Meaning for a ledger |
|---|---|
| id | Job id; the same value is generation_id |
| model | Echoes the id you sent, or sume/auto verbatim |
| status | completed, failed, pending, in_progress or cancelled |
| unsigned_urls | Content URL for the clip, index 0 |
| usage.cost | Billable USD for this job |
A ledger script
The script below reads a list of variants, each with a label and a job id you stored at submit time, polls each job once and prints the cost grouped by hook. It uses Node 18 fetch and no dependencies. Run it after the batch has finished; a job that is not completed has no cost to read yet, so the script counts those separately.
const H = { Authorization: `Bearer ${process.env.SUME_API_KEY}` };
const variants = [
{ hook: 'A', ending: 'x', id: 'job_01' },
{ hook: 'A', ending: 'y', id: 'job_02' },
{ hook: 'B', ending: 'x', id: 'job_03' },
];
async function main() {
const byHook = {};
let pending = 0;
for (const v of variants) {
const j = await (await fetch(`https://api.sume.com/v1/videos/${v.id}`, { headers: H })).json();
if (j.status !== 'completed') { pending += 1; continue; }
byHook[v.hook] = (byHook[v.hook] || 0) + (j.usage?.cost ?? 0);
}
console.log(byHook, 'not completed:', pending);
}
main();Checking it against the account
Compare your ledger with the account read. GET /v1/usage returns usage for the workspace and GET /v1/balance returns the balance, both documented in the Sume recipes. If the ledger total is lower than the usage you see for the period, you have jobs that were not in your list, such as retries you did not record or captions and trims you ran on the clips. Extra steps cost money too: a trim is $0.02 and a caption job is $0.20, and they will not show up in a ledger that reads only /v1/videos.
- Store the job id the moment you receive the 202.
- Count failed jobs separately and compare them with the account usage read, so you know what a failure actually cost.
- Record the model id with each row so that a price change is visible.
Using the ledger
The point of a ledger is a decision rule. Pick a cost per variant that you will not exceed for a test arm, and compare each hook's average against it before you scale. A hook that costs twice as much because it needed retakes is a worse bet than a hook that was right the first time, even if the final clip looks the same.
Keep the ledger beside the ad platform report. When a variant wins, you can say what it cost to make and what it cost to run, and you can decide whether to spend on a higher quality final for that arm only.
Limits
Reading usage.cost tells you what was billed, not what will be billed. For a forecast, read the model's pricing on GET /v1/videos/models and remember that the reserve at submit is the list price times 1.25 and settles on completion.
Adding the fixed-price steps
A ledger that stops at generation understates the cost of a variant. Most ad variants also get trimmed, captioned or assembled, and those jobs have fixed prices in the Sume docs: video trim is $0.02, a standalone caption job is $0.20 for clips up to 60 seconds, and a Timeline render is $0.10 per output minute rounded up. Add a column for each step and a constant for its price, then add them to the generation cost.
For a 6 second variant that is trimmed once, captioned once and assembled once, the fixed part is $0.02 plus $0.20 plus $0.10, which is $0.32 per variant. Twenty variants add $6.40 of fixed-price work to whatever the generation jobs cost. That figure is worth knowing before you choose between many cheap variants and a few expensive ones.
Sources
Related posts
More in Developers
- Create an AI avatar and its first talking video in one bash script
Two Sume jobs in order: create the avatar, wait, then render a talking video with its handle. A bash script with curl and jq, plus the cost of both steps.
- CTA end card for an AI video ad: use last_frame on Sume
End an ad clip on your CTA card by sending it as a last_frame image on /v1/videos. Which models accept it, which do not, and the Timeline alternative.
- How do I narrate a DIY tutorial step by step with a TTS API?
Narrate an 8-step DIY tutorial with one TTS job per step: 1,570 characters, $0.10 on Sume. Why per-step jobs make a fixed step a 1-cent redo.
- Do I pay for a failed AI avatar video job? Refunds on Sume
Sume reserves the avatar video price at submit, captures it on completion, and releases or refunds it where a job fails. What it means for retries.
Written by Sume