BBramaDocs

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

EndpointAliasAnswer
POST /v1/images/generationsimage-modelThe image document: data[] carrying b64_json or url (Gemini adds mime_type), with model rewritten to the route the caller named.
POST /v1/images/editsimage-modelThe 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/videosvideo-modelA job, not a render: an id and a status. The clip finishes minutes later.
GET /v1/videos/{id}?model=…video-modelThat job as the provider reports it now.
POST /v1/audio/speechvoice-modelEncoded 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/musicvoice-model or a music routeEncoded audio bytes of one song.
GET /v1/audio/voices?model=…voice-modelThe provider's voice list for the deployment's account, under voices.
POST /v1/audio/voicesvoice-modelOne voice cloned from recordings: the provider's answer, carrying voice_id.
DELETE /v1/audio/voices/{voice_id}?model=…voice-modelThe 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 optionally n, size, quality, background, output_format, response_format, user, image (1–10 input images as data: or https URLs), aspect_ratio, seed, watermark. Gemini takes only prompt, image (as data: URLs) and aspect_ratio; any other field on a gemini/… route is refused with route `gemini/…` takes prompt, image and aspect_ratio, not `…`.
  • Speech: model, input, voice (a voice name, or the vendor's voice id), and optionally response_format, speed, instructions (OpenAI-shaped vendors only), stability, similarity_boost and timestamps (ElevenLabs only), emotion (MiniMax only). A misplaced option answers invalid_request: route `…` takes no `…` option.
  • Music: model, lyrics (lines separated by \n), and optionally prompt and response_format.
  • Voice clone: model, name, optionally description, and samples: 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.

ProviderImageVideoVoiceMusicVoice 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-6 on 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-mini passes 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:

CheckRefusal
Empty prompt, input or lyricsprompt must not be empty, input must not be empty, lyrics must carry the song's words
Zero images or secondsn must be at least 1, seconds must be at least 1
Empty input image or sample listimage must carry at least one input image, samples must carry at least one recording
Playback speed outside the OpenAI speech contractspeed must be between 0.25 and 4.0
Empty audio answerprovider_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/completions and is selected by the any-vision-capable selector. 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.