Draft with GPT Image 2.5 Flare, finish with Sunburst: a two-pass edit
OpenAI pairs Flare with fast generation and Sunburst with editing precision. A Python two-pass on Sume's Image API that drafts, then refines the first result.

OpenAI's image guide recommends gpt-image-2.5-sunburst for editing precision and gpt-image-2.5-flare for fast everyday generation. A two-pass workflow follows from that: draft with Flare until the composition is right, then send the winning draft to Sunburst as a reference with an edit instruction.
On Sume the two are openai/gpt-image-2.5 (Flare) and openai/gpt-image-2.5-sunburst, both on POST /v1/images.
What each model is for
From the OpenAI guide and Sume's Image API page, read 2026-10-03.
| Item | Flare | Sunburst |
|---|---|---|
| OpenAI guide role | Fast everyday generation | Editing precision |
| Sume model id | openai/gpt-image-2.5 | openai/gpt-image-2.5-sunburst |
| Image references on Sume | Up to 16 | Up to 16 |
| Quality values on Sume | auto, low, medium, high, xhigh, max (default high) | Same |
| Rates on Sume | Same Fal token rates for both | Same Fal token rates for both |
The two-pass script
Pass one generates a draft. Pass two sends the draft URL as input_references with an edit prompt and aspect_ratio: "auto", which the Sume docs recommend on edit calls so the output matches the reference. Both calls handle the documented 200 versus 202 split: a 200 carries the image, a 202 carries a job to poll.
import os, time, requests
BASE = "https://api.sume.com"
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def images(body):
r = requests.post(BASE + "/v1/images", headers=H, json=body, timeout=60)
r.raise_for_status()
if r.status_code == 200:
return r.json()["data"][0]["url"]
job = r.json()["data"]
while True:
s = requests.get(job["status_url"], headers=H, timeout=60).json()
d = s.get("data", s)
if d.get("terminal"):
break
time.sleep(d.get("next_poll_after_seconds") or 5)
res = requests.get(job["result_url"], headers=H, timeout=60).json()
print(res) # inspect the job result shape for the image URL
raise SystemExit("read the artifact URL from the job result above")
draft = images({"model": "openai/gpt-image-2.5", "quality": "low",
"prompt": "a ceramic mug on a wooden desk, morning light"})
final = images({"model": "openai/gpt-image-2.5-sunburst", "quality": "high",
"aspect_ratio": "auto",
"prompt": "keep the mug and light, make the desk dark walnut",
"input_references": [{"type": "image_url", "image_url": {"url": draft}}]})
print(final)Why a low-quality first pass
The point of pass one is composition, not finish.
- Sume's docs say
autoquality reservesmax, so name a tier explicitly.lowfor drafts andhighfor the final keeps the draft cheap to repeat. - Slow settings (4K, high quality, large
n) are the ones most likely to return202instead of an image, so the script handles both. - Reference URLs must be public HTTPS. A Sume-hosted result URL qualifies; a localhost path does not.
- Change one thing per edit prompt. If the second pass drifts, the edit instruction was doing too much, not the model.
Limits of this recipe
The recipe follows the roles in OpenAI's guide, but neither page says Sunburst always beats Flare at edits on your content. Run the same edit on both models for five of your own images before you commit the second pass to a pipeline.
Sources
Related posts
More in Developers
- Dramatiq retry_when for Sume: retry only retryable errors
A Dramatiq actor with retry_when that retries 429 and 5xx but not 402 or 400, and sends one stable Idempotency-Key so a retried Sume submit is not billed twice.
- Draw in the browser, send to Sume: a canvas Sketch pad in 20 lines
ChatGPT Sketch lives inside ChatGPT. For your own app, export a canvas as PNG, upload it to a public HTTPS URL and pass it to Sume as a reference.
- Dropped connection mid-render: what happens to the Sume job
A dropped connection never cancels a Sume job. Wait again with jobs_wait on the same ids, or read the job status; never resubmit the paid create.
- DynamoDB conditional put: dedupe Sume job_id webhook retries
A PutItem with attribute_not_exists(job_id) makes the first Sume webhook the only one that proceeds. Node sample with a two-state record and TTL.
Written by Sume