Image Models
Generate, edit, and vary images from text prompts with the OpenAI-compatible Images API
The Images API generates and edits images from text prompts through three OpenAI-compatible endpoints: /v1/images/generations from a prompt, /v1/images/edits from a prompt plus an input image, and /v1/images/variations from an input image alone. Images come back base64-encoded in the JSON response, ready to save or serve.
The served model is Tongyi-MAI/Z-Image-Turbo, a 6B diffusion model built for fast generation and inpainting. It is in preview: details may change before general availability.
Every example reads your key from NEBUL_API_KEY; export it first. The Quick Start covers key setup.
Generate images
POST https://api.inference.nebul.io/v1/images/generations
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | String | Yes | Description of the image to generate. |
model | String | Yes | The model ID, Tongyi-MAI/Z-Image-Turbo. |
n | Integer | No | Number of images to generate. Defaults to 1. |
response_format | String | No | "b64_json" (default) for inline images. |
output_format | String | No | "png" (default) or "jpeg". |
Example
import base64
import os
import requests
response = requests.post(
"https://api.inference.nebul.io/v1/images/generations",
headers={
"Authorization": f"Bearer {os.environ['NEBUL_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": "Tongyi-MAI/Z-Image-Turbo",
"prompt": "A photo of a cat sitting on a windowsill at sunset",
"n": 1,
},
)
image_bytes = base64.b64decode(response.json()["data"][0]["b64_json"])
with open("generated.png", "wb") as f:
f.write(image_bytes)A request for one 1024x1024 image finishes in a few seconds and writes a valid PNG to generated.png. Images default to 1024x1024; output_format: "jpeg" returns JPEG instead.
Edit images
POST https://api.inference.nebul.io/v1/images/edits
Send an input image plus a prompt describing the change. The request is multipart:
| Parameter | Type | Required | Description |
|---|---|---|---|
model | String | Yes | The model ID, Tongyi-MAI/Z-Image-Turbo. |
prompt | String | Yes | Description of the edit to apply. |
image | File | Yes | The image to edit. |
n | Integer | No | Number of images to generate. Defaults to 1. |
response_format | String | No | "b64_json" (default) for inline images. |
import base64
import os
import requests
with open("original.png", "rb") as f:
response = requests.post(
"https://api.inference.nebul.io/v1/images/edits",
headers={"Authorization": f"Bearer {os.environ['NEBUL_API_KEY']}"},
files={"image": ("original.png", f, "image/png")},
data={
"model": "Tongyi-MAI/Z-Image-Turbo",
"prompt": "Add a red hat to the cat",
},
)
image_bytes = base64.b64decode(response.json()["data"][0]["b64_json"])
with open("edited.png", "wb") as f:
f.write(image_bytes)The same request with curl:
curl https://api.inference.nebul.io/v1/images/edits \
-H "Authorization: Bearer $NEBUL_API_KEY" \
-F "model=Tongyi-MAI/Z-Image-Turbo" \
-F "prompt=Add a red hat to the cat" \
-F "image=@original.png" \
-o response.json
jq -r '.data[0].b64_json' response.json | base64 --decode > edited.pngCreate variations
POST https://api.inference.nebul.io/v1/images/variations
Send an image with no prompt and get a new image in the same style:
| Parameter | Type | Required | Description |
|---|---|---|---|
model | String | Yes | The model ID, Tongyi-MAI/Z-Image-Turbo. |
image | File | Yes | The image to vary. |
n | Integer | No | Number of images to generate. Defaults to 1. |
response_format | String | No | "b64_json" (default) for inline images. |
import base64
import os
import requests
with open("original.png", "rb") as f:
response = requests.post(
"https://api.inference.nebul.io/v1/images/variations",
headers={"Authorization": f"Bearer {os.environ['NEBUL_API_KEY']}"},
files={"image": ("original.png", f, "image/png")},
data={"model": "Tongyi-MAI/Z-Image-Turbo"},
)
image_bytes = base64.b64decode(response.json()["data"][0]["b64_json"])
with open("variation.png", "wb") as f:
f.write(image_bytes)Quick reference
Match the problem to the fix:
- Image doesn't match the prompt: make the prompt more specific. Name the subject, setting, lighting, composition, and style.
- Need variations of one prompt: set
nhigher, up to what your budget allows; each image bills separately. - Need a smaller file: request
output_format: "jpeg". - Storing or piping the image: the response is already inline base64 (
b64_json); no URL round trip to make.
Response
All three endpoints return the same shape:
{
"created": 1792150343,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAA...",
"url": null
}
],
"size": "1024x1024",
"quality": "auto",
"background": "auto",
"output_format": "png",
"usage": {
"total_tokens": 1036,
"input_tokens": 12,
"output_tokens": 1024,
"input_tokens_details": {
"text_tokens": 12,
"image_tokens": 0
},
"output_tokens_details": {
"text_tokens": 0,
"image_tokens": 1024
}
}
}| Field | Type | Description |
|---|---|---|
created | Integer | Unix timestamp of the response. |
data[].b64_json | String | The image, base64-encoded. |
data[].url | String or null | Always null on this API; images are inline only. |
size | String | Image dimensions, 1024x1024. |
output_format | String | png or jpeg. |
usage.input_tokens | Integer | Prompt text tokens plus input image tokens (edits and variations). |
usage.output_tokens | Integer | Generated image tokens: 1,024 per 1024x1024 image, scaling with size. |
The response body lands in response; the vector is data[0].embedding in the JSON:
Billing follows the usage counts, and the counts scale with image size: a 1024x1024 image is 1,024 tokens, a 512x512 image is 256. A generated image bills 1,024 output tokens at the model's output price (about €0.00026 at €0.25 per 1M); an edit also bills input tokens for the image you send, at the same scale. Edits and variations return an image the same size as the one you send; generation always produces 1024x1024.
Write prompts with specifics
Name the subject, the setting, the lighting, and the style. "A photorealistic portrait of a cat sitting on a windowsill at sunset, soft golden lighting, shallow depth of field" beats "a cat": the model has something concrete to honor.
For reading images instead of creating them, send them to a vision model as content parts: see Examples. Current model specs live in the Model Catalog.