970x250 billboard ad image: render 1920x640, crop 23% of height
A 970x250 ad is 3.88:1, wider than the 3:1 limit on GPT Image 2.5. Render 1920x640 (3:1), scale to 970 wide, and crop the height. Table of checks and prices.

A 970x250 billboard ad is 3.88:1, which is wider than the 3:1 cap on GPT Image 2.5 custom sizes, so you cannot ask for it directly. Render 1920x640 (exactly 3:1), scale it to 970 wide, and crop the height from 323 pixels to 250.
The crop removes 73 of 323 rows, about 22.6 percent of the height. Plan the picture for that before you pay for it: the subject belongs in the middle band, with sky and foreground you can lose.
Numbers
1920x640 sits right on the ratio limit and well inside the pixel range, so it passes every rule the OpenAI guide lists for custom sizes.
| Check | Value | Result |
|---|---|---|
| Both edges multiples of 16 | 1920 = 16 x 120, 640 = 16 x 40 | pass |
| Longest edge at most 3840 | 1920 | pass |
| Aspect ratio at most 3:1 | 3.000:1 | pass |
| Pixels 655,360 to 8,294,400 | 1,228,800 | pass |
Code
The same fit call does both steps. It scales 1920x640 to 970x323, then trims the overflow equally from the top and bottom.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def generate(body):
r = requests.post("https://api.sume.com/v1/images", headers=H, json=body, timeout=60)
if r.status_code != 200: # 202 = still running, read data.status_url
raise SystemExit(f"{r.status_code}: {r.text[:300]}")
return r.json()["data"][0]["url"]
from io import BytesIO
from PIL import Image, ImageOps
url = generate({
"model": "openai/gpt-image-2.5",
"prompt": "Wide scene of a mountain lake at dawn, the main subject in the center band, calm empty sky above and water below",
"image_size": {"width": 1920, "height": 640},
"quality": "high",
})
img = Image.open(BytesIO(requests.get(url, timeout=60).content)).convert("RGB")
ImageOps.fit(img, (970, 250), Image.LANCZOS).save("ad-970x250.png")What one render costs
These are output-only prices from the Flare token rate. Sume bills list times 1.25. A wide master gives you room for a 2x file too: crop 1940x500 from the same render and the shape still matches.
| Quality | Provider list | Sume at list x 1.25 |
|---|---|---|
| low | $0.0019 | $0.0024 |
| medium | $0.0046 | $0.0058 |
| high | $0.0186 | $0.0232 |
Writing the prompt for the crop
Tell the model the picture will be cropped to a thin band. Keep faces and products between 30 and 70 percent of the height, and leave copy space at one end of the band for the headline you add in code.
Draft cheap, finish once
A display set usually needs several concepts before one is approved. Request the first round at quality: "low", pick the layout, then repeat only the winner at high. Quality is a per-request field on both ChatGPT Image 2.5 variants (openai/gpt-image-2.5 and openai/gpt-image-2.5-sunburst), and the accepted values are auto, low, medium, high, xhigh and max. Avoid auto: Sume reserves the max price for it, so set the tier yourself.
Flare is the faster variant and Sunburst is tuned for edit precision, according to the fal pages. Both share the same token rates, so for an ad pass you can pick on behavior, not on price. Auto routing on Sume (sume/auto) uses Flare.
If the call returns 202 instead of 200
POST /v1/images waits up to 30 seconds and answers 200 with the images when the job finishes in time. When it does not, the route answers 202 with the standard job envelope, and the images come from GET /v1/jobs/{id}/result. Slow settings such as 4K, high quality and large n are the likeliest to fall back. A 1-2 megapixel ad master at high quality usually stays in the wait budget, but the code should branch on the status code, not the body shape.
For a batch of ad sizes, send each request with mode: "async" and read the results afterwards, or add a webhook_url with mode: "webhook". A failed synchronous job returns 502 with an error code and a next_action, and Sume does not bill failed generations.
Sources
Related posts
More in Use cases
- A/B test two AI music beds on one ad: cost and the Timeline steps
Make two beds for one ad at $0.125 each, render both cuts on Timeline at $0.10 per minute, and compare. A cost table for a 30-second ad.
- A4 poster at 300 dpi: 2480x3508 is over the GPT Image 2.5 pixel cap
A4 at 300 dpi is 2480x3508, 8,699,840 pixels, above the 8,294,400 cap. Render 2400x3392 on GPT Image 2.5, then scale up 3.4% in Pillow and tag it 300 dpi.
- ACCC Black Friday sweep: match the clip's end date to the sale end
ACCC Black Friday sweeps target limited-time claims and countdown timers that miss the real sale end. Burn the end date from one value. Read 2026-10-05.
- Add a logo to a product image: Ideogram 4.5 with two input references
Send the product photo first and the logo second in input_references on Sume, and say which is which in the prompt. Order matters: the first image is edited.
Written by Sume