Skip to content
Numes

Multimodal

Image inputs

Send photos, screenshots and diagrams to vision-capable models with the image_url content part, by HTTPS URL or inline base64.

On this page

Add an image_url content part to a user message, pointing at an HTTPS URL or holding the image as a base64 data: URL. The examples use openai/gpt-6-luna; replace it with a model whose endpoints accept image input (see Route to vision-capable endpoints).

Send an image by URL

curl -X POST "https://api.numes.ai/api/v1/chat/completions" \  -H "Authorization: Bearer $NUMES_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "openai/gpt-6-luna",    "messages": [      {        "role": "user",        "content": [          {            "type": "text",            "text": "Transcribe the total and the date from this receipt."          },          {            "type": "image_url",            "image_url": {              "url": "https://example.com/images/receipt.jpg"            }          }        ]      }    ]  }'

The URL must be publicly reachable over HTTPS when the request runs. Signed URLs work while they're valid. Images on localhost or a private network can't be fetched; send them inline instead.

Send a local image as base64

Send a data: URL with the media type image/png, image/jpeg, image/gif or image/webp, matching the actual file, and standard (not URL-safe) base64:

import base64import osfrom pathlib import Path​from openai import OpenAI​MEDIA_TYPES = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp"}​def image_data_url(path: str) -> str:    file = Path(path)    encoded = base64.b64encode(file.read_bytes()).decode("ascii")    return f"data:{MEDIA_TYPES[file.suffix.lower()]};base64,{encoded}"​client = OpenAI(base_url="https://api.numes.ai/api/v1", api_key=os.environ["NUMES_API_KEY"])​completion = client.chat.completions.create(    model="openai/gpt-6-luna",    messages=[        {            "role": "user",            "content": [                {"type": "text", "text": "Describe this chart in two sentences."},                {"type": "image_url", "image_url": {"url": image_data_url("chart.png")}},            ],        }    ],)print(completion.choices[0].message.content)

Inline images count toward the 10 MiB chat body limit, and base64 adds about a third to their size. Keep inline images under about 7.5 MiB in total, or send HTTPS URLs.

The image_url part

Content part

type"image_url"Required

Identifies an image part.

image_urlobjectRequired

The image to attach.

Show child attributes
urlstringRequired

An https:// URL or a data:image/...;base64, URL.

detail"auto" | "low" | "high"

Accepted for OpenAI compatibility. It isn't forwarded to providers, so it doesn't change resolution or cost.

Add one part per image; images reach the model in the order you list them. The model doesn't see which sentence an image sat next to, so refer to images by position ("the first screenshot"). Images in earlier turns that you resend are sent, and billed, again.

Route to vision-capable endpoints

Routing considers only endpoints whose input_modalities include image. Check a model's endpoints before you send images:

curl "https://api.numes.ai/api/v1/models/author/vision-model/endpoints" \  -H "Authorization: Bearer $NUMES_API_KEY"

You can combine image input with the usual routing preferences.

Limits

LimitValue
FormatsPNG, JPEG, GIF, WebP
One image8 MiB decoded
All media in one request24 MiB decoded
Chat request body10 MiB, including inline data: URLs

See Sending media for the rules every media URL follows.

Billing

Endpoints price images either per image, reported as input_images in usage, or as prompt tokens. Text tokens and any per-request price apply as usual. pricing.image in GET /models shows the lowest image rate of the model's representative endpoint. See Usage accounting.

Troubleshooting

Image problems return 400 invalid_request, and the message names the failing part, such as messages[0].content[1].image_url.url.

SymptomCause and fix
400 with a data: URLThe media type isn't one of the four supported types (use image/jpeg, not image/jpg), doesn't match the bytes, or the data isn't standard base64.
400 with an HTTPS URLThe server returned an error status, a compressed response or a mismatched Content-Type (such as text/html for an error page), or the URL isn't publicly reachable.
400 for an http:// URLUse HTTPS or inline the image.
400 for a large imageThe image exceeds 8 MiB, or all media together exceed 24 MiB.
400 for SVG, HEIC, BMP or TIFFConvert the image to PNG, JPEG, GIF or WebP.
400 with an image in a system messageMove media into a user message.
408 timeoutThe image host didn't respond in time.
413 payload_too_largeInline images pushed the body over 10 MiB. Use HTTPS URLs.
503 provider_unavailableNo endpoint for the model accepts image input under your routing preferences.

Next steps