Ruby Net::HTTP: submit a Wan 3.0 video job and poll until it finishes

A standard-library Ruby script that posts to /v1/videos with wan-3.0, polls the polling_url every 30 seconds and stops on completed, failed or cancelled.

4 min readSume
All posts

In Ruby, POST to https://api.sume.com/v1/videos with model: "wan-3.0", read polling_url from the 202 response, and poll it until status is completed, failed or cancelled. The standard library is enough: net/http, json and uri, with no gem.

The script below prints the job id, the status on each poll, and the first download URL when the job completes.

The script

It reads the key from SUME_API_KEY, sends a 6-second 720p request and sleeps 30 seconds between polls, the interval the Sume docs example uses. Net::HTTP.get with a headers hash needs Ruby 3.0 or newer.

require "net/http"
require "json"
require "uri"

key = ENV.fetch("SUME_API_KEY")
headers = { "Authorization" => "Bearer #{key}", "Content-Type" => "application/json" }

uri = URI("https://api.sume.com/v1/videos")
body = { model: "wan-3.0", prompt: "A paper boat drifting down a rainy street, soft light",
         duration: 6, resolution: "720p" }.to_json
res = Net::HTTP.post(uri, body, headers)
raise "submit failed: #{res.code} #{res.body}" unless res.code == "202"
job = JSON.parse(res.body)
puts "job #{job["id"]}"

loop do
  sleep 30
  st = JSON.parse(Net::HTTP.get(URI(job["polling_url"]), headers))
  puts st["status"]
  if st["status"] == "completed"
    puts st["unsigned_urls"].first
    break
  end
  abort("stopped: #{st["status"]} #{st["error"]}") if %w[failed cancelled].include?(st["status"])
end

Statuses to handle

The poll returns pending, in_progress, completed, failed or cancelled (video generation docs). Treat the last two as terminal. On failed, the error field carries a public message, for example when an input media URL could not be downloaded.

Poll statuses on /v1/videos (read 2026-10-07)
StatusKeep polling?What to do
pendingYesJob is queued
in_progressYesGeneration is running
completedNoDownload from unsigned_urls[0]
failedNoRead error; fix the input and submit again
cancelledNoThe job did not complete

Download

The content endpoint, GET /v1/videos/{job_id}/content?index=0, needs your Bearer key and redirects to the artifact URL, so use a client that follows redirects and send the key only to api.sume.com. A 409 job_not_completed means keep polling, and a 409 job_failed means stop.

Cost

Wan 3.0 at 720p is $0.125 per second on Sume, so this 6-second script spends $0.75 (read 2026-10-07, pricing basis). The poll response reports the billed amount in usage.cost. For a webhook instead of polling, pass an HTTPS callback_url.

Practical notes

Two small hardening steps for production: add a deadline so the loop gives up after, say, 20 minutes, and wrap the submit in a retry that reuses the same Idempotency-Key header so a network error does not create two billed jobs.

Rails users can move this into a background job. Submit in one job, store the id, and either schedule a poll job or accept a callback_url webhook, so no worker sits asleep for minutes.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume