Protocols

Studio Unified

One asynchronous image API for 🎨 GPT Image and 🍌 Nano Banana.

Let AI read the docs πŸ₯ΊπŸ‘‰AI docs
Protocol navigation

Switch protocols here

Examples

One image per job. Choose URL or Base64 when reading the result.

More parameters

The key stays in this browser and is used only for requests you send.

Need a key? Create oneChoose the 🎨 GPT Image group when creating your key.
ASYNC
$pip install httpx
import jsonimport httpximport timeapi_key = "YOUR_API_KEY"api_base = "https://api.1route.dev"payload = {    "model": "openai/gpt-image-2.5-flare",    "prompt": "Editorial portrait of a woman in profile beside a wind-bent tree, late afternoon light, deep cobalt coat, pale concrete wall, subtle film grain, restrained color palette, clean composition, vertical 4:5.",    "size": "auto"}headers = {"Authorization": f"Bearer {api_key}"}response = httpx.post(    api_base + "/api/v1/images/generations/jobs",    headers=headers,    json=payload,    timeout=1500,)response.raise_for_status()result = response.json()job_url = f"{api_base}/api/v1/images/jobs/{result['jobId']}"while result["phase"] in ("queued", "running"):    time.sleep(1.5)    snapshot = httpx.get(job_url, headers=headers, timeout=30)    snapshot.raise_for_status()    result = snapshot.json()if result["phase"] != "completed":    raise RuntimeError(result)response = httpx.get(f"{job_url}/result?response_format=base64", headers=headers, timeout=120)response.raise_for_status()result = response.json()print(json.dumps(result, ensure_ascii=False, indent=2))
Response
No request sent

OpenAPI integration

When calling the Studio HTTP API directly, ask your AI to read this OpenAPI document or import it into a tool that supports OpenAPI to inspect endpoints, request fields, and response schemas. Use it with the Studio guide for model extensions and the asynchronous job workflow when generating integration code.

This OpenAPI 3.1 document describes Studio generation, editing, job status, results, cancellation, SSE, and media endpoints. After import, configure the Base URL and API key shown on this page, then submit a job, poll its status, and retrieve its result.

Request lifecycle

Submit generation / edit
    ↓ 202 with jobId
queued β†’ running β†’ completed β†’ retrieve result β†’ save image
             β”œβ†’ failed
             β””β†’ cancelled

One job generates one image. For bulk generation, submit separate jobs, store their IDs, and respect the account's concurrency allowance. Studio uses the full user concurrency allowance reported by the site, shared across the same user's API keys. Jobs beyond that allowance remain queued. 202 means the job was created, not that the image is ready.

Generate an image

POSThttps://api.1route.dev/api/v1/images/generations/jobs
Default https://api.1route.devFrequent timeouts? Use https://image-api.1route.dev

Use Authorization: Bearer YOUR_API_KEY and a JSON request body.

Need a key? Create oneChoose the 🎨 GPT Image or 🍌 Nano Banana group for your model.

🎨 GPT Image

{
  "model": "openai/gpt-image-2.5-flare",
  "prompt": "A product photograph of a white ceramic cup, pale gray background, soft side light",
  "size": "1024x1024",
  "quality": "high"
}

model requires the openai/ prefix. Options are gpt-image-2, gpt-image-2.5-flare, and gpt-image-2.5-sunburst; gpt-image-2.5 is a Flare alias.

prompt is a non-empty description. size defaults to auto and accepts 1K, 2K, 4K, or WIDTHxHEIGHT. Pixel dimensions are mapped to an upstream tier.

Use the base model names above and select dimensions with size. If a client sends a -1k/-2k/-4k model alias recognized by this site, the tier derived from an explicit size takes precedence over the model suffix. For example, openai/gpt-image-2.5-sunburst-2k with 1824x1024 routes to 1K. With size=auto or an unrecognized model name, the requested model is retained.

quality is a model extension. Image 2 accepts auto, low, medium, and high; 2.5 adds xhigh and max. Higher quality may take longer. 🎨 GPT Image requests do not use resolution or aspect_ratio.

🍌 Nano Banana

{
  "model": "google/gemini-3.1-flash-image",
  "prompt": "A spring menu poster for a coffee shop, title SPRING MENU",
  "resolution": "2K",
  "aspect_ratio": "3:4"
}

Use google/gemini-3.1-flash-image (🍌 Nano Banana 2), google/gemini-3-pro-image (🍌 Nano Banana Pro), or google/gemini-nano-banana-2.1 (🍌 Nano Banana 2.1). resolution defaults to 1K; common options are 1K, 2K, and 4K. aspect_ratio defaults to 1:1; common ratios include 3:2, 2:3, 4:3, 16:9, and 9:16. Do not send size for Google models.

References and editing

POSThttps://api.1route.dev/api/v1/images/edits/jobs
Default https://api.1route.devFrequent timeouts? Use https://image-api.1route.dev
{
  "model": "openai/gpt-image-2.5-sunburst",
  "prompt": "Keep the cup's shape and logo. Change the background to a wooden table.",
  "size": "1024x1024",
  "images": [
    { "url": "https://your-image-host.example/product.png" },
    { "dataUrl": "data:image/png;base64,<image bytes>" }
  ]
}

images requires at least one item. Each item contains exactly one of url and dataUrl; the array can mix both and preserves order. The server downloads public URLs. Encode local files as complete Data URLs; Studio Unified does not accept multipart submissions.

For 🎨 GPT Image edits, an optional mask: { "image_url": "data:image/png;base64,..." } applies to the first reference. Transparent areas indicate the region to change. Describe the intended edit in the prompt as well.

Model-specific extensions

Other top-level fields are handled by the chosen native adapter. Examples include 🎨 GPT Image quality, output_format, output_compression, background, moderation, complexity, markup, safety_identifier, and GIF frame controls, and Google generationConfig, systemInstruction, and safetySettings.

Public prompt, images, and dimension fields own their corresponding content. For example:

{
  "model": "google/gemini-3-pro-image",
  "prompt": "A landscape exhibition poster with the words DESIGN WEEK",
  "resolution": "2K",
  "aspect_ratio": "16:9",
  "generationConfig": { "temperature": 0.7 }
}

OpenAI markup and 2.6 output extensions

Supporting GPT Image 2.5 / 2.6 models accept an optional transparent PNG markup layer on an edit. The public images array remains required; markup never adds or replaces a reference. Use markup.image_url with a public URL or complete Data URL, including in the playground's Additional JSON fields:

{
  "model": "openai/gpt-image-2.5-flare",
  "prompt": "Apply the annotated changes while preserving the rest of the product",
  "size": "1024x1024",
  "images": [{ "url": "https://your-image-host.example/product.png" }],
  "markup": { "image_url": "data:image/png;base64,<transparent PNG annotation bytes>" }
}

Markup must match the first reference's dimensions after image orientation, contain transparency, and be at most 50 MiB; both images must be at most 16,777,216 pixels. Do not combine it with mask or prompt_rewriter. markup.file_id is unsupported (unsupported_file_id, param=markup.file_id). See Native input rules and edit errors.

Official GPT Image 2.6 generation/edit accepts complexity: "low" | "medium" | "high" (upstream default high). Generation additionally supports SVG and animated GIF. These are OpenAI provider extensions, not Studio public fields or Gemini parameters. The exact official IDs are gpt-image-2.6-flare and gpt-image-2.6-sunburst; availability, supported sizes, and pricing come from the selected channel's current image catalog.

Conditional 2.6 generation examples below share the browser/code generator request constructor. SVG uses one image; GIF frame_count is 2–64 (default 9), and frame_duration_ms is 20–2000 (default 200), rounded upstream to 10 ms increments. SVG/GIF cannot be edit outputs and do not support partial_images, custom output_compression, or prompt_rewriter. Send compression only for JPEG/WebP. Studio provider calls remain non-streaming; its job SSE still reports progress.

SVG Β· POST /api/v1/images/generations/jobs

{  "complexity": "medium",  "output_format": "svg",  "model": "openai/gpt-image-2.6-flare",  "prompt": "A simple flat vector icon of a white ceramic cup",  "size": "auto"}

GIF Β· POST /api/v1/images/generations/jobs

{  "complexity": "medium",  "frame_count": 9,  "frame_duration_ms": 200,  "output_format": "gif",  "model": "openai/gpt-image-2.6-flare",  "prompt": "A seamless looping animation of steam rising from a ceramic cup",  "size": "auto"}

For SVG/GIF, keep the original returned bytes and images[].mimeType (image/svg+xml / image/gif). Do not convert originals through canvas for storage or download, or replace an animation with a static preview. Separate thumbnails and clipboard PNGs can be generated while retaining the original. See the Workbench and Image Studio guide and Canvas saving guide for the website workflows. Returned providerMetadata.openai.outputFormat and usage describe the actual upstream response; frame settings do not determine billing locally.

Submission response

{
  "jobId": "job_example",
  "phase": "queued",
  "durationGuidance": { "tier": "2K", "timeoutSeconds": 300, "milestones": [] }
}

Use jobId for subsequent operations. phase is the current state. durationGuidance contains the tier, timeout, and waiting-time guidance. Milestone items are omitted in this example; each contains percentile, seconds, level, cardMessage, detailTitle, and detailBody. These describe expected waiting time, not completion percentage. Use the actual response's timeout.

Query the job

GEThttps://api.1route.dev/api/v1/images/jobs/{jobId}
Default https://api.1route.devFrequent timeouts? Use https://image-api.1route.dev

Use the same key as the submission. The main response fields are shown below:

{
  "jobId": "job_example",
  "model": "openai/gpt-image-2.5-flare",
  "hasInputImage": false,
  "phase": "running",
  "createdAt": 1788940800000,
  "updatedAt": 1788940802000,
  "startedAt": 1788940801000,
  "durationGuidance": { "tier": "2K", "timeoutSeconds": 300, "milestones": [] }
}
PhaseMeaningNext step
queuedQueued for executionPoll or subscribe
runningGeneratingWait or cancel
completedImage generatedRetrieve the result
failedJob failedRead error
cancelledJob cancelledStop polling

createdAt, updatedAt, startedAt, and finishedAt are Unix milliseconds. Optional fields may be omitted until available.

queuePosition is the queue position, and message describes progress. Use phase to determine the job's state. usage contains known usage and error contains failure details.

Retrieve and save the image

GEThttps://api.1route.dev/api/v1/images/jobs/{jobId}/result
Default https://api.1route.devFrequent timeouts? Use https://image-api.1route.dev
{
  "images": [{
    "url": "https://api.1route.dev/api/v1/images/files/media_example",
    "base64": "<complete image bytes>",
    "mimeType": "image/png",
    "revisedPrompt": "<present when returned by the upstream>"
  }],
  "usage": {},
  "providerMetadata": {"openai": {"quality": "high", "outputFormat": "png", "outputCompression": 0, "moderation": "auto", "size": "1536x1024", "model": "gpt-image-2.5-flare"}}
}

By default, results include both url and base64. mimeType identifies the format. OpenAI may provide revisedPrompt per image and returned quality, background, outputFormat, outputCompression, moderation, size, and model under providerMetadata.openai; Gemini uses providerMetadata.gemini.modelVersion. These fields appear only when returned by the upstream and are never filled from request values. Read images.length for the image count and usage.response for response dimensions, tiers, and billing. Select the image representation with the response_format query when reading the result:

ValueFields returned for each image
urlurl, mimeType
base64base64, mimeType
both (default)url, base64, mimeType

For example, GET /api/v1/images/jobs/{jobId}/result?response_format=url returns image URLs and MIME types without Base64. Unselected fields are omitted, rather than set to null. Empty or other values return 400 invalid_value with error.param=response_format.

Read the same job in different representations without generating again. OpenAI and Google models follow the same rule. Keep this query out of the submission JSON; it does not control Gemini upstream INLINE / URI delivery. All formats follow the same media availability and expiry rules. The following save example applies to base64 or both:

import base64
from pathlib import Path

image = result["images"][0]
Path("output.png").write_bytes(base64.b64decode(image["base64"]))

Images and stored results are retained for 24 hours, then cleaned up. Download them for long-term use. Media endpoints support GET and HEAD; expired content returns 410 result_expired.

SSE progress and cancellation

GET /api/v1/images/jobs/{jobId}/events returns text/event-stream. Event names match phases such as running and completed; data contains a snapshot. heartbeat events contain {}. The connection ends after a terminal phase.

event: running
data: {"jobId":"job_example","phase":"running",...}

event: heartbeat
data: {}

DELETE /api/v1/images/jobs/{jobId} requests cancellation and returns a snapshot. A job that has already finished may still return completed; inspect the returned phase. Closing a browser wait or SSE connection does not cancel the job. For distributed execution, cancellation is accepted before the first upstream permit. Once execution has started, the service returns 409 job_not_cancellable and the job continues; keep polling or waiting for its result. Cancelling a terminal job returns its current snapshot.

Idempotency and errors

Submissions accept Idempotency-Key. The same API key, idempotency value, and request return the original job; a different request with the same idempotency value returns 409.

HTTP errors contain error.status, message, type, code, and param. Generation failures after acceptance appear in the job snapshot's error.

HTTP statusCommon cause
400Invalid model prefix, dimensions, reference, or fields
401Missing or invalid key
404Job not found or owned by another key
409Idempotency conflict, cancellation refused after distributed execution started, unfinished or cancelled result
410Expired image or result
413Request exceeds the body limit
415Submission is not application/json
429Quota or concurrency; inspect the error
500 / 502 / 504Job, media, upstream, or timeout error

Request bodies are limited to 512 MiB and each input media file to 80 MiB; model-level limits also apply. For frequent timeouts, use the alternate address shown on this page.