Media¶
Brama routes the generation shapes that are not text: an image, a video, a voice and a song, and the voice library a voice is chosen from. They are reached the way every model here is reached — through an alias or a canonical provider/model route, over the same client identity, the same bounded attempt and the same refusal envelope as a chat completion.
The shapes¶
| Endpoint | Alias | Answer |
|---|---|---|
POST /v1/images/generations | image-model | The image document: data[] carrying b64_json or url (Gemini adds mime_type), with model rewritten to the route the caller named. |
POST /v1/images/edits | image-model | The same image document, from the OpenAI edit form: input images as files (image or image[]) and an optional mask. A provider with an edit endpoint edits there; one that reads input images in its generation request is sent that request with them. |
POST /v1/videos | video-model | A job, not a render: an id and a status. The clip finishes minutes later. |
GET /v1/videos/{id}?model=… | video-model | That job as the provider reports it now. |
POST /v1/audio/speech | voice-model | Encoded audio bytes, with the provider's Content-Type. With "timestamps": true (ElevenLabs only) the answer is application/json: ElevenLabs' own document with the audio as audio_base64 beside the character alignment and normalized_alignment. |
POST /v1/audio/music | voice-model or a music route | Encoded audio bytes of one song. |
GET /v1/audio/voices?model=… | voice-model | The provider's voice list for the deployment's account, under voices. |
POST /v1/audio/voices | voice-model | One voice cloned from recordings: the provider's answer, carrying voice_id. |
DELETE /v1/audio/voices/{voice_id}?model=… | voice-model | The voice deleted from the deployment's account: the provider's acknowledgement. A voice the account does not hold is the provider's refusal. On the shell, brama voices remove VOICE_ID --confirm; without --confirm it is refused with exit 2, because the provider keeps no copy. |
Request fields¶
Each endpoint refuses a field it does not know (deny_unknown_fields), and a vendor option sent to a route of another vendor is refused by name, never dropped.
- Image:
model,prompt, and optionallyn,size,quality,background,output_format,response_format,user,image(1–10 input images asdata:orhttpsURLs),aspect_ratio,seed,watermark. Gemini takes onlyprompt,image(asdata:URLs) andaspect_ratio; any other field on agemini/…route is refused withroute `gemini/…` takes prompt, image and aspect_ratio, not `…`. - Speech:
model,input,voice(a voice name, or the vendor's voice id), and optionallyresponse_format,speed,instructions(OpenAI-shaped vendors only),stability,similarity_boostandtimestamps(ElevenLabs only),emotion(MiniMax only). A misplaced option answersinvalid_request: route `…` takes no `…` option. - Music:
model,lyrics(lines separated by\n), and optionallypromptandresponse_format. - Voice clone:
model,name, optionallydescription, andsamples: one or more recordings, each{"data_base64", "content_type", "filename"}.
Why a status read names a model¶
Brama holds no job state. A video identifier belongs to the provider that issued it, so the caller keeps the identifier and names the same model it started the job with; a gateway that guessed the vendor would eventually ask the wrong one, and a gateway that stored the job would become a second source of truth about somebody else's queue. A status read with no model is refused:
400 {"error":{"code":"invalid_request",
"message":"a video status read names the model that started the job: GET /v1/videos/{id}?model=…"}}
Who pays¶
The deployment does, through its own provider capability. No subscription in the pool carries an image, video or voice quota, so there is nothing for best to delegate to: a media alias whose route is best fails the shape check at startup and at PUT /v1/admin/routes. Media is the deployment's spend and appears on the deployment's bill.
Which providers¶
A provider serves a media shape only where its vendor documents that endpoint. OpenAI-shaped vendors are spoken as they are; ElevenLabs, MiniMax and Gemini each have their own adapter that translates the request and the answer, and OpenRouter's image API is the OpenAI shape with input images sent as its input_references (data: URLs only; a mask is refused with invalid_request: route `…` takes no `mask`). Every other shape is declared with an empty path and refused by name.
| Provider | Image | Video | Voice | Music | Voice library |
|---|---|---|---|---|---|
openai | /v1/images/generations; edits on /v1/images/edits | /v1/videos and /v1/videos/{id} | /v1/audio/speech | — | — |
xai | /v1/images/generations | — | — | — | — |
together | /v1/images/generations | — | — | — | — |
venice | /v1/images/generations | — | /v1/audio/speech | — | — |
groq | — | — | /v1/audio/speech | — | — |
byteplus (Seedream) | /images/generations | — | — | — | — |
gemini | /v1beta/models/{model}:generateContent | — | — | — | — |
openrouter | /api/v1/images, input images as input_references | — | — | — | — |
elevenlabs | — | — | /v1/text-to-speech/{voice} | — | /v1/voices, /v1/voices/add |
minimax | — | — | /v1/t2a_v2 | /v1/music_generation | — |
MiniMax answers HTTP 200 with its outcome in base_resp.status_code; Brama refuses a non-zero code with that code and MiniMax's message (1002 and 1039 as rate-limited, 1004 as authentication, 1008 as quota exhausted, 1000, 1001 and 1013 as provider unavailable). Each provider's key is the deployment's own capability provider:<id>. The table in the source is src/providers/adapter/registry/roster/media.rs, and it is what these pages follow.
Naming a model¶
Either the deployment's media alias or a canonical route. Two checks stand between a name and a bill:
- The provider must serve the shape.
anthropic/claude-sonnet-4-6on the image endpoint is refused with`anthropic/claude-sonnet-4-6` cannot generate images: name `image-model` or a provider/model route whose provider does. - The model must be that kind. OpenAI declares an image path, so
openai/gpt-4o-minipasses the first check and fails the second:`openai/gpt-4o-mini` is a text model: name `image-model` or a provider/model route the catalogue lists as image. The catalogue already says what each model produces, so the kind decides before a credential is redeemed. A route no public catalogue carries is allowed through — a provider serves models no list knows, and refusing those would make the catalogue's blind spots into Brama's.
A media alias named on a chat endpoint is refused by name, exactly as a decision alias is: `image-model` is a media alias: it generates on POST /v1/images/generations or POST /v1/videos, not chat completions.
Declaring the aliases¶
The three media aliases are known by name and required of nobody: a deployment that generates no media declares no route for them and changes no policy to take the release. Unrouted, each reports no_route with the command that repairs it, and a request naming one answers 503 with that same sentence.
$ brama routes set image-model openai/gpt-image-1
$ brama routes set video-model openai/sora-2
$ brama routes set voice-model openai/gpt-4o-mini-tts
Bounds¶
Brama sets no size or count limits of its own: prompts, image counts, clip lengths, spoken input, samples and request bodies go to the provider, and a provider's limit comes back as that provider's refusal. Brama refuses only what cannot be a request at all:
| Check | Refusal |
|---|---|
| Empty prompt, input or lyrics | prompt must not be empty, input must not be empty, lyrics must carry the song's words |
| Zero images or seconds | n must be at least 1, seconds must be at least 1 |
| Empty input image or sample list | image must carry at least one input image, samples must carry at least one recording |
| Playback speed outside the OpenAI speech contract | speed must be between 0.25 and 4.0 |
| Empty audio answer | provider_failure: provider returned no audio |
Not to be confused with¶
- A vision model. A chat model that reads an image answers on
POST /v1/chat/completionsand is selected by theany-vision-capableselector. Media is about what a model produces. - Image Video Router. That internal service executes caller-built ComfyUI workflows for Content Platform. Brama routes the vendor-hosted media models behind one authenticated gateway, with client identity, catalogue and refusal contract; it builds no workflow graphs.
See category for how the catalogue says what a model produces, brama image, brama video and brama speak for the shell surface. brama music --model minimax/music-2.6 --lyrics … --output song.mp3 --allow-provider-cost composes a song and prints its route, audio type, bytes and output file, brama voices list [--model …] prints the provider's voice list, brama voices clone --name … --sample a.mp3 --content-type audio/mpeg --allow-provider-cost clones a voice and brama voices remove VOICE_ID --confirm deletes one; each prints key: value lines, or one JSON document with --json, and each refuses a billable call without --allow-provider-cost.