Ruby Net::HTTP: Gemini Omni Flash 1.1 vertical 6 s clip, $0.75
Ruby standard library only: submit a 6-second 9:16 Gemini Omni Flash 1.1 clip to Sume ($0.75 at 720p) and poll to completion. Prices at four resolutions.

From Ruby you need no gem for Sume video: Net::HTTP and JSON are enough. Post to /v1/videos with model gemini-omni-flash-1.1, duration 6, resolution 720p and aspect_ratio 9:16, read the polling_url from the 202, and poll it until the status is completed. At 720p the price is $0.125 per second, so the clip is 6 x 0.125 = $0.75.
What this model accepts
gemini-omni-flash-1.1 takes 3 to 10 seconds, only 16:9 or 9:16, and resolutions of 360p, 720p, 1080p and 4K. Native audio is always on, so there is no generate_audio switch to turn off and no cheaper silent version. Six seconds is inside the range; the sample would be rejected for 2 or 11 seconds, so check supported_durations in GET /v1/videos/models if you pass user input. The table shows what the same six seconds cost at each of the four resolutions, so you can see what the choice of 720p saves against 4K: $2.25 minus $0.75 is $1.50 per clip.
| Resolution | USD per second | 6 seconds |
|---|---|---|
| 360p | 0.0375 | 6 x 0.0375 = $0.225 |
| 720p | 0.125 | 6 x 0.125 = $0.75 |
| 1080p | 0.1875 | 6 x 0.1875 = $1.125 |
| 4K | 0.375 | 6 x 0.375 = $2.25 |
The Ruby script
Net::HTTP.new with use_ssl keeps one connection for the submit and the polls. The delay starts at 2 seconds, grows by half each round, and stops growing at 30. The case statement ends the loop on completed, aborts on failed or cancelled, and ignores pending and in_progress.
require "net/http"
require "json"
base = URI("https://api.sume.com/v1/videos")
http = Net::HTTP.new(base.host, base.port)
http.use_ssl = base.scheme == "https"
auth = { "Authorization" => "Bearer #{ENV.fetch('SUME_API_KEY')}" }
req = Net::HTTP::Post.new(base, auth.merge("Content-Type" => "application/json", "Idempotency-Key" => "omni-9x16-6s-001"))
req.body = { model: "gemini-omni-flash-1.1", prompt: "Barista hands a cup to the camera, cafe ambience",
duration: 6, resolution: "720p", aspect_ratio: "9:16" }.to_json
res = http.request(req)
abort "submit #{res.code}: #{res.body}" unless res.code == "202"
job = JSON.parse(res.body)
delay = 2.0
loop do
sleep delay
s = JSON.parse(http.get(URI(job["polling_url"]), auth).body)
case s["status"]
when "completed"
puts s["unsigned_urls"][0], s.dig("usage", "cost")
break
when "failed", "cancelled"
abort s["error"].inspect
end
delay = [delay * 1.5, 30].min
endDetails worth knowing
ENV.fetch raises if SUME_API_KEY is missing, which is better than sending a request with an empty bearer token. The Idempotency-Key header is a fixed string in the sample; use a new value for each clip you want to pay for. The usage.cost field in the completed response is the billable amount; for this clip it should agree with the table row for 720p.
Vertical output matters for short-form feeds, but the model only offers two ratios. If you need 1:1 or 4:3, pick another model from the list; do not expect Sume to crop. Reference images and videos are supported for this model through the same endpoint, and video edits go through the Video Router instead.
If you accept a duration from a form, validate it before the call. A Ruby guard such as (3..10).cover?(seconds) costs nothing, while a rejected request still uses a write from your per-minute budget. Check also that the completed response lists a URL in unsigned_urls before you hand it to a downloader, and log usage.cost next to the job id so that a month-end bill can be matched to clips.
One practical note on Net::HTTP: the poll uses the same http object as the submit, so the TLS connection is reused between requests, and the explicit sleep keeps the loop well inside the read budget of the plan.
- Read GET /v1/videos/models once at start-up rather than hard-coding limits.
- Handle 402 and 429 before polling; both are submit-time answers.
- Download the file from unsigned_urls[0] with the Authorization header.
Sources
Related posts
More in Developers
- Run receipt micros: 5,000,000 is $5.00 and 240,000 is $0.24
Sume run receipts report spend in USD micros. How to convert the cap and billable fields to dollars, and why GET /v1/usage stays the billing ledger.
- Scheduled run input: 64 properties and 2 MiB, how to pack a brief
A Sume scheduled run takes an input object of at most 64 properties and 2,097,152 bytes. Here is how to pack a brief for an agent without hitting either limit.
- Self-hosted H3 video server: API key, TLS and read-only media
MiniMax's H3 guide says to require an API key and TLS before public exposure and mount reference media read-only. A checklist, and what a hosted API gives you.
- Timed-out Seedance 2.5 POST: retry with the same key, pay $8.09 once
If the POST for a 14-second Seedance 2.5 720p job times out, resend it with the same Idempotency-Key to get the original job; a new key could hold $8.09 twice.
Written by Sume