Image generation
MirAPI offers two OpenAI-compatible endpoints for working with images:
POST /v1/images/generations: text-to-image.POST /v1/images/edits: image editing (send an image plus an edit instruction).
Both endpoints also have a trailing-slash variant (/v1/images/generations/, /v1/images/edits/), and both are billed per generated image: one charge per image in the response, never per token. They use standard Authorization: Bearer authentication. Google’s Gemini image models (the Nano Banana family) are multimodal chat models and use the Gemini-native POST /v1beta/models/{model}:generateContent instead (see the Gemini section below). Anthropic has no image-generation endpoint.
Generate an image
Section titled “Generate an image”/v1/images/generations takes a chat-style input.messages payload with a parameters object:
curl https://api.mirapi.ai/v1/images/generations \ -H "Authorization: Bearer $MIRAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-chat", "input": { "messages": [ { "role": "user", "content": [ {"text": "A neon-lit street in the rain, cinematic"} ] } ] }, "parameters": { "size": "1024*1024", "negative_prompt": "blurry, low quality", "prompt_extend": true, "watermark": false } }'import osimport requests
resp = requests.post( "https://api.mirapi.ai/v1/images/generations", headers={"Authorization": f"Bearer {os.environ['MIRAPI_API_KEY']}"}, json={ "model": "deepseek-chat", "input": { "messages": [ { "role": "user", "content": [{"text": "A neon-lit street in the rain, cinematic"}], } ] }, "parameters": {"size": "1024*1024", "prompt_extend": True, "watermark": False}, },)print(resp.json()["data"][0])Edit an image
Section titled “Edit an image”/v1/images/edits takes the source image and the instruction in the same message-style shape:
curl https://api.mirapi.ai/v1/images/edits \ -H "Authorization: Bearer $MIRAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-chat", "input": { "messages": [ { "role": "user", "content": [ {"image": "https://example.com/photo.png"}, {"text": "Turn the sky into a starry night"} ] } ] }, "parameters": {"n": 2, "prompt_extend": true, "watermark": false} }'The image field accepts a public HTTP(S) URL or a base64 data URI (data:image/png;base64,…).
Parameters
Section titled “Parameters”| Parameter | Purpose |
|---|---|
model |
Model name exactly as shown in the catalog |
input.messages[].content[].text |
The generation or edit instruction |
input.messages[].content[].image |
Source image for edits (URL or base64 data URI) |
parameters.size |
Output dimensions as a string, e.g. 1024*1024 |
parameters.negative_prompt |
Things to avoid in the output |
parameters.prompt_extend |
Let the model expand the prompt (true / false) |
parameters.watermark |
Request a visible watermark (true / false) |
parameters.n |
Number of images to return (where supported) |
Not every model accepts every parameter, and many models only support n: 1. Check the model card in the catalog for supported values.
Retrieving the image
Section titled “Retrieving the image”The response contains an array of images:
{ "created": 1780000000, "data": [ { "url": "https://…", "b64_json": null, "revised_prompt": "…" } ]}url: a temporary URL to download the image.b64_json: the image as a base64 string.revised_prompt: the prompt actually used when the model rewrites yours.
To save the image to disk, prefer b64_json (no second request) or download url immediately, because it is temporary.
Gemini image models (Nano Banana)
Section titled “Gemini image models (Nano Banana)”Google’s Gemini image models (gemini-2.5-flash-image, gemini-3-pro-image-preview, gemini-3.1-flash-image-preview, and the other Nano Banana names in the catalog) are multimodal chat models. They do not use the image endpoints above: call them through the Gemini-native POST /v1beta/models/{model}:generateContent, request image output with generationConfig.responseModalities: ["TEXT", "IMAGE"], and read it back as base64 from candidates[0].content.parts[].inlineData. Authenticate with the x-goog-api-key header (or the ?key= query parameter).
curl https://api.mirapi.ai/v1beta/models/gemini-3.1-flash-image-preview:generateContent \ -H "x-goog-api-key: $MIRAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "contents": [{"role": "user", "parts": [{"text": "A neon-lit street in the rain, cinematic"}]}], "generationConfig": { "responseModalities": ["TEXT", "IMAGE"], "imageConfig": {"aspectRatio": "16:9"} } }'import base64import osimport requests
resp = requests.post( "https://api.mirapi.ai/v1beta/models/gemini-3.1-flash-image-preview:generateContent", headers={"x-goog-api-key": os.environ["MIRAPI_API_KEY"]}, json={ "contents": [{"role": "user", "parts": [{"text": "A neon-lit street in the rain, cinematic"}]}], "generationConfig": { "responseModalities": ["TEXT", "IMAGE"], "imageConfig": {"aspectRatio": "16:9"}, }, },)for part in resp.json()["candidates"][0]["content"]["parts"]: if "inlineData" in part: with open("nano_banana.png", "wb") as f: f.write(base64.b64decode(part["inlineData"]["data"])) elif "text" in part: print(part["text"])| Parameter | Purpose |
|---|---|
contents[].parts[].text |
The generation or edit instruction |
contents[].parts[].inlineData |
A source or reference image for edits: {"mimeType": "image/png", "data": "<base64>"}, the same shape as in Vision inputs |
generationConfig.responseModalities |
Must include "IMAGE"; use ["TEXT", "IMAGE"] |
generationConfig.imageConfig.aspectRatio |
Aspect ratio, e.g. 1:1, 16:9, 9:16, 4:3, 3:4 |
generationConfig.imageConfig.imageSize |
Output resolution 1K / 2K / 4K; optional, Gemini 3 image models only |
The response uses the standard Gemini shape, with the image as one of the parts:
{ "candidates": [ { "content": { "role": "model", "parts": [ {"text": "…"}, {"inlineData": {"mimeType": "image/png", "data": "<base64>"}} ] } } ], "usageMetadata": {"promptTokenCount": …, "candidatesTokenCount": …, "totalTokenCount": …}}Base64-decode inlineData.data to save the file. The same models are also available through POST /v1/chat/completions (OpenAI format), with the image options under extra_body.google.image_config (aspect_ratio, image_size).
Send images to chat models
Section titled “Send images to chat models”Image generation is separate from vision input. To have a model read an image (caption it, answer questions, extract text), send it through a chat endpoint, where it is billed as tokens, not per image.
With the OpenAI-compatible protocol, add an image_url part to the content array:
import osfrom openai import OpenAI
client = OpenAI(base_url="https://api.mirapi.ai/v1", api_key=os.environ["MIRAPI_API_KEY"])
response = client.chat.completions.create( model="deepseek-chat", messages=[{ "role": "user", "content": [ {"type": "text", "text": "What is in this photo?"}, {"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}, ], }],)print(response.choices[0].message.content)The url can be an HTTP(S) URL or a base64 data URI. The same capability is available on the Anthropic (/v1/messages) and Gemini (/v1beta/models/{model}:generateContent) chat protocols. See Vision inputs for the full formats.
Errors and billing
Section titled “Errors and billing”Billing. Generation and editing are charged per image and deducted from your prepaid balance. When the balance is exhausted, requests return 403; topping up restores the same key immediately. Reconcile spend in the Platform billing log or via GET /api/usage/token (account-level summary) and GET /api/log/token (per-request detail). Gemini image models called through generateContent are billed per token like any other Gemini call: the generated image counts as output tokens (see usageMetadata in the response), at the rate on the model card.
Errors. The gateway returns standard status codes: 401 (fix your key), 403 (balance, model whitelist, quota, or IP allowlist), 413 (request too large), 429 (rate limited: back off exponentially with jitter; there is no Retry-After header), and 500 (upstream failure; idempotent requests are safe to retry). Error responses use the OpenAI envelope, and each message ends with a request ID. Include it in any support ticket.
Troubleshooting
Section titled “Troubleshooting”- Wrong model. Image endpoints reject models without image-generation capability. Filter the catalog by output type and use the model’s exact
id. - Gemini image models (Nano Banana). Call
POST /v1beta/models/{model}:generateContentwithresponseModalities: ["TEXT", "IMAGE"], not/v1/images/generations; the image is ininlineData.data. 403on a valid key. Check your balance first, then the model whitelist, quota, and IP allowlist on the key.urlno longer works. Download it immediately after the request, or useb64_json.413with base64. Large images exceed the size limit. Downscale them before encoding.nignored or rejected. Some models return a single image regardless; check the model card.
Related links
Section titled “Related links”- Video generation: video output
- Vision inputs: images into chat models on all three protocols
- Image generation tutorial: a complete script
- Models & pricing: find image-capable models
- Billing & top-ups: per-image and per-token pricing
- API reference: the full generateContent request and response schema