Images, audio & files
Send images, audio, PDFs and video in a chat request on any API — checked against the model's input modalities before anything is routed or charged.
Content parts
A user message's content can be a list of parts: text plus images, audio, PDF files and video, in the shape each API already uses. Every part is checked against the model's input modalities — the modalities list on GET /v1/models/{id} and on the model page — before anything is routed or charged.
On /v1/responses, input_audio and input_video are gateway extensions in the chat shape: the gateway serves every API over the same models, so audio and video work there too where the model accepts them.
Examples
An image and a recording in one turn, with the OpenAI Python SDK:
import base64
audio = base64.b64encode(open("question.wav", "rb").read()).decode()
r = client.chat.completions.create(
model="google/gemini-2.5-flash",
messages=[{"role": "user", "content": [
{"type": "text", "text": "Answer the question in the recording about this chart."},
{"type": "image_url", "image_url": {"url": "https://example.com/chart.png"}},
{"type": "input_audio", "input_audio": {"data": audio, "format": "wav"}},
]}],
max_tokens=400,
)
print(r.usage.prompt_tokens_details) # cached_tokens, audio_tokensA PDF with cURL (the file is sent inline as a data URL):
curl https://api.yelno.ai/v1/chat/completions \
-H "Authorization: Bearer $YELNO_API_KEY" -H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-sonnet-4", "max_tokens": 600,
"messages": [{"role": "user", "content": [
{"type": "text", "text": "Summarize the termination clause."},
{"type": "file", "file": {"filename": "contract.pdf",
"file_data": "data:application/pdf;base64,JVBERi0xLjcK…"}}]}]}'The same document through /v1/messages with the Anthropic SDK:
client.messages.create(model="anthropic/claude-sonnet-4", max_tokens=600, messages=[{
"role": "user", "content": [
{"type": "document", "title": "contract.pdf",
"source": {"type": "base64", "media_type": "application/pdf", "data": pdf_b64}},
{"type": "text", "text": "Summarize the termination clause."},
]}])Video, where the model takes it, is a video_url part with an https URL or a data:video/mp4;base64,… URL.
Limits
A conversation is sent whole on every turn, so the request limit counts the media of every earlier turn too. Linked (URL) media is fetched by the model's provider and is not measured before dispatch; some models take PDFs inline only, and a linked file to one of them is refused with input_type_unsupported. File references by file_id are not supported: send the bytes inline or a URL.
Refusals
{"error": {"type": "invalid_request", "code": "input_type_unsupported", "param": "messages[0].content[1]",
"message": "'mistralai/mistral-large-4-0' does not accept audio input; this model accepts text and images", "retriable": false}}Every refusal happens before a provider is contacted and before any funds are held. A request with fallback models (models / fallback_models) skips the fallbacks that cannot take its inputs.
How inputs are charged
Images, PDF pages and video are counted by the provider as input tokens and charged at the model's input price. Audio is reported apart (usage.prompt_tokens_details.audio_tokens, and input_audio in yelno.usage.units): it is charged at the model's audio input price where one is published, otherwise as ordinary input tokens — never free. prompt_tokens always includes the audio tokens.