Skip to content
Numes

Multimodal

Image generation

Create images from a text prompt and optional reference images with POST /images, returned as base64 in one response or as a stream.

On this page

POST /images generates one or more images from a prompt, optionally guided by reference images. Images always come back as base64 data with their media type; there are no hosted URLs. Image generation is available on models whose endpoints offer it: find them with GET /models?output_modalities=image.

POST/api/v1/imagesReference →

Image prompts preserve JSON-escaped control characters without stripping. Prompt and request size limits still apply.

Generate an image

curl -X POST "https://api.numes.ai/api/v1/images" \  -H "Authorization: Bearer $NUMES_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "author/image-model",    "prompt": "A lighthouse on a basalt cliff at dusk, watercolor, soft light",    "size": "1024x1024",    "output_format": "png"  }'
Response
{  "created": 1790000000,  "data": [    {      "b64_json": "iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zU...",      "media_type": "image/png"    }  ],  "usage": {    "input_images": 0,    "output_images": 1,    "input_audio_seconds": 0,    "output_audio_seconds": 0,    "input_characters": 0,    "prompt_tokens": 0,    "completion_tokens": 0,    "total_tokens": 0,    "cost": 0.04  }}

The response carries an X-Generation-Id header; use it with GET /generation to look up the request later.

Request fields

Request body

modelstringRequired

Canonical ID of an image-generation model, such as author/image-model.

promptstringRequired

What to draw. Must not be blank; at most 1 MiB.

nintegerDefault 1

Number of images, from 1 to 10.

sizestring

auto, or WIDTHxHEIGHT in pixels with each side from 64 to 8192, such as 1024x1536. Generated images may not exceed 16,777,216 pixels (4096 × 4096).

resolutionstring

Resolution label, at most 16 bytes. Accepted values depend on the model.

aspect_ratiostring

Aspect ratio label such as 16:9, at most 16 bytes. Accepted values depend on the model.

qualitystring

auto, low, medium or high.

output_formatstring

png, jpeg or webp.

backgroundstring

auto, opaque or transparent.

output_compressioninteger

Compression level from 0 to 100, typically for jpeg and webp.

seedinteger

64-bit seed for models that support reproducible sampling.

streambooleanDefault false

Stream Server-Sent Events instead of one JSON response.

input_referencesarray

Up to 16 reference images. See Reference images.

providerobject

Routing preferences, as for chat. See Provider routing.

Unknown fields, including response_format and user, are rejected with 400. The request body is limited to 10 MiB.

Controls and routing

Image models differ in the controls they support. Every control you set, including n and size, is forwarded, and an endpoint that can't apply one rejects the request rather than ignoring it. To route only to endpoints that declare every control you set, add provider.require_parameters: true:

curl -X POST "https://api.numes.ai/api/v1/images" \  -H "Authorization: Bearer $NUMES_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "author/image-model",    "prompt": "A flat vector icon of a paper airplane",    "size": "1024x1024",    "background": "transparent",    "output_format": "png",    "provider": {      "require_parameters": true    }  }'

If no endpoint declares them, the request fails with 503 provider_unavailable. Each endpoint lists its controls in supported_parameters of GET /models/{author}/{slug}/endpoints.

Reference images

Each item in input_references is a URL string or an object {"image_url": "..."}. Unlike chat, the object holds the URL directly, not in a nested url field:

Request body with references
{  "model": "author/image-model",  "prompt": "Place the product from the first image on the table in the second image",  "input_references": [    "https://example.com/images/product.png",    { "image_url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..." }  ]}

References follow the same rules as image inputs: HTTPS or base64 data: URLs, PNG, JPEG, GIF or WebP, at most 8 MiB each and 24 MiB in total. A request with references needs an endpoint that accepts image input, and each reference counts as one input_images unit.

Stream progress events

With "stream": true, the response is an SSE stream. Each frame is one data: line holding a JSON event, and the stream ends with data: [DONE]:

Stream
data: {"type":"image_generation.partial","index":0,"b64_json":"iVBORw0KGgoAAAANSUhEUgAA...","media_type":"image/png"}​data: {"type":"image_generation.completed","index":0,"b64_json":"iVBORw0KGgoAAAANSUhEUgAB...","media_type":"image/png"}​data: {"type":"image_generation.usage","usage":{"input_images":0,"output_images":1,"input_audio_seconds":0,"output_audio_seconds":0,"input_characters":0,"prompt_tokens":0,"completion_tokens":0,"total_tokens":0,"cost":0.04}}​data: [DONE]
Event typeFieldsMeaning
image_generation.partialindex, b64_json, media_typeA preview of image index, if the model produces previews
image_generation.completedindex, b64_json, media_typeA final image
image_generation.usageusageFinal usage, sent once after all images
image_generation.errorerrorThe request failed after the stream started

index identifies which of the n images an event belongs to, from 0. A failure after the stream starts keeps HTTP status 200 and sends one error event, then [DONE], with no usage event:

In-band error
data: {"type":"image_generation.error","error":{"code":"provider_unavailable","message":"provider became unavailable","status":503}}​data: [DONE]

error.code is an error type such as provider_unavailable, rate_limit_exceeded, timeout or cancelled, and error.status the matching HTTP status. Look up what was delivered and charged with GET /generation. Failures before the first event return an ordinary JSON error.

Frames that carry full images can be several megabytes long; read them with a line reader that has no small line-length limit.

Save the images

Decode b64_json and write the bytes with the extension that matches media_type:

import base64import os​import requests​EXTENSIONS = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp"}​response = requests.post(    "https://api.numes.ai/api/v1/images",    headers={"Authorization": f"Bearer {os.environ['NUMES_API_KEY']}"},    json={"model": "author/image-model", "prompt": "A lighthouse at dusk, watercolor", "n": 2},    timeout=630,)response.raise_for_status()result = response.json()​for index, image in enumerate(result["data"]):    path = f"lighthouse-{index}.{EXTENSIONS[image['media_type']]}"    with open(path, "wb") as file:        file.write(base64.b64decode(image["b64_json"]))​print("cost", result["usage"]["cost"], "generation", response.headers["X-Generation-Id"])

When streaming, save each image_generation.completed event as it arrives:

stream_images.py
import base64import jsonimport os​import requests​EXTENSIONS = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp"}​with requests.post(    "https://api.numes.ai/api/v1/images",    headers={"Authorization": f"Bearer {os.environ['NUMES_API_KEY']}"},    json={"model": "author/image-model", "prompt": "A red fox in fresh snow", "stream": True},    stream=True,    timeout=630,) as response:    response.raise_for_status()    for line in response.iter_lines(decode_unicode=True):        if not line or not line.startswith("data: "):            continue        payload = line[len("data: "):]        if payload == "[DONE]":            break        event = json.loads(payload)        if event["type"] == "image_generation.completed":            with open(f"fox-{event['index']}.{EXTENSIONS[event['media_type']]}", "wb") as file:                file.write(base64.b64decode(event["b64_json"]))        elif event["type"] == "image_generation.usage":            print("cost", event["usage"]["cost"])        elif event["type"] == "image_generation.error":            raise RuntimeError(f"{event['error']['code']}: {event['error']['message']}")

Billing

UnitCharged for
output_imagesEach final image delivered to you, at the endpoint's output image rate
input_imagesEach reference image, at the endpoint's input image rate
RequestThe endpoint's per-request price, if it has one

Before the request runs, funds for all n images are held, so your balance must cover n images even if fewer are delivered. GET /generation is the authoritative record of what was charged. See Usage accounting.

Errors

Statuserror_typeCause
400invalid_requestBlank or oversized prompt, n outside 1–10, malformed size, unknown enum value, more than 16 references, invalid reference image, unknown field
402insufficient_creditsBalance or key limit doesn't cover n images
408timeoutThe request didn't complete in time
413payload_too_largeBody larger than 10 MiB
429rate_limitedKey or account rate limit; wait for Retry-After
502provider_unavailableThe provider returned an invalid image
503provider_unavailableNo eligible endpoint for the model, or none declares a required control
503provider_overloadedEvery eligible endpoint is at capacity

See Errors for the envelope and retry guidance.

Next steps