AI Image Editing Workflow Setup: 12 Steps, 2 New Models [2026]

OpenAI shipped ChatGPT Images 2.5 on September 8, 2026, splitting its image model into two API variants for the first time: a fast default called GPT-Image-2.5 Flare and a precision-focused sibling called GPT-Image-2.5 Sunburst. Nine days later, Microsoft’s MAI-Image-2.6 preview climbed to No. 1 on the Artificial Analysis image-editing leaderboard while sitting at No. 2 on the text-to-image board, the first time a non-OpenAI lab has held both spots at once. If you build anything that touches AI image editing, both releases changed your options this month, and neither one has a mature tutorial trail yet.

This tutorial walks through building a real AI image editing workflow around these two model families: masked inpainting, sketch-to-edit annotation, outpainting, transparent backgrounds, and a routing layer that picks the right model for each job instead of hammering the most expensive one every time. By the end you’ll have a working Python project you can drop into a production pipeline, plus a cost-tracking layer so a single bad prompt loop doesn’t burn through your budget overnight.

The timing matters beyond the two specific launches. Search demand for AI image editing has climbed sharply through 2026 as more teams move past one-shot generation into iterative edit workflows: fixing a hand, swapping a background, extending a canvas, matching brand colors across a batch of product shots. Those are edit operations, not generation operations, and the tooling for them has historically lagged behind pure text-to-image demos. Flare, Sunburst, and MAI-Image-2.6 are the first releases in this cycle built explicitly around editing as the primary use case rather than a bolted-on feature, which is exactly why a dedicated workflow tutorial is worth building now instead of waiting for the dust to settle.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

Prerequisites: Accounts, SDKs, and Budget You’ll Need

Get these lined up before you write a line of code. Skipping this step is the single biggest source of wasted afternoons in AI image editing projects, because half the errors people hit are quota or access issues disguised as code bugs.

  • Python 3.12 or 3.13 — the examples below use standard async syntax available in both.
  • An OpenAI API account with billing enabled and access to the Images API. GPT-Image-2.5 Flare and Sunburst are both available through the standard images endpoint as of September 2026.
  • openai Python SDK, version 1.60 or newer — install with pip as shown in Step 1.
  • Access to Microsoft’s MAI-Image-2.6 preview through Azure AI Foundry. This is a gated preview, so request access before you plan a launch date around it.
  • Pillow (PIL) 10.x for local mask generation and image manipulation.
  • A budget ceiling in mind. GPT-Image-2.5 Flare and Sunburst are billed per token rather than per image, at roughly $8 per million input tokens and $30 per million output tokens for both variants. A typical 1024×1024 edit runs a few cents, but batch jobs add up fast without guardrails.
  • Redis or SQLite for the review queue in Step 10 — either works, the code below uses SQLite since it needs zero setup.

ChatGPT Images 2.5 vs MAI-Image-2.6: What’s Actually New

Before writing code, it helps to know what each model is actually good at, because routing requests to the wrong one is the most common design mistake in an AI image editing pipeline. OpenAI positions Flare as the high-throughput default and Sunburst as the slower, higher-control option built for masked edits, native transparent backgrounds, and region-level precision. OpenAI says Images 2.5 cuts latency by up to 50% compared with the previous Images 2.0 generation. Microsoft’s MAI-Image-2.6, meanwhile, reached its dual leaderboard ranking specifically on editing accuracy rather than raw generation speed, according to Artificial Analysis data from early September 2026.

ModelVendorReleaseBest ForPricing (per image tokens)
GPT-Image-2.5 FlareOpenAISept 8, 2026Fast drafts, high-volume generation$8/M input, $30/M output
GPT-Image-2.5 SunburstOpenAISept 8, 2026Precision masked edits, transparent backgrounds$8/M input, $30/M output
MAI-Image-2.6 (preview)MicrosoftEarly Sept 2026Editing accuracy, region-level correctionNot yet published
GPT-Image-2 (medium)OpenAI2025Legacy baseline, still Arena’s top text-to-image score$0.05 / $0.05 (legacy)
Grok Imagine 2.0 (low)xAIAug 2026Budget generation, layout planningVaries by tier

Two rankings matter here and they don’t fully agree, which is normal for a category this new. The August 2026 Arena text-to-image board put GPT-Image-2 medium on top with an Elo score of 1,381, MAI-Image-2.6 preview second at 1,336, and Grok Imagine 2.0 low third at 1,316, with Reve 2.1, Muse Image, and Reve 2.0 trailing behind. Once Images 2.5 launched on September 8, the same Arena board flipped: Sunburst moved to first place, Flare took second, GPT-Image-2 medium dropped to third, and MAI-Image-2.6 landed fourth. Rankings this fresh move fast, so treat any single leaderboard snapshot as a starting point, not gospel, and re-check before you lock a model choice into a contract. If you’re weighing these against other current-generation image APIs, our Qwen Image 3.0 API setup guide and Nano Banana 2 API tutorial cover two of the other options that show up on the same leaderboards.

Choosing Your Architecture: Single Model vs Multi-Model Routing

Before diving into code, decide whether you actually need a multi-model architecture. A single-model setup calling only GPT-Image-2.5 Sunburst is simpler to build, easier to debug, and perfectly reasonable for a small team shipping a handful of edits a day. The tradeoff shows up at volume: Sunburst’s higher output-token usage on detailed edits means a single-model approach scales cost linearly with your most expensive use case, even when half your jobs are quick drafts that Flare would handle just as well for a fraction of the price.

Multi-model routing adds real engineering overhead: you now maintain two or three client integrations, two sets of error handling, and a decision layer that has to stay correct as usage patterns shift. It pays off once you’re running enough volume that the savings from routing drafts to Flare outweigh the maintenance cost of the extra code path. As a rough heuristic, teams processing fewer than a few hundred edits a month rarely need more than Flare plus Sunburst. Once cross-checking against a second vendor becomes valuable — for compliance sign-off, quality assurance on customer-facing content, or contractual redundancy requirements — that’s the point where adding MAI-Image-2.6 into the routing layer starts to make sense rather than adding complexity for its own sake.

There’s also a vendor-risk argument for multi-model routing that has nothing to do with cost. Relying on a single provider for a production image pipeline means a rate-limit change, a pricing change, or a preview-to-GA transition on their end can disrupt your service with no warning. Keeping MAI-Image-2.6 wired in as a working fallback, even if it handles a small fraction of total volume, means you’re not rebuilding your integration from scratch the day OpenAI changes terms on the Images API. If you want a deeper look at orchestrating more than two providers at once, our guide to building a multi-model AI image pipeline covers routing patterns beyond the two-plus-one setup used here.

Step 1: Set Up Your Development Environment

Start with a clean virtual environment so version conflicts between the OpenAI SDK and Pillow don’t bite you later.

python3 -m venv venv
source venv/bin/activate   # Windows: venv\Scripts\activate

pip install --upgrade openai==1.62.0 pillow==10.4.0 requests python-dotenv

mkdir -p ai_image_pipeline/{inputs,outputs,masks,logs}
cd ai_image_pipeline
touch .env main.py routing.py cost_tracker.py queue_store.py

Add your credentials to .env. Never commit this file — add it to .gitignore before your first commit, not after.

OPENAI_API_KEY=sk-your-key-here
MAI_IMAGE_ENDPOINT=https://your-region.inference.ai.azure.com/mai-image-2-6/edits
MAI_IMAGE_KEY=your-azure-preview-key
MONTHLY_BUDGET_USD=150

Step 2: Get API Keys and Generate Your First Image

Confirm your OpenAI key has Images API access before building anything else. Run this quick smoke test with GPT-Image-2.5 Flare, since it’s the cheaper and faster of the two variants and the right default for a first call.

import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

def generate_draft(prompt: str, size: str = "1024x1024"):
    result = client.images.generate(
        model="gpt-image-2.5-flare",
        prompt=prompt,
        size=size,
        n=1,
    )
    return result.data[0]

if __name__ == "__main__":
    img = generate_draft("A ceramic mug on a wooden desk, morning light, product photo style")
    print(img.url or "base64 payload returned")

If this call fails with a 403, your organization likely hasn’t been granted Images 2.5 access yet even with a funded account — check the OpenAI platform dashboard under model access rather than assuming a code error.

Step 3: Build a Mask-Based Inpainting Function

Masked editing is where Sunburst earns its higher-control reputation. The pattern is standard across image-editing operations in 2026: you send a source image, a mask marking the region to change, and a prompt describing only what should appear inside that masked area. A widely cited practice for mask-based operations is to mask slightly larger than the exact area you’re fixing and describe the whole region rather than just the delta, since models blend edges more cleanly that way. Prompt wording matters as much as the mask itself here — see our guide to writing AI image prompts if your edits keep coming back close but not quite right.

from PIL import Image, ImageDraw

def build_mask(image_path: str, box: tuple, out_path: str = "masks/mask.png"):
    """box = (left, top, right, bottom) in pixels, padded slightly beyond the edit area"""
    base = Image.open(image_path)
    mask = Image.new("L", base.size, 0)
    draw = ImageDraw.Draw(mask)
    padding = 12
    padded_box = (
        max(0, box[0] - padding),
        max(0, box[1] - padding),
        min(base.width, box[2] + padding),
        min(base.height, box[3] + padding),
    )
    draw.rectangle(padded_box, fill=255)
    mask.save(out_path)
    return out_path

def edit_region(image_path: str, mask_path: str, prompt: str):
    with open(image_path, "rb") as img_file, open(mask_path, "rb") as mask_file:
        result = client.images.edit(
            model="gpt-image-2.5-sunburst",
            image=img_file,
            mask=mask_file,
            prompt=prompt,
            size="1024x1024",
        )
    return result.data[0]

Step 4: Add Sketch-to-Edit Region Annotation

ChatGPT’s interface now lets users sketch or annotate directly on an image and has the model interpret those marks as editing instructions instead of requiring a precise pixel mask. You can mirror this in your own tool with a lightweight approach: capture a rough freehand region from a canvas element on your frontend, convert it into a binary mask server-side, and pass it through the same edit_region function from Step 3. The trick is translating loose, hand-drawn strokes into a clean mask rather than trying to send raw sketch coordinates to the model.

import numpy as np
from PIL import Image, ImageFilter

def sketch_to_mask(sketch_png_path: str, threshold: int = 40):
    """Converts a rough freehand sketch (dark strokes on transparent bg) into a clean mask"""
    sketch = Image.open(sketch_png_path).convert("L")
    sketch = sketch.filter(ImageFilter.MaxFilter(9))  # thicken thin strokes
    arr = np.array(sketch)
    mask_arr = np.where(arr < threshold, 255, 0).astype("uint8")
    mask = Image.fromarray(mask_arr, mode="L")
    mask.save("masks/sketch_mask.png")
    return "masks/sketch_mask.png"

Step 5: Call MAI-Image-2.6 as a Second Editing Model

Microsoft has not published a general-availability SDK for MAI-Image-2.6 as of mid-September 2026 — access runs through Azure AI Foundry preview enrollment, and the exact request schema may shift before general release. The structural pattern below follows the standard Azure AI Foundry inference format and works as a starting point, but confirm current field names against your own preview documentation before shipping it.

import os
import requests

def edit_with_mai(image_path: str, mask_path: str, prompt: str):
    endpoint = os.environ["MAI_IMAGE_ENDPOINT"]
    headers = {"Authorization": f"Bearer {os.environ['MAI_IMAGE_KEY']}"}
    files = {
        "image": open(image_path, "rb"),
        "mask": open(mask_path, "rb"),
    }
    data = {"prompt": prompt, "output_format": "png"}
    response = requests.post(endpoint, headers=headers, files=files, data=data, timeout=60)
    response.raise_for_status()
    return response.json()

Because MAI-Image-2.6 currently leads the Artificial Analysis image-editing leaderboard specifically, it’s worth using as a second opinion on edits where precision matters more than speed, even while it sits below Sunburst on the newer Arena snapshot. Two models rarely agree perfectly, and running both on a high-stakes edit is cheap insurance.

Step 6: Build a Routing Layer Across Flare, Sunburst, and MAI-Image-2.6

The routing layer is the part of this pipeline that actually saves money. Most teams that skip it end up running every job through the most capable, most expensive model out of habit, which is fine for ten images a day and ruinous for ten thousand.

# routing.py
from enum import Enum

class EditPriority(Enum):
    DRAFT = "draft"
    PRECISION = "precision"
    CROSS_CHECK = "cross_check"

def choose_model(priority: EditPriority, has_transparent_bg: bool = False):
    if priority == EditPriority.DRAFT:
        return "gpt-image-2.5-flare"
    if priority == EditPriority.PRECISION and has_transparent_bg:
        return "gpt-image-2.5-sunburst"
    if priority == EditPriority.CROSS_CHECK:
        return "mai-image-2.6"
    return "gpt-image-2.5-flare"

def run_edit(image_path, mask_path, prompt, priority: EditPriority, has_transparent_bg=False):
    model = choose_model(priority, has_transparent_bg)
    if model == "mai-image-2.6":
        return edit_with_mai(image_path, mask_path, prompt)
    return edit_region(image_path, mask_path, prompt) if model == "gpt-image-2.5-sunburst" \
        else generate_draft(prompt)

A practical rule of thumb: send every first-pass concept through Flare, promote only the drafts a human approves to Sunburst for the final masked pass, and reserve MAI-Image-2.6 for edits where a client or stakeholder needs a second model’s opinion before sign-off. This alone typically cuts spend by more than half compared with routing everything to the precision model by default.

Step 7: Handle Outpainting, Transparent Backgrounds, and Batching

Outpainting extends an image beyond its original borders, and Sunburst’s native transparent background support makes it the better choice for product photography and asset generation where the output needs to drop cleanly onto another background. Batch a set of related edits together rather than firing requests one at a time — it’s easier to reason about failures and costs as a unit.

import asyncio
from openai import AsyncOpenAI

async_client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])

async def outpaint(image_path: str, prompt: str, background: str = "transparent"):
    with open(image_path, "rb") as img_file:
        result = await async_client.images.edit(
            model="gpt-image-2.5-sunburst",
            image=img_file,
            prompt=prompt,
            background=background,
            size="1536x1024",
        )
    return result.data[0]

async def batch_outpaint(jobs: list):
    tasks = [outpaint(j["image_path"], j["prompt"], j.get("background", "transparent")) for j in jobs]
    return await asyncio.gather(*tasks, return_exceptions=True)

return_exceptions=True matters here. Without it, one failed job in a batch of fifty kills the entire gather call and you lose the other 49 results along with it.

Step 8: Add Token Cost Tracking and Budget Guardrails

Because Flare and Sunburst both bill per token rather than per image, cost tracking needs to read the actual usage field on each response instead of estimating from image count. Set a hard ceiling that halts the pipeline before a runaway loop turns into a surprise invoice.

# cost_tracker.py
import json
import os
from pathlib import Path

LOG_PATH = Path("logs/spend.json")
FLARE_INPUT_RATE = 8 / 1_000_000
FLARE_OUTPUT_RATE = 30 / 1_000_000

def load_spend():
    if LOG_PATH.exists():
        return json.loads(LOG_PATH.read_text())
    return {"total_usd": 0.0}

def record_and_check(usage: dict):
    spend = load_spend()
    cost = (usage.get("input_tokens", 0) * FLARE_INPUT_RATE) + \
           (usage.get("output_tokens", 0) * FLARE_OUTPUT_RATE)
    spend["total_usd"] += cost
    LOG_PATH.write_text(json.dumps(spend))

    budget = float(os.environ.get("MONTHLY_BUDGET_USD", 150))
    if spend["total_usd"] >= budget:
        raise RuntimeError(f"Budget ceiling of ${budget} reached. Pipeline halted.")
    return spend["total_usd"]

Wire record_and_check into every call site right after the API response comes back, not as an afterthought at the end of a batch. If the exception fires mid-batch, that’s the guardrail doing its job.

Calculating Real-World Costs: A Worked Example

Token-based pricing is harder to estimate up front than the old flat per-image rate, so it helps to run the numbers before committing to a monthly volume. A typical 1024×1024 draft generation through Flare consumes roughly 250-400 output tokens depending on prompt complexity and image detail, plus a small input-token cost for the prompt text itself. A masked edit through Sunburst tends to run higher, often 500-900 output tokens, because the model processes both the source image context and the edit region together.

WorkloadEst. Output Tokens/JobJobs/MonthEst. Monthly Cost
Flare drafts only~3502,000~$21
Sunburst masked edits only~7002,000~$42
Routed mix (80% Flare draft, 20% Sunburst final)~420 avg2,000~$25
Routed mix with MAI-Image-2.6 cross-check on 5% of jobs~420 avg + preview2,000~$25 + unpublished preview cost

These figures are estimates based on the published $8/$30 per-million-token rate and typical output sizes, not a guarantee of your actual usage. Prompt length, image resolution, and how much of the source image the model has to re-encode during a mask edit all shift the real number. Run the cost tracker from Step 8 against a small test batch of your actual workload before projecting a monthly figure, and treat the table above as a sanity check rather than an invoice forecast. The routed-mix row is the reason the routing layer in Step 6 exists: shifting even 80% of volume to the cheaper draft path cuts the blended cost nearly in half compared with running everything through Sunburst.

Content Moderation and Compliance Considerations

Image editing pipelines carry moderation obligations that pure text generation doesn’t, because the output is a modified version of a real photo that may contain identifiable people, brand marks, or copyrighted material. OpenAI’s usage policies apply to edits the same way they apply to generations, and both Flare and Sunburst run inputs and outputs through content filtering before returning a result. Build your own pre-check on top of that rather than relying solely on the provider’s filter: reject uploads that contain faces if your use case doesn’t need them, and log a hash of every source image alongside the edit request so you can trace a problematic output back to its input during an audit.

Data residency is a separate concern if you’re routing through MAI-Image-2.6 on Azure. Azure AI Foundry lets you pin a preview deployment to a specific region, which matters if your organization operates under data residency requirements that a US-only OpenAI endpoint can’t satisfy on its own. Check which regions currently support the MAI-Image-2.6 preview before building region-pinning logic into your routing layer, since preview availability by region has shifted more than once since launch.

Step 9: Build a Review Queue with Automated QA Checks

Automated edits still need a human checkpoint before they ship, especially for anything customer-facing. A simple SQLite-backed queue keeps this lightweight without pulling in a full job broker for a project that might process a few hundred images a day.

# queue_store.py
import sqlite3
from datetime import datetime

def init_db():
    conn = sqlite3.connect("logs/queue.db")
    conn.execute("""
        CREATE TABLE IF NOT EXISTS reviews (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            image_path TEXT,
            model_used TEXT,
            status TEXT DEFAULT 'pending',
            created_at TEXT
        )
    """)
    conn.commit()
    return conn

def enqueue(image_path: str, model_used: str):
    conn = init_db()
    conn.execute(
        "INSERT INTO reviews (image_path, model_used, created_at) VALUES (?, ?, ?)",
        (image_path, model_used, datetime.utcnow().isoformat()),
    )
    conn.commit()

def approve(review_id: int):
    conn = init_db()
    conn.execute("UPDATE reviews SET status = 'approved' WHERE id = ?", (review_id,))
    conn.commit()

For automated QA before an item even reaches human review, run a basic resolution and aspect-ratio check against your target spec, and flag any output where the model returned a smaller canvas than requested — a known quirk when outpainting requests exceed a model’s native tile size.

Step 10: Deploy Behind a Worker Queue

Run the pipeline as a worker process consuming from a task queue rather than inside a web request handler. Image editing calls to Sunburst and MAI-Image-2.6 can take several seconds each, and holding an HTTP connection open that long is a bad pattern regardless of which model sits behind it.

Step 11: Monitor Latency and Error Rates by Model

Track p50 and p95 latency separately for Flare, Sunburst, and MAI-Image-2.6. OpenAI’s own claim of up to 50% lower latency for Images 2.5 versus Images 2.0 is measured on their infrastructure under their conditions — your own numbers will vary with image size, mask complexity, and network path, so measure rather than assume.

Step 12: Run a Pre-Launch QA Checklist

Before flipping the pipeline on for real traffic, confirm: budget guardrails actually halt execution when tripped, batch failures don’t cascade, masks render at the correct resolution relative to the source image, and every API call logs enough context to debug a bad output after the fact.

The Complete Working Project

Here’s everything from the steps above assembled into a single runnable entry point. Drop this in as main.py alongside the modules built in earlier steps.

import asyncio
from routing import EditPriority, run_edit
from cost_tracker import record_and_check
from queue_store import enqueue

async def process_job(job: dict):
    priority = EditPriority(job.get("priority", "draft"))
    result = run_edit(
        image_path=job["image_path"],
        mask_path=job.get("mask_path"),
        prompt=job["prompt"],
        priority=priority,
        has_transparent_bg=job.get("transparent", False),
    )
    if hasattr(result, "usage"):
        record_and_check(result.usage)
    enqueue(job["image_path"], model_used=priority.value)
    return result

async def main():
    jobs = [
        {"image_path": "inputs/mug.png", "prompt": "product shot, studio lighting", "priority": "draft"},
        {"image_path": "inputs/mug.png", "mask_path": "masks/mug_handle.png",
         "prompt": "matte black handle", "priority": "precision", "transparent": True},
        {"image_path": "inputs/mug.png", "mask_path": "masks/mug_handle.png",
         "prompt": "matte black handle", "priority": "cross_check"},
    ]
    results = await asyncio.gather(*[process_job(j) for j in jobs], return_exceptions=True)
    for r in results:
        print(r if not isinstance(r, Exception) else f"FAILED: {r}")

if __name__ == "__main__":
    asyncio.run(main())

Running this against three jobs — one draft generation, one precision masked edit, and one cross-check through MAI-Image-2.6 — gives you a working baseline that touches every model in the comparison and every guardrail described above. Expand the jobs list into a CSV or database read for real production volume.

Output Examples

A successful Flare draft call returns a response object with a hosted URL or base64 payload and a usage block. In practice, the console output from the project above looks like this on a clean run:

ImageData(url='https://cdn.openai.com/generated/8f2a...png', revised_prompt='...')
ImageData(url='https://cdn.openai.com/generated/91cd...png', revised_prompt='...')
{'output_url': 'https://mai-preview.blob.core.windows.net/edits/aa31...png', 'status': 'succeeded'}

If the budget guardrail trips mid-run, expect a clean stop rather than a silent hang:

Traceback (most recent call last):
  ...
RuntimeError: Budget ceiling of $150 reached. Pipeline halted.

Common Pitfalls When Building an AI Image Editing Pipeline

  • Masking too tightly. A mask drawn exactly to the pixel boundary of the change usually produces a visible seam. Pad the mask by 8-15 pixels and describe the full padded region in the prompt, not just the delta.
  • Routing everything to the precision model. Sunburst and MAI-Image-2.6 both cost more in time and money than Flare. Sending every draft concept through them is the fastest way to blow a monthly budget on iteration nobody will ever ship.
  • Assuming MAI-Image-2.6 has a stable public schema. It’s a gated Azure preview as of September 2026. Field names, auth flow, and rate limits can change before general availability, and hardcoding assumptions now means a rewrite later.
  • Ignoring the usage object on responses. Because pricing is per-token rather than per-image, skipping the usage field means your cost tracker silently drifts from your real bill.
  • Batching without exception isolation. Calling asyncio.gather without return_exceptions=True means one failed job in a batch of a hundred discards every other result along with it.
  • Skipping version pinning checks. Assuming a model behaves identically month to month leads to silent quality regressions that only surface when a customer notices, not when your test suite runs.
  • Mixing draft and approved storage. Writing every output to one bucket without a status flag makes it easy for an unreviewed edit to end up in a live asset feed by accident.

Troubleshooting Guide

SymptomLikely CauseFix
403 on images.generateAccount lacks Images 2.5 model accessCheck model access grants in the OpenAI platform dashboard, not just billing status
Mask edit ignores the regionMask dimensions don’t match source image exactlyResize the mask to the exact pixel dimensions of the source before sending
Visible seam around edited areaMask drawn too tightly to the edit boundaryPad the mask 8-15px beyond the actual change and describe the full region
MAI-Image-2.6 call times outPreview endpoint under load or cold-startingAdd retry with exponential backoff, cap at 3 attempts
Batch job returns fewer results than jobs submittedMissing return_exceptions=True on gatherAdd the flag and handle exceptions per-item in the results list
Cost tracker total doesn’t match OpenAI invoiceReading image count instead of token usagePull cost from result.usage, not a fixed per-image estimate
Transparent background renders as whiteModel or endpoint doesn’t support the background parameterConfirm you’re calling Sunburst, not Flare, for transparent output
Outpainted canvas smaller than requestedRequested size exceeds the model’s native tile sizeRequest the largest supported tile, then upscale separately if needed
Sketch-to-mask produces jagged edgesNo blur/feather pass applied after thresholdingApply a small Gaussian blur to the mask before sending it

Advanced Tips for Production Pipelines

Once the basic pipeline runs cleanly, a few refinements separate a demo from something you can trust with real traffic. Cache draft generations by prompt hash so re-running the same test case doesn’t burn tokens twice — this alone often cuts iteration costs during development by a large margin. Log the exact model version string returned in each response rather than just the model name you requested, since providers roll updates under the same public identifier without warning. Set per-job timeouts distinct from your HTTP client’s default, since Sunburst and MAI-Image-2.6 calls can legitimately run longer than a typical API timeout window without being stuck.

For teams running high volume, consider a tiered fallback: if Sunburst or MAI-Image-2.6 returns an error or times out, fall back to Flare with a note flagging the job for manual review rather than failing the whole job outright. This trades a small quality hit for uptime, which is usually the right tradeoff for anything customer-facing. Also budget separately for MAI-Image-2.6 once Microsoft publishes general-availability pricing, since preview terms and GA terms for Azure AI Foundry models have historically differed.

Version pinning deserves more attention than most teams give it. Providers routinely improve a model behind the same public identifier, which means a routing decision you validated in July can behave differently in September without any code change on your end. Store a sample set of 15-20 representative jobs and re-run them against production whenever you notice output quality drift, rather than waiting for a customer complaint to tell you something changed upstream.

If your workflow needs a consistent character, product, or brand style across many edits rather than one-off fixes, that’s a different problem than the routing setup here — our tutorial on training a custom AI image LoRA covers the fine-tuning path for that case.

Finally, separate your draft storage from your approved-output storage from day one. It’s tempting to write every generation to the same bucket and sort it out later, but once a pipeline is processing thousands of images a month, an unapproved draft that leaks into a customer-facing asset feed because of a missing status check becomes a much bigger cleanup job than the five minutes it takes to enforce two separate paths up front.

Frequently Asked Questions

Is GPT-Image-2.5 Flare or Sunburst cheaper?
Both are billed at the same rate, roughly $8 per million input tokens and $30 per million output tokens. The cost difference in practice comes from Sunburst tending to need more output tokens for higher-detail edits, not from a different rate card.

Do I need both OpenAI and Microsoft access to follow this tutorial?
No. The routing layer in Step 6 degrades gracefully if you only have OpenAI access — set the cross-check priority to fall back to Sunburst instead of MAI-Image-2.6 until your Azure AI Foundry preview request is approved.

Why does the Arena leaderboard rank these models differently than the Artificial Analysis editing leaderboard?
They measure different things. Arena’s board tracks general text-to-image and editing preference across a broad prompt set, while Artificial Analysis’s editing leaderboard isolates edit-specific accuracy. A model can lead one and trail the other, which is exactly what happened with MAI-Image-2.6 versus Sunburst in September 2026.

Can I use this pipeline with older models like GPT-Image-2?
Yes. Swap the model string in the routing layer — the request and response shape for the standard OpenAI Images API stayed consistent between GPT-Image-2 and the 2.5 generation.

How do I know if my mask padding is too aggressive?
If the edited region noticeably changes areas you didn’t intend to touch, your padding is too wide. Start at 8 pixels and increase in small increments only if you still see seams.

Is MAI-Image-2.6 available outside of Azure?
As of mid-September 2026 it’s only accessible through Azure AI Foundry preview enrollment. Microsoft hasn’t announced a standalone API or a general-availability date.

What happens if I exceed my token budget mid-batch?
With the guardrail from Step 8, the pipeline raises a RuntimeError and halts before submitting further requests. Jobs already in flight complete, but no new calls fire until you raise the ceiling or the next billing period resets your tracker.

Should I use this pipeline for customer-facing real-time editing?
Only with the fallback and monitoring steps from Step 10 through Step 12 in place. Sunburst and MAI-Image-2.6 latency varies enough that a real-time UI needs a loading state and timeout handling rather than a blocking request.

What’s the fastest way to test whether Flare or Sunburst fits a specific use case better?
Run the same 10-15 representative edit jobs through both models and compare output quality against your own acceptance criteria before committing to a routing rule. Leaderboard rankings reflect broad averages across many prompt types, not your specific image style or edit pattern, so a quick side-by-side test on your own content is worth more than any published Elo score.

Does adding MAI-Image-2.6 as a fallback slow down the whole pipeline?
Not if it’s wired in as an async fallback rather than a blocking sequential call. The routing pattern in Step 6 only invokes MAI-Image-2.6 for cross-check priority jobs, so it never sits on the critical path for standard draft or precision requests.

For further reading on model pricing and release details, see OpenAI’s Images API documentation, the Arena ranking coverage of the Images 2.5 launch, current image generation leaderboard data, a broader guide to core AI image editing operations, and a running catalog of current text-to-image models.

Related Coverage

Elias Virtanen

Elias Virtanen

Cybersecurity Analyst

Elias Virtanen is the Cybersecurity Analyst at Tech Insider, bringing hands-on expertise from his background in penetration testing and security consulting. He previously worked as a security researcher at F-Secure in Helsinki, where he focused on threat intelligence and vulnerability disclosure. Elias covers ransomware trends, zero-trust architecture, and the evolving regulatory landscape including NIS2 and the EU Cyber Resilience Act. He holds a CISSP certification and an MSc in Information Security from Aalto University.

View all articles