Charging users for AI video: price each one from usage.cost
After Sora, your app pays Sume's usage.cost per video. Add a margin, round up to the cent, charge only completed jobs. A JavaScript helper and rules.

If your product sold Sora clips to your own users, price each Sume clip from the usage.cost on the completed job, multiply by one plus your margin, and round up to the cent. Charge your customer only when the status is completed. Failed jobs release or refund the reservation on Sume's side, so you should not bill the customer for them either.
Where the cost comes from
The poll response for a finished job includes a usage object whose cost is the billed amount. That is the number to build on, not a figure you multiplied yourself, because edit jobs treat duration only as a reserve hint.
Decide whether you quote before or after the render. A quote before needs a model's per-second rate and your clip length; a charge after uses usage.cost. Many products show an estimate up front and settle on the real number, which handles edits where the duration is only a hint.
Examples
| Clip | Sume billed cost | Price at +40% | Price at +100% |
|---|---|---|---|
| 10 s, gemini-omni-flash-1.1, 720p | $1.25 | $1.75 | $2.50 |
| 10 s, wan-3.0, 1080p | $2.50 | $3.50 | $5.00 |
| 10 s, grok-imagine-video-1.5 | $0.13 | $0.19 | $0.26 |
A note on the examples
The margins in the table are illustrations, not recommendations. The Sume column is the billed price: list per second times 1.25, with the reservation rounded up to the cent.
The helper
This helper rounds up, so a tiny floating-point wobble never costs you a cent. Run it with node and compare the two logged prices to the table.
const price = (cost, margin) => Math.ceil(cost * (1 + margin) * 100 - 1e-9) / 100;
const job = { status: "completed", usage: { cost: 1.25 } }; // from GET /v1/videos/{id}
if (job.status === "completed") {
console.log(price(job.usage.cost, 0.4)); // 1.75
console.log(price(job.usage.cost, 1.0)); // 2.5
}Rules that keep the books straight
Take payment after completion, or hold funds and capture on completion. Either way, tie the customer charge to your own record of the job id, and send an Idempotency-Key with the submit, so that a retried request cannot create two jobs for one payment.
Keep margin in one place in your code, and store it with each order. When you change it, old orders keep the margin they were sold at, and your reports still add up.
- Charge on status completed only.
- Release or refund for failed jobs, and read usage.cost on a cancelled one before billing.
- Store job id, model, resolution and usage.cost with the order.
- Handle 402 insufficient_credits by pausing new orders and alerting yourself.
Quote before you render
Keep a small buffer in your own balance, since each submit reserves the full amount before a clip exists. See the admission docs for the reservation rules and the per-second table for quoting a price before the job runs.
Sources
Related posts
More in Use cases
- Charity appeal film: 3 versions of 30 seconds, 720p vs 480p
Three 30-second 16:9 versions of an appeal film cost $52.02 at 720p and $24.21 at 480p on Seedance 2.5 on Sume. How to pick which to test first.
- Charter boat listing video from ten photos: Wan 3.0 vertical and wide
One set of ten boat photos, two Wan 3.0 jobs: 9:16 for stories and 16:9 for the listing page. $3.75 each at 720p for 30 s, $7.50 for both, with a shot order.
- ChatGPT Images 2.5 Poster and Merch templates as API prompts
ChatGPT Images 2.5 added Poster and Merch templates. The API has no template field, so write the layout into the prompt and call openai/gpt-image-2.5 on Sume.
- Livestream service intro: 10 seconds of Wan 3.0, 63 cents to $2.50
A 10-second intro bumper for a livestream or service costs 63 cents at 480p, $1.25 at 720p and $2.50 at 1080p on Sume's wan-3.0. When 1080p pays off.
Written by Sume