Image Generation

POST /v1/images/generations

Generate one or more images from a text prompt. Compatible (with extensions) with the OpenAI Images API.

Headers

Header Required Description
Authorization Yes Bearer <api-key-or-jwt>
Content-Type Yes application/json
X-Quantized-Provider No Force a specific provider (openai or gemini). Otherwise resolved per-model from the catalog.

Request body

Field Type Required Default Description
model string Yes — Model identifier (e.g. gpt-image-1.5, gpt-image-2, gemini-3.1-flash-image, imagen-4.0-fast-generate-001)
prompt string Yes — Text description of the image to generate
n integer No 1 Number of images to generate. Range 1..10 at the serializer; per-model upper bounds are stricter (see Per-model constraints)
size string No "1024x1024" Image dimensions as WxH, or "auto". Normalized per-provider to the nearest supported aspect ratio
quality string No provider default One of standard, hd, low, medium, high, auto
style string No null vivid or natural. Accepted for compatibility; no currently routable model uses it
background string No null transparent, opaque, auto. gpt-image-* only — stripped elsewhere
output_format string No null png, jpeg, webp. gpt-image-* only — stripped elsewhere
output_compression integer No null 0..100 JPEG/WebP quality. gpt-image-* only
moderation string No null auto or low. gpt-image-* only
seed integer No null Deterministic seed. Accepted for compatibility; no currently routable model accepts one — silently dropped
negative_prompt string No null Text describing what to avoid. Accepted for compatibility; no currently routable model accepts one — silently dropped
user string No null End-user identifier forwarded to the provider for abuse monitoring
Strict validation

The serializer uses extra="forbid" — any field not listed above is rejected with 422. This keeps typos from being silently dropped.

Notable fields not accepted in this release: response_format (transport is forced to base64 — see below), messages, dimensions, image/mask (those belong to the not-yet-shipped /v1/images/edits endpoint).

Output transport is always base64

The router returns b64_json for every response. Read images from data[].b64_json. There is no data[].url field. OpenAI itself removed the response_format parameter from /v1/images/generations in 2026, so even on the upstream side everything is base64. Gemini has always been base64 natively, so the contract is uniform across providers.

Examples

cURL — gpt-image-1.5
cURL — transparent background
cURL — Gemini
Python (OpenAI SDK)
Python (httpx)
curl -X POST https://api.quantized.us/v1/images/generations \
  -H "Authorization: Bearer sk-quantized-YOUR-KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1.5",
    "prompt": "A whimsical watercolor of a sleepy hedgehog under a mushroom",
    "size": "1024x1024",
    "quality": "low"
  }'
curl -X POST https://api.quantized.us/v1/images/generations \
  -H "Authorization: Bearer sk-quantized-YOUR-KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1.5",
    "prompt": "A logo on a fully transparent background, single hedgehog character",
    "quality": "medium",
    "background": "transparent",
    "output_format": "png"
  }'
curl -X POST https://api.quantized.us/v1/images/generations \
  -H "Authorization: Bearer sk-quantized-YOUR-KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.1-flash-image",
    "prompt": "A whimsical watercolor of a sleepy hedgehog under a mushroom"
  }'
import base64
from openai import OpenAI

client = OpenAI(
    api_key="sk-quantized-YOUR-KEY",
    base_url="https://api.quantized.us/v1",
)

resp = client.images.generate(
    model="gpt-image-1.5",
    prompt="A whimsical watercolor of a sleepy hedgehog",
    size="1024x1024",
    quality="low",
)
img_bytes = base64.b64decode(resp.data[0].b64_json)
with open("hedgehog.png", "wb") as f:
    f.write(img_bytes)
import base64
import httpx

response = httpx.post(
    "https://api.quantized.us/v1/images/generations",
    headers={"Authorization": "Bearer sk-quantized-YOUR-KEY"},
    json={
        "model": "gpt-image-1.5",
        "prompt": "An overhead view of an open notebook with a pen",
        "size": "1024x1024",
        "quality": "low",
    },
    timeout=180,
)
data = response.json()
img_bytes = base64.b64decode(data["data"][0]["b64_json"])
print(f"image: {len(img_bytes)} bytes, watermark: {data['data'][0]['watermark']}")

Response

{
  "created": 1787941342,
  "model": "gpt-image-1.5",
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...",
      "revised_prompt": null,
      "seed": null,
      "watermark": "c2pa",
      "flagged": false
    }
  ],
  "usage": {
    "images": 1,
    "input_tokens": 16,
    "output_tokens": 272,
    "total_tokens": 288,
    "megapixels": null,
    "credits_used": 1790500
  }
}

Response fields

Field Type Description
created integer Unix timestamp from the upstream provider (0 if the provider doesn’t supply one — Gemini)
model string Model id echoed from the request (with any provider prefix preserved)
data array One entry per generated image, in upstream order
data[].b64_json string Base64-encoded image bytes (PNG by default, JPEG/WebP if requested on a gpt-image-* model)
data[].revised_prompt string or null Upstream-rewritten prompt. Gemini Flash Image returns mixed text and image parts, and the text part lands here when present, so the same model returns a string on one call and null on the next. null everywhere else
data[].seed integer or null Seed used by upstream when reported. No currently routable model reports one, so this is always null today
data[].watermark string One of c2pa, provenance, synthid, none — see Watermarking
data[].flagged boolean true if upstream answered a moderation block with 200 and no image. No currently routable provider does this, so it is always false today
usage.images integer Number of images successfully generated. Equals data.length; can be 0 when flagged is true
usage.input_tokens integer or null Input token count — gpt-image-* and Gemini Flash Image. null on Imagen
usage.output_tokens integer or null Output (image) token count — gpt-image-* and Gemini Flash Image. null on Imagen
usage.total_tokens integer or null Sum of input + output tokens — gpt-image-* and Gemini Flash Image. null on Imagen
usage.megapixels number or null Megapixels rendered, as a surrogate when token counts aren’t available. null on every currently routable model
usage.credits_used integer Micro-credits consumed by this request
No streaming

Image generation endpoints are not streamable on any provider. stream: true is not accepted.

Watermarking

Different providers/models embed different provenance metadata. The watermark enum in each data[] entry lets clients disclose this to end users if needed.

Value Standard Models
c2pa C2PA Content Credentials the gpt-image-* family
provenance AWS provenance metadata Reserved for Amazon Titan / Nova; not currently routable
synthid Google SynthID Gemini Flash Image, Imagen 4
none No watermark No currently routable model returns this
Educational disclosure

Quantized targets education customers. If your application surfaces images to students, consider rendering a disclosure when watermark != "none". The C2PA and SynthID standards are designed to be detectable downstream, but a textual disclosure removes ambiguity.

Per-model constraints

Each model has stricter limits than the serializer’s generic [1, 10] range for n and unrestricted size. The router does not enforce these — they’re handled by upstream:

Model Provider Max n Sizes quality values Pricing
gpt-image-2 openai 1 up to 3840px on the longer edge low, medium, high, auto $5/M input + $30/M output tokens
gpt-image-1.5 openai 1 up to 3840px on the longer edge low, medium, high, auto token-priced
gpt-image-1-mini openai 1 up to 3840px on the longer edge low, medium, high, auto token-priced
chatgpt-image-latest openai 1 up to 3840px on the longer edge low, medium, high, auto token-priced
gemini-3-pro-image gemini 1 chat-style (no size knob) — $2/M input + $120/M output tokens
gemini-3.1-flash-image gemini 1 chat-style (no size knob) — $0.50/M input + $60/M output tokens
gemini-3.1-flash-lite-image gemini 1 chat-style (no size knob) — $0.25/M input + $30/M output tokens
gemini-2.5-flash-image gemini 1 chat-style (no size knob) — $0.30/M input + $30/M output tokens
imagen-4.0-fast-generate-001 gemini 4 1K (aspect ratios: 1:1, 3:4, 4:3, 9:16, 16:9) — $0.020 per image

The gpt-image-* models accept background, output_format, output_compression and moderation, and require OpenAI org verification on our account. The Gemini Flash Image models route through :generateContent and return mixed text and image parts. Imagen routes through :predict.

gpt-image-1 is still resolvable but is deprecated in the catalog. DALL-E 2 and DALL-E 3 were retired by OpenAI in 2026 and are no longer served.

Imagen needs a paid Google project

imagen-4.0-fast-generate-001 resolves and routes correctly, but Gemini’s :predict endpoint is not available on a free-tier API key, so requests currently come back 404 from Google. The Flash Image models are unaffected.

Discovery via /v1/models

Filter GET /v1/models on output_modality.image == true:

models = response.json()["data"]  # GET /v1/models returns {"object": "list", "data": [...]}
image_models = [m for m in models if m["output_modality"]["image"]]
The filter over-matches

supported_features does not carry image_generation, so there is no semantic filter for this endpoint — a "image_generation" in supported_features check returns an empty list.

output_modality.image is the closest available signal, but it also matches models served only by OpenRouter, which cannot serve this endpoint. Cross-check against the table above until the catalog exposes which provider serves a model.

The catalog exposes per-model pricing in cost, whose shape varies by model (per_image for Imagen, prompt / completion for the token-priced models, and {} where the adapter computes the rate itself).

Providers

Provider Slug Models
OpenAI Direct openai gpt-image-2, gpt-image-1.5, gpt-image-1-mini, chatgpt-image-latest, gpt-image-1 (deprecated)
Google Gemini gemini gemini-3-pro-image, gemini-3.1-flash-image, gemini-3.1-flash-lite-image, gemini-2.5-flash-image, imagen-4.0-fast-generate-001

These are the only two providers holding the image_generation capability, so X-Quantized-Provider: bedrock is not usable here. Routing is resolved per-model from the catalog, so requesting gemini-3.1-flash-image reaches Gemini with no header needed.

No native passthrough endpoints

Unlike embeddings, image generation does not expose /v1/aws-bedrock/images/generations or /v1/gemini/images/generations native passthroughs. The unified /v1/images/generations is the only image endpoint — each provider adapts to that shape internally.

Errors

Status Condition
400 Modality mismatch — the model resolves but no provider serving it can produce image output (e.g. an LLM or embedding model id)
400 X-Quantized-Provider names a provider that cannot serve this endpoint
400 or 404 Unknown model id — forwarded to a provider, which decides. See below
401 Invalid or missing API key
402 Insufficient credits
422 Validation error — missing required field, unsupported enum value, out-of-range integer, or any field not in the documented schema (extra="forbid")
503 Upstream provider unavailable (timeout, rate limit, auth failure on the upstream key, OpenAI org-verification failure)
An unknown model id has no fixed status here

Model validation belongs to the provider (see Who validates the model). An id the catalog cannot resolve is forwarded as sent, and because this endpoint has two eligible providers with nothing to choose between them, the same request can reach either one:

reached Gemini  404  models/<id> is not found for API version v1beta ...
reached OpenAI  400  The model '<id>' does not exist.

Pin X-Quantized-Provider if you need a predictable failure. Requests naming a model the catalog resolves are unaffected: the model selects its provider.

Moderation blocks

Both providers answer a content-policy block with a normal error response (400 with the upstream message), which the router maps to its standard error hierarchy.

The response schema also carries data[].flagged and allows usage.images: 0 for providers that answer a block with 200 and no image. No currently routable provider does this, so flagged is always false today.

Out of scope on this endpoint

The following are not accepted by /v1/images/generations in this release:

  • Image edits (/v1/images/edits) — requires multipart upload and mask handling
  • Image variations (/v1/images/variations)
  • response_format: "url" — transport is forced to b64_json
  • Streaming — no provider streams image bytes
  • CDN rehosting — base64 only, no signed URLs

These may be added in a future release.