AI sofa fabric preview: swap the upholstery using a swatch photo

Preview a new sofa fabric: the sofa photo first, a photo of the fabric swatch second, a mask on the upholstery, and one Sume edit that keeps legs and cushions.

4 min readSume
All posts

A fabric swatch as a second reference

A swatch card is a thumb-size piece of cloth. Photograph it in daylight and send it as the second image next to your sofa photo. The prompt asks for the upholstery in that fabric.

Use mask_url on ChatGPT Image 2.5 to limit the edit to the sofa body. Without a mask, the room's cushions and rug are likely to pick up the fabric too.

Sume Image API docs list ChatGPT Image 2.5 as openai/gpt-image-2.5 (Flare) and openai/gpt-image-2.5-sunburst. OpenAI's guide says to choose Sunburst where editing precision matters most and Flare for fast everyday generation, so these edits use Sunburst.

Describe texture and what stays

Say bouclé, linen or velvet, since the model reads the swatch but the word helps. Keep the legs, stitching lines and the shadow under the sofa. Say that cushions on the sofa stay the same color unless you want them to change.

import os
import requests

REFS = [
    "https://example.com/sofa.jpg",
    "https://example.com/swatch.jpg",
]
resp = requests.post(
    "https://api.sume.com/v1/images",
    headers={"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"},
    json={
        "model": "openai/gpt-image-2.5-sunburst",
        "prompt": "Image 1 is a sofa photo, image 2 is a fabric swatch. "
                  "Reupholster the sofa body in image 2. Keep legs, "
                  "stitching, cushions, the rug and wall unchanged.",
        "aspect_ratio": "auto",
        "mask_url": "https://example.com/sofa-mask.png",
        "input_references": [
            {"type": "image_url", "image_url": {"url": u}} for u in REFS
        ],
    },
    timeout=60,
)
print(resp.status_code)
print(resp.json())

Fabric options

One call per swatch with the same photo and mask.

Swatch comparison (example inputs; limits per Sume docs, read 2026-10-03)
OptionFabric
AOatmeal bouclé
BGreen velvet
CGrey linen

Feel it before you buy

A render cannot show how cloth feels or wears. Ask the retailer for a swatch you can rub and clean, and use the render only to reject colors that look wrong in your room.

Inputs Sume checks before it spends anything

Reference and mask URLs must be public HTTPS; localhost, private-network and non-HTTPS URLs are rejected. Sume also checks every field against the model's catalog entry, so a field the model does not list returns 400 unsupported_parameter instead of being dropped without a word.

If you are unsure which fields a model accepts, GET /v1/images/models lists them, and GET /v1/images/models/{id}/endpoints returns the per-endpoint capabilities and pricing.

Cost, retries and slow calls

Each edit is one billed image when it completes, and nothing when it fails. Sume's docs say the amount in usage.cost is what the wallet is charged, with the 1.25 multiplier on provider list price already applied. That makes a retry cheap to reason about: a failed attempt costs zero.

Slow settings, such as 4K output, high quality or a large n, can push a call past the 30-second wait. Then the response is 202 with a job envelope rather than the image, and you fetch the result from the job endpoints.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume