Skip to content

API reference

Images: generation

POST /v1/images/generations in the shape of OpenAI's Images API: what it accepts, what comes back, what it costs and what is refused.

Last updated: 2026-10-11

One request, one answer: a picture takes seconds, so there is no job to follow as with video. The shape is OpenAI's Images API. Code written for it works once it uses the base URL and the key of AI Tokens, a model of this page instead of OpenAI's, and only the fields below: What works where and OpenAI SDK migration list the differences.

In one request

bash
curl -s https://api.aitokens.ch/v1/images/generations \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "z-image-turbo", "prompt": "A cozy fantasy tavern at night, warm candle light, wooden beams, digital painting"}' \
  | python3 -c 'import sys, json, base64; open("tavern.png", "wb").write(base64.b64decode(json.load(sys.stdin)["data"][0]["b64_json"]))'

Models

model Makes size n
z-image-turbo (default) text → picture, PNG 1024x1024 (default), 1024x1536 (portrait), 1536x1024 (landscape) 1 to 4

A square picture takes about 9 seconds, a tall or wide one about 13.

The request

POST /v1/images/generations, JSON:

Field
prompt required What to draw, up to 4000 characters.
model optional z-image-turbo.
size optional One of the sizes above, as width x height.
n optional 1 to 4 pictures, made one after the other.
response_format optional b64_json (default): the PNG inside the answer. url: a link to it, valid 24 hours.
seed optional A whole number from 0 to 2147483647. The same prompt and seed give the same picture again.

Every other field is refused with a 400 that names it, OpenAI's quality, style, background and output_format included, and a value the model cannot take is refused, not rounded: ask for "size": "512x512" and you get a 400 that lists the sizes.

The answer

json
{
  "created": 1791297500,
  "data": [
    {"b64_json": "iVBORw0KGgoAAAANSUhEUgAA…"}
  ]
}

With "response_format": "url" each picture is a link instead:

json
{"created": 1791297500, "data": [{"url": "https://api.aitokens.ch/v1/images/file/…?expires=…&signature=…"}]}

The link works without the key, so it can go straight into a web page or a game, for 24 hours. Then the file is deleted: download what you want to keep.

Prompts that work

  • Say the subject, the setting, the style, the light and the framing: A low-poly red fox in an autumn forest, side view, soft morning light.
  • Italian works. For words written in the picture (a sign, a title, a label), write the prompt in English and put the exact words in quotes: A wooden sign reading "Benvenuti" at the entrance of a medieval village.
  • For variants of the same idea, ask n pictures, or keep the prompt and change the seed.

What is refused

Before the picture is made, one of our own models reads the prompt; after, the picture itself is checked before it reaches you. These are refused:

  • sexual content or nudity;
  • minors in any unsafe, violent or sexual situation;
  • real, identifiable people (public figures, people named in the prompt), and any likeness of them;
  • blood, gore, torture, self-harm; realistic violence against people or animals;
  • hate, harassment, extremist symbols;
  • realistic illegal activity;
  • well-known copyrighted characters and brand logos.

Fantasy and game scenes with stylised action are fine: knights fighting, explosions without victims, monsters, space battles, landscapes, objects, animals, characters you invent.

  • A refused prompt gets a 400 with code prompt_refused and the reason.
  • A picture that fails the check after it is made is not delivered and not charged. If you asked for several, you get those that passed; if none did, a 400 with code output_refused.
  • If a check cannot answer, nothing goes through: a 503 moderation_unavailable. Try again a minute later.

Which checks run is decided zone by zone by whoever runs the machines. Today both run everywhere for pictures.

Every picture is marked as made by AI inside the PNG, for article 50 of the EU AI Act: the IPTC field DigitalSourceType says trainedAlgorithmicMedia, the mark that image sites and editors read, and a text comment says the same. Editors and social networks can strip metadata, so where you publish a picture, say it in words too. What is in the file, how to read it and what removes it: AI-generated media.

What we keep

  • The prompt: not kept.
  • The pictures: not kept with b64_json. With url, for 24 hours in AI Tokens's storage, then deleted.
  • The usage: model, number of pictures, cost and time, as for every request.

Price

Per picture delivered, at the price in Pricing: in CHF, or in credits where AI Tokens works with credits. A refused picture, or a failed request, costs nothing.

Errors

Status error.code When
400 unknown_parameter a field this API does not have; error.param names it
400 missing_required_parameter no prompt, or an empty one
400 string_above_max_length a prompt longer than 4000 characters
400 model_not_found a model that does not make pictures here
400 invalid_value a size, n, response_format or seed the model cannot take
400 prompt_refused the prompt goes against the rules
400 output_refused every picture failed the check after it was made
401 missing or wrong key
402 insufficient_credits no credits left
429 more than 30 requests in a minute
502 engine_error the machine could not make the picture
503 no_engine_available no machine is making this model right now
503 moderation_unavailable a check could not answer

Errors have OpenAI's shape:

json
{"error": {"message": "'z-image-turbo' makes pictures of 1024x1024, 1024x1536, 1536x1024.", "type": "invalid_request_error", "param": "size", "code": "invalid_value"}}

Examples

Python, with OpenAI's SDK

python
import base64
import os

from openai import OpenAI

client = OpenAI(base_url="https://api.aitokens.ch/v1", api_key=os.environ["API_KEY"])

result = client.images.generate(
    model="z-image-turbo",
    prompt="A low-poly red fox in an autumn forest, side view, soft morning light",
    size="1536x1024",
)

with open("fox.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))

The SDK has no seed argument: pass it with extra_body.

python
for seed in (1, 2, 3):
    result = client.images.generate(
        model="z-image-turbo",
        prompt="A treasure chest on a beach at sunset, stylised game art",
        extra_body={"seed": seed},
    )
    with open(f"chest-{seed}.png", "wb") as f:
        f.write(base64.b64decode(result.data[0].b64_json))

JavaScript (Node 18+)

js
import { writeFile } from "node:fs/promises";

const res = await fetch("https://api.aitokens.ch/v1/images/generations", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    prompt: "Four flat game icons: a sword, a shield, a potion, a key, white background",
    n: 2,
  }),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);

for (const [i, picture] of body.data.entries()) {
  await writeFile(`icons-${i + 1}.png`, Buffer.from(picture.b64_json, "base64"));
}

Save it as icons.mjs and run it with node icons.mjs.

Search the docs

Type to search…