Skip to main content
GuidesMedia inputs

Media Inputs

Sending an image, video, document, or audio file to a model, and what the marketplace does with it.

This page covers media understanding. Media generation is a separate surface: see Image Generations, Video Generations, and Music Generations.

Generation vs Understanding

The two are separate surfaces with separate models. Nothing rejects a cross-surface call up front, so sending a generation model to /v1/chat/completions, or a vision model to /v1/images/generations, surfaces as 404 no_sellers_for_model or an opaque provider error rather than a clear message.

New image from a promptEndpoint · POST /v1/images/generationsModel kind · image-generationShape · synchronous
Edited image from a source imageEndpoint · POST /v1/images/editsModel kind · image-edit models (most, not all, carry an -edit suffix)Shape · synchronous
New video from a prompt or a stillEndpoint · POST /v1/video/generationsModel kind · video-generationShape · async (submit, poll)
New music or audio clipEndpoint · POST /v1/music/generationsModel kind · music-generationShape · async (submit, poll)
Model reads an existing imageEndpoint · POST /v1/chat/completionsModel kind · vision text modelShape · image parts in messages
Model reads an existing documentEndpoint · POST /v1/chat/completionsModel kind · model declaring file_inputShape · file parts in messages
Transcript of an audio fileEndpoint · POST /v1/audio/transcriptionsModel kind · STT modelShape · multipart upload

Generation endpoints take a source image in dedicated top-level fields (image, image_url, input_images). Understanding endpoints take it inside messages[].content.

Generating media is not the same as understanding it
Understanding — you send mediaVision and audio models on /v1/chat/completions. Image or audio in, text out.
Generation — you receive media/v1/images, /v1/video, /v1/music, /v1/audio/speech. Text in, media out.
Sending an image to a generation endpoint, or asking a vision model to produce one, gets 404 no_sellers_for_model — the model is real, it just does not serve that surface.

Capability Discovery

GET /v1/models is the capability surface, public and unauthenticated. Two fields matter:

  • architecture.input_modalities, with values from text, image, video, file, audio.
  • supported_features, where vision and file_input are relevant.

Check both. The two disagree on a meaningful number of rows, and the router treats a model as image-capable when either says so. claude-opus-5 declares vision in supported_features while input_modalities reads ["text"], and it does accept images.

bash
# Models accepting image input, by either signal
curl -s $SURPLUS_BASE_URL/models \
  | jq -r '.data[]
      | select(((.architecture.input_modalities // []) | index("image"))
               or ((.supported_features // []) | index("vision")))
      | .id'

# Everything one model declares
curl -s $SURPLUS_BASE_URL/models \
  | jq '.data[] | select(.id=="gemini-3.8-flash")
      | {id, input: .architecture.input_modalities, features: .supported_features}'

A 2026-09-07 snapshot returned 403 catalog rows: 99 accepting image input, 18 declaring file, 15 declaring audio, 14 declaring video. Counts change; read the endpoint. A declared modality means the upstream model accepts it, not that a given wire spelling reaches that model through the marketplace.

Image Input

Send an OpenAI-format image content part. A remote URL and an inline data URL both work. There is no upload step and no file id to create first.

bash
curl $SURPLUS_BASE_URL/chat/completions \
  -H "Authorization: Bearer inf_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash",
    "messages": [{
      "role": "user",
      "content": [
        {"type": "text", "text": "What is in this image?"},
        {"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}
      ]
    }]
  }'
json
{
  "type": "image_url",
  "image_url": { "url": "data:image/png;base64,iVBORw0KGgo..." }
}

Marketplace Handling

messages is forwarded to the chosen seller whole. The marketplace does not fetch buyer URLs, re-encode bytes, or validate the MIME type declared in a data URL. Three behaviors apply:

Presence detection. A part typed image_url, input_image, or image marks the request as carrying an image. A capability gate can reject an image sent to a text-only model with 400 model_does_not_support_images. When that gate is inactive the request is forwarded, the provider rejects it, and the router may try a bounded number of other offers (a capability fault is capped at three upstream attempts in total) before surfacing the provider's error. That failover is gated by ADAPTER_FAILOVER, which ships off, in which case the first provider's error surfaces directly. The remedy is the same in every case: use a vision-capable model.

Refusal for images referenced by id. An image part whose only content is a file_id returns 400 unresolvable_file_reference. A file id names a file in the buyer's own provider account; the marketplace has no files API, another seller's key cannot resolve the id, and the chat wire has no field for one. Inline the bytes as a data URL instead.

Anthropic wire translation. On a seller served over the Anthropic wire, image_url is rewritten into an Anthropic image block. A data: URL becomes {"source": {"type": "base64", "media_type": "<as declared>", "data": "..."}}; an https URL becomes {"source": {"type": "url", "url": "..."}}. The media_type is copied verbatim from the data URL, not inferred from the bytes.

Video Input

The marketplace defines no contract for sending video to a chat model. No request path recognizes, validates, fetches, transcodes, or samples video, and no wire spelling for video input exists.

The data:video/mp4 Payload

A payload of this shape has been reported in the wild:

json
{"type": "image_url", "image_url": {"url": "data:video/mp4;base64,<BASE64>"}}

It is not universally supported and is not a marketplace feature. Actual behavior:

  • The MIME type is never parsed, so the part is forwarded unchanged to whichever seller wins the route. It succeeds only if that provider accepts a video payload in the image_url field.
  • Provider selection is a per-request routing decision, so an identical body can succeed on one request and fail on the next as liquidity and health change.
  • It cannot work on an Anthropic-format seller. The bridge maps it to an Anthropic image block with media_type: "video/mp4", which that block type does not accept.
  • The 10 MB JSON body limit applies, which is small for video.

Clients depending on this behavior should pin the route with a provider hint naming the verified provider, or use a BYOK priority provider. Confirm against that provider's own documentation and treat a change of provider as a change of contract.

YouTube URLs

Not supported. No marketplace code path recognizes a YouTube URL, and the OpenAI-compatible wire has no field that carries one.

  • A YouTube link in a text part reaches the model as a literal string.
  • A YouTube link in image_url.url is forwarded as an image URL and rejected by the provider.
  • Providers with native YouTube support expose it through their own API shape rather than the OpenAI-compatible wire, so it is unreachable through the marketplace even for models whose upstream supports it.

Extract frames or a transcript locally, or call that provider directly with an own-account key.

File Input

A file content part is forwarded unchanged, so a provider accepting inline document bytes works:

json
{
  "type": "file",
  "file": { "filename": "contract.pdf", "file_data": "data:application/pdf;base64,JVBERi0x..." }
}
  • No capability gate applies to file parts. Few catalog rows declare file_input, and some models accept PDFs without declaring it. Check supported_features first and expect a provider-side error otherwise.
  • A file_id on a file part is forwarded as sent. It resolves only when the credential serving the request belongs to the account owning the id, which in practice means routing to a BYOK provider.
  • A file_id on an image part is refused up front, as described above.

Audio Input

POST /v1/audio/transcriptions is the speech-to-text upload endpoint, and one of only two paths that take a multipart/form-data file body (the other is POST /v1/images/edits). It takes a file part, capped at 25 MB, against a speech-to-text model such as venice-whisper-large-v3. Chat models declaring audio in input_modalities accept provider-native audio parts on the chat wire under the same passthrough rules as everything else on this page.

Limits

JSON request bodyValue · 10 MBApplies to · every JSON endpoint, so roughly 7.5 MB of raw bytes after base64 expansion
Multipart image partValue · 8 MiB eachApplies to · POST /v1/images/edits file parts
Source images per requestValue · 8Applies to · input_images and multipart image parts on generation endpoints
Transcription uploadValue · 25 MBApplies to · POST /v1/audio/transcriptions

Providers apply their own limits, usually smaller. A payload within the marketplace limit can still be rejected upstream.

Errors

400 unresolvable_file_referenceMeaning · An image part carried only a file_id. Inline the bytes as a data URL.
400 model_does_not_support_imagesMeaning · The image-modality gate is enforcing and the resolved model is not vision-capable. The gate is off by default, in which case the provider rejects the request instead.
400 invalid_image_inputMeaning · Generation endpoints. A source image was not an https URL or data: URI, a role was invalid, or the entry was malformed.
400 too_many_input_imagesMeaning · Generation endpoints. More than 8 source images.
400 image_requiredMeaning · Generation endpoints. An edit or image-to-video request arrived with no usable image.
400 mask_not_supportedMeaning · Masked edits (inpaint) are not supported.
Provider 400Meaning · The part reached the provider and the provider rejected it. The usual outcome for an unsupported media shape.

See Also