Headphone and earbud product photos: logo and orientation QC
Make headphone or earbud lifestyle shots with Sume's image API, then catch flipped logos, wrong earcup sides and cable errors with a Pillow contact sheet.

Headphones are symmetric until they are not: a left cup carries an L, a logo faces outward, and a cable leaves one side. Generated photos often flip such details. A review step is worth more than a longer prompt.
Generate with Sume's Image API, using one clean product photo as a reference, and review a grid of variants at once.
Generate several in one request
Sume's n parameter returns up to 10 images per call, with lower limits on some models. Ask for four scenes of the same headphones: desk, commute, gym, sofa. Keep the prompt strict about what must match the reference.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
resp = requests.post("https://api.sume.com/v1/images", headers=H, timeout=90, json={
"model": "openai/gpt-image-2.5",
"prompt": "Photograph these exact over-ear headphones worn by a person at a desk, soft daylight. Keep the earcup shape, the logo on the outside of the left cup, and the headband as in the reference.",
"input_references": [
{"type": "image_url", "image_url": {"url": "https://example.com/headphones.jpg"}}
],
"aspect_ratio": "auto",
"n": 4,
})
resp.raise_for_status()
if resp.status_code == 202:
raise SystemExit("job envelope: poll data.status_url")
body = resp.json()
print([d["url"] for d in body["data"]], body.get("usage"))A contact sheet for review
Paste the variants beside the reference so a reviewer sees all five at once and judges against the original. The script uses the data[].url values from the response.
import io, requests
from PIL import Image
urls = ["https://example.com/ref.jpg", "https://example.com/v1.png",
"https://example.com/v2.png", "https://example.com/v3.png"]
tiles = []
for u in urls:
r = requests.get(u, timeout=60)
r.raise_for_status()
tiles.append(Image.open(io.BytesIO(r.content)).convert("RGB").resize((400, 400)))
sheet = Image.new("RGB", (400 * len(tiles), 400), "white")
for i, t in enumerate(tiles):
sheet.paste(t, (400 * i, 0))
sheet.save("contact-sheet.jpg")
print("saved", sheet.size)Checklist
- The logo is on the same cup, facing the same way, as on the reference.
- L and R marks, if visible, are on the correct sides.
- The cable leaves the same earcup and does not appear twice.
- Earbud pairs show two matched buds, not one and a half.
Reject variants quickly and keep the cost log: usage.cost comes back with each response, so a rejected batch of four has a known price before you decide whether to ask again.
Before you run a catalog
Run one SKU end to end first. POST /v1/images returns the images directly when it finishes within 30 seconds; past that it returns a 202 envelope with status_url and result_url, which the jobs and results guide explains. Handle that branch before you loop over a catalog, and write each result's URL and usage.cost to a file keyed by SKU, so a failed run restarts where it stopped and nothing is paid for twice.
Sources
Related posts
More in Use cases
- HeyGen Free: 3 videos of 1 minute to test a script
HeyGen's Free plan lists 3 videos a month up to a minute. Use them to judge a script's pacing, then check it against Sume's 4 to 60 second window.
- Holiday ad voiceover and music bed: cost per spot, 300-900 chars
On Sume a 600-character voiceover costs $0.0285 and a music track $0.125 flat, so a spot with both is $0.1535, before the video.
- Holiday clip for a marketplace video slot: what to check before upload
Amazon, Shopify, Etsy and TikTok Shop each set their own video rules. Sume gives you ratio, length and size controls; read each platform's current page.
- A 15-second home-anniversary video for past clients from one avatar
Send past buyers a short personal video each year. One $0.95 avatar and a 15-second script cost $2.76 on standard or $3.68 on plus per video.
Written by Sume