Image generation
OpenAI-compatible image generation with per-image pricing.
Image models use the OpenAI Images API surface — the same one
client.images.generate speaks in every OpenAI SDK:
curl -s https://api.gopura.net/v1/images/generations \
-H "Authorization: Bearer $GOPURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "bytedance/seedream-4.0",
"prompt": "a majestic gopuram temple tower at golden hour",
"size": "1024x1024"
}' | jq -r '.data[0].b64_json' | base64 -d > out.png
Or with the SDK:
const image = await client.images.generate({
model: 'bytedance/seedream-4.0',
prompt: 'a majestic gopuram temple tower at golden hour',
size: '1024x1024',
});
// image.data[0].b64_json
Request
| Field | Meaning |
|---|---|
model | an image model id from the catalog (output_modalities: ["image"]) |
prompt | up to 10,000 characters |
n | 1–4 images |
size | WIDTHxHEIGHT, e.g. 1024x1024 (model-dependent) |
response_format | b64_json (default) or url — hosted result links (below) |
Response
{
"created": 1787443200,
"data": [{ "b64_json": "…" }],
"usage": { "images": 1, "cost": 0.0315 }
}
As everywhere on Gopura, the actual cost is in-band — image models are
priced per generated image (see the pricing.image field on /v1/models),
so the charge is exact and known even before generation starts.
Hosted URLs instead of base64
response_format: "url" returns hosted links instead of inline base64 —
useful when a multi-image response would otherwise be megabytes of JSON
(serverless callers, <img> tags, queues):
{
"data": [{
"url": "https://api.gopura.net/v1/artifacts/1f0c…9ab2",
"mime_type": "image/png"
}],
"usage": { "images": 1, "cost": 0.0315 }
}
The links are unauthenticated capability URLs (the unguessable id is the
secret) so they work directly in image tags — and they expire after ~48
hours. Download anything you want to keep. Pricing is identical to
b64_json.
Codec, mime_type, and what response_format means
response_format selects the transport (base64 vs hosted URL), not the
image codec — the same semantics as OpenAI's Images API. The codec is
model-native: BFL models emit JPEG, others PNG or WebP. Every data[]
entry therefore carries mime_type with the sniffed actual format —
use it for file extensions and Content-Type headers instead of assuming
PNG.
Latency
Generation is synchronous. The gateway enforces a 120-second upstream
ceiling — a hung provider returns a clean 504 timeout and you are not
billed. Observed latency from production traffic (small sample, measured
2026-08-24 — treat as indicative):
| Model | p50 | p95 |
|---|---|---|
google/gemini-3.1-flash-lite-image | ~6s | ~8s |
google/gemini-2.5-flash-image | ~6s | — |
bytedance/seedream-4.0 | ~9s | — |
bfl/flux-pro-1.1 | ~4s | — |
bfl/flux-kontext-pro | ~12s | ~13s |
google/gemini-3.1-flash-image | ~13s | ~14s |
openai/gpt-image-1-mini | ~38s | — |
bytedance/seedream-5.0-pro | up to ~90s observed |
Size timeouts to the model you use; 120s covers everything we serve.
Remixing with reference images
Models whose catalog entry lists image in input_modalities accept
reference images through /v1/images/edits — the same multipart surface as
OpenAI's client.images.edit:
curl -s https://api.gopura.net/v1/images/edits \
-H "Authorization: Bearer $GOPURA_API_KEY" \
-F "model=bfl/flux-kontext-pro" \
-F "prompt=the same scene during a monsoon thunderstorm" \
-F "image=@reference.png" \
| jq -r '.data[0].b64_json' | base64 -d > remixed.png
const remixed = await client.images.edit({
model: 'bfl/flux-kontext-pro',
prompt: 'the same scene during a monsoon thunderstorm',
image: fs.createReadStream('reference.png'),
});
Pass several references by repeating the image field (up to 8 MB per
file). Pricing is identical to generation: per output image, exact, in-band.
Sending a reference to a model that doesn't accept one returns a 400 that
says so.
Current image models
| Model | Per image | References | Best at |
|---|---|---|---|
google/gemini-3.1-flash-image | $0.07035 | yes | Nano Banana 2 — instruction-following edits |
google/gemini-3.1-flash-lite-image | $0.0357 | yes | Nano Banana Lite — fast, cheap remixing |
google/gemini-3-pro-image | $0.14112 | yes | Nano Banana Pro — highest fidelity |
google/gemini-2.5-flash-image | $0.04095 | yes | the original Nano Banana |
bytedance/seedream-5.0-pro | $0.03675 | yes | current ByteDance flagship |
bytedance/seedream-4.5 | $0.042 | yes | strong all-rounder |
bytedance/seedream-4.0 | $0.0315 | yes | the price floor |
spacexai/grok-imagine-image-2.0 | $0.063 | yes | xAI's latest |
recraft/recraft-v4.1 | $0.03675 | no | design, brand and vector-style output |
bfl/flux-kontext-pro | $0.042 | yes | faithful remixing — preserves source structure |
bfl/flux-pro-1.1 | $0.042 | no | classic high-quality text-to-image |
The openai/gpt-image-1.5 family is also available — it bills by token
rather than per image, so its exact cost appears in usage.cost per request.
Reference support is probe-verified per model, not assumed. Prices include
margin and match the in-band usage.cost exactly. The authoritative list is
always the live catalog:
Which endpoint for which model
Chat models belong to /v1/chat/completions, image models to
/v1/images/generations — using the wrong endpoint returns a 400 that
points you to the right one. Filter the catalog programmatically:
curl -s https://api.gopura.net/v1/models \
| jq '.data[] | select(.architecture.output_modalities == ["image"]) | {id, pricing}'