Ruby Net::HTTP: POST /v1/images and handle 200 and 202
A Ruby script for Sume's Images API: send the request with Net::HTTP, print data[].url on 200, and read status_url when a slow job returns 202.

In Ruby, call Sume's Images API with Net::HTTP: POST JSON to https://api.sume.com/v1/images, then branch on the status code. A 200 carries data[].url with the finished images, and a 202 carries a job envelope with status_url and result_url for polling. Set the read timeout above 30 seconds so the sync wait can finish.
The script
It reads the key from the environment, which fails fast if the variable is missing. Net::HTTP is in the standard library, so there are no gems to install.
require "net/http"
require "json"
require "uri"
key = ENV.fetch("SUME_API_KEY")
uri = URI("https://api.sume.com/v1/images")
req = Net::HTTP::Post.new(uri, "Authorization" => "Bearer #{key}", "Content-Type" => "application/json")
req.body = { model: "openai/gpt-image-2.5", prompt: "A red kettle on a wooden table", quality: "medium" }.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 45) { |h| h.request(req) }
body = JSON.parse(res.body)
case res.code.to_i
when 200 then puts body["data"].map { |i| i["url"] }
when 202 then puts "poll: #{body.dig("data", "status_url")}"
else abort "#{res.code}: #{res.body}"
endWhy the status code decides
The two successful responses have different shapes. The 200 body is the image response with created, model, data and usage. The 202 body is the standard job envelope. Parsing both as one type fails, so check res.code first, then read the fields for that case.
Polling a 202
On 202, call GET /v1/jobs/{id}/status until the job is terminal, then fetch GET /v1/jobs/{id}/result. Use the URLs in the envelope instead of building them. High resolution, high quality and large n are the likeliest to cross the 30 second wait. You can also send mode: "async" to always take the job path.
Errors to handle
Sume rejects a parameter that the model does not list with 400 unsupported_parameter, rather than ignoring it. A provider failure returns 502, and a failed generation is not billed. Print the body on any other status so you can read the error code.
| Status | Meaning | Action |
|---|---|---|
| 200 | images ready | download data[].url |
| 202 | job envelope | poll status_url, then result_url |
| 400 | unsupported field or value | fix the request |
| 502 | provider failure, not billed | retry or try another model |
Next steps
Add an Idempotency-Key header when you retry the same payload after a timeout. For the timeout details, see the Images API route guide.
Related posts
More in Developers
- Ruby Net::HTTP: POST to Sume images and save the file
Net::HTTP.start with use_ssl and read_timeout, one POST to /v1/images, a string comparison on res.code, and File.binwrite for the image. No gems needed.
- Run create 503 studio_agent_upstream_timeout: the run may exist
A 502 or 503 on a Sume run create can mean the run already exists and is spending. Retry with the same Idempotency-Key and the original run is replayed.
- Sume run webhook outcome degraded: status OK but output is null
A Sume run webhook can say status OK and still carry output null. Branch on outcome (ok, degraded, error), not status, and dedupe on the envelope request_id.
- First MCP call: Runway whoami vs Sume account_me and mcp_health
Runway says verify its dev MCP with whoami. On Sume, call mcp_health for endpoint and auth source, then account_me for the workspace; both are read only.
Written by Sume