Image generation
POST https://api.mafdet.ai/v1/chat/completions
Image generation runs on the chat endpoint, not a separate images endpoint. You send a normal chat request; the generated image comes back alongside the message.
Models
| Model | Price (output) | Per image ≈ | Notes |
|---|---|---|---|
gemini-3-flash-lite-image | $36 / 1M tokens | $0.04 | Cheapest, returns JPEG |
gemini-3-image | $72 / 1M tokens | $0.08 | Returns PNG |
gemini-3-pro-image | $144 / 1M tokens | $0.16 | Highest quality, returns PNG |
Don't read the per-million figure as the price of a picture. An image model's output tokens are image tokens, and one image is a fixed ~1,120 of them — the right-hand column is the number that matters. See Billing.
All three also accept image input (text + image → image).
Request
Nothing special — a chat request with an image model:
curl https://api.mafdet.ai/v1/chat/completions \
-H "Authorization: Bearer $MAFDET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-image",
"messages": [{ "role": "user", "content": "A red bicycle on a white background" }]
}'
There are no size, quality or n parameters — the Gemini chat surface does
not take them, so Mafdet does not invent them.
Response
The image is not in message.content (which is usually null). It arrives in
choices[0].message.images[], each entry holding a data URI:
{
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"images": [
{ "image_url": { "url": "data:image/png;base64,iVBORw0KGgo..." } }
]
},
"finish_reason": "stop"
}
]
}
Streaming. With "stream": true the whole image arrives in a single chunk as
choices[0].delta.images[].image_url.url. A client that only reads
delta.content will silently drop the image — read delta.images too.
The MIME type varies by model and is carried by the data URI itself
(gemini-3-flash-lite-image → JPEG, the other two → PNG).
Billing
Billed as output tokens, like any chat call — there is no per-image price, only a fixed number of tokens per image, which is what makes the conversion possible.
One standard image is about 1,120 image tokens, regardless of your
max_tokens:
| Model | Working | Per image |
|---|---|---|
gemini-3-flash-lite-image | 1,120 × $36 ÷ 1M | $0.040 |
gemini-3-image | 1,120 × $72 ÷ 1M | $0.081 |
gemini-3-pro-image | 1,120 × $144 ÷ 1M | $0.161 |
Two smaller amounts ride along: your prompt is billed at the input rate
(usually a few dozen tokens, negligible), and gemini-3-pro-image tends to
return a written note with the picture, billed at the output rate — so a real
call on pro usually lands at $0.18–0.20.
Resolution is not selectable. There is no size parameter; the model
decides. The table above is therefore the price you will meet — there is no
larger size that multiplies the bill.
Is that expensive next to a text model?
Per million tokens, gemini-3-image at $72 is 6.7× gemini-3-flash at $10.80.
But a single call consumes wildly different amounts: a text reply runs from a few
hundred to a few thousand tokens (more on a model that thinks first), while an
image is a fixed 1,120. Per call, the two land in the same range.
Because the per-request cost cap applies, gemini-3-pro-image has its output cap
tuned so one image fits under the cap; you do not get a half-image billed as a
whole one — a truncated generation is not returned as a successful image.
In the Playground
Image models are marked with an output badge in the model picker. Generated images are previewed and downloadable, but the base64 is not persisted with the conversation: reopening a saved session shows a placeholder telling you the image was not saved. Playground calls draw on your Playground credit, not the API wallet.
Errors
Content-policy refusals, insufficient balance and provider failures surface as normal chat errors — see Errors.