> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# media

> Image, video and 3D model generation, the model catalogue, stock photo search, video clipping and the audio routes — client.media.

Four generators — images, videos, sound effects and music — a catalogue, and — further down — `stock`, a free search over a licensed photo library, `clips`, the video-clipping job, and `audio`, transcription, speech and speech-to-speech. An image, sound effect or song renders in one call and comes back as [files](https://vetta.sh/docs/sdk/files.md); a video is a **media job** you read back until it finishes. The catalogue belongs to the provider and changes without a release of ours, so it is a **search**, not a constant.

## images.generate

```ts theme={"system"}
client.media.images.generate(body: {
  prompt: string;
  model?: string;
  image_urls?: string[];   // fil_ ids or public URLs
  character?: string;      // chr_ id or name of a ready character
  n?: number;
  aspect_ratio?: string;
  seed?: number;
}): Promise<ImageGeneration>
```

[`POST /v1/media/images`](https://vetta.sh/docs/api/images), synchronous. Every output is a file:

```ts theme={"system"}
{ object: "image_generation", model: string, files: FileObject[], cost_micro_usd: number }
```

`model` left out picks the platform's default image model — with `image_urls`, the first that takes an image input; with `character`, one that pins it. `image_urls` edits or restyles images — stored `fil_` ids or public URLs — instead of rendering from nothing. `character` renders as a trained [character](https://vetta.sh/docs/sdk/characters.md) and is not combined with `image_urls`. `n` is 1–4, default 1; when some fail, the ones that rendered are still returned and billed. The client sends the required [`Idempotency-Key`](https://vetta.sh/docs/api/overview#idempotency) for you.

```ts theme={"system"}
const out = await client.media.images.generate({ prompt: "a paper kite over a grey harbour", n: 2 });
const png = await client.files.downloadBytes(out.files[0].id);
```

## videos.generate

```ts theme={"system"}
client.media.videos.generate(body: {
  model?: string;
  prompt: string;
  image_urls?: string[];   // one first frame: a fil_ id or a public URL
  seconds?: number;
  aspect_ratio?: string;
  seed?: number;
}): Promise<MediaJob>
```

[`POST /v1/media/videos`](https://vetta.sh/docs/api/video) — answers at once with the job in `queued`. `model` is optional: omitted, it is the first of the platform's video defaults the catalogue publishes — `black-forest-labs/flux-3-max`, `minimax/hailuo-3`, `bytedance/seedance-2.5`, then `alibaba/wan-3.0/text-to-video`. `image_urls` is one first frame — a stored still's `fil_` id (one rendered as a character, say) or a public URL. `seconds` is 1–60.

## meshes.create

```ts theme={"system"}
client.media.meshes.create(body: {
  model?: string;
  prompt?: string;         // or image_urls, not both
  image_urls?: string[];   // 1–4 photos of one object: fil_ ids or public https URLs
  texture?: boolean;       // default true
  rig?: boolean;           // default false; a prompt only
  seed?: number;
}): Promise<MediaJob>
```

[`POST /v1/media/meshes`](https://vetta.sh/docs/api/meshes) — a 3D model, answered at once with the job (`kind: "mesh"`) in `queued`. Read it back with [`get`](#get); a completed job's `result.files[0]` is a GLB (`model/gltf-binary`). Priced for the options used, at completion; a failed job is free.

```ts theme={"system"}
let job = await client.media.meshes.create({ prompt: "a weathered bronze lantern" });
while (job.status === "queued" || job.status === "processing") {
  await new Promise((r) => setTimeout(r, 10_000));
  job = await client.media.get(job.id);
}
const glb = await client.files.downloadBytes(job.result!.files[0].file_id); // binary-safe: the GLB as bytes
```

## soundEffects.generate

```ts theme={"system"}
client.media.soundEffects.generate(body: {
  prompt: string;              // 1–500 characters
  duration_seconds?: number;   // 0.5–30; omitted, fit to the prompt
  loop?: boolean;              // default false
}): Promise<SoundGeneration>
```

[`POST /v1/media/sound-effects`](https://vetta.sh/docs/api/audio#sound-effects), synchronous — a text prompt to a short generated clip, saved as a [file](https://vetta.sh/docs/sdk/files.md):

```ts theme={"system"}
{ object: "sound_generation", file: FileObject, duration_seconds: number | null, cost_micro_usd: number }
```

Turns a description into an effect (ambience, foley, a sting), so it takes no `voice` and no `model`. `loop` makes the clip loop seamlessly for backgrounds. The client sends the required [`Idempotency-Key`](https://vetta.sh/docs/api/overview#idempotency) for you.

```ts theme={"system"}
const sound = await client.media.soundEffects.generate({
  prompt: "a heavy wooden door slamming shut, echoing",
  duration_seconds: 3,
});
await writeFile("door.mp3", await client.files.downloadBytes(sound.file.id));
```

## music.generate

```ts theme={"system"}
client.media.music.generate(body: {
  prompt: string;              // 1–2 000 characters
  length_seconds?: number;     // 3–300; omitted, 30
  instrumental?: boolean;      // default false
}): Promise<MusicGeneration>
```

[`POST /v1/media/music`](https://vetta.sh/docs/api/audio#music), synchronous — a text prompt to an original song, saved as a [file](https://vetta.sh/docs/sdk/files.md):

```ts theme={"system"}
{ object: "music_generation", file: FileObject, duration_seconds: number | null, cost_micro_usd: number }
```

Turns a description into a song (any genre, mood or instrumentation), so it takes no `voice` and no `model`. `instrumental` forces a track with no vocals. The client sends the required [`Idempotency-Key`](https://vetta.sh/docs/api/overview#idempotency) for you.

```ts theme={"system"}
const song = await client.media.music.generate({
  prompt: "an upbeat synthwave track with driving bass and bright arpeggios",
  length_seconds: 30,
});
await writeFile("track.mp3", await client.files.downloadBytes(song.file.id));
```

## get

```ts theme={"system"}
client.media.get(id: string): Promise<MediaJob>
```

`GET /v1/media/{id}`. Any `med_` of yours, a clipping job's included. Poll until `status` is `completed` or `failed`; a completed video job's `result.files[].file_id` is the rendered video, a completed clipping job's `result.clips` are its clips (see [`clips.get`](#clipsget)).

```ts theme={"system"}
let job = await client.media.videos.generate({ model: "example/reel", prompt: "waves at dusk", seconds: 4 });
while (job.status === "queued" || job.status === "processing") {
  await new Promise((r) => setTimeout(r, 5_000));
  job = await client.media.get(job.id);
}
if (job.status === "failed") throw new Error(job.error?.message);
```

## list

```ts theme={"system"}
client.media.list(query?: {
  kind?: "video" | "clip" | "transcription" | "mesh";
  status?: "queued" | "processing" | "completed" | "failed";
  session_id?: string;
  limit?: number;
  after?: string;
}): Promise<Page<MediaJob>>
```

`GET /v1/media`, newest first. `session_id` narrows to what one session's agent submitted; API-submitted jobs carry `session_id: null`.

## listModels

```ts theme={"system"}
client.media.listModels(query: {
  kind: "image" | "video" | "mesh" | "stt" | "tts" | "s2s";
  search?: string;
  limit?: number;
  after?: string;
}): Promise<Page<MediaModel>>
```

`GET /v1/media/models`. `kind` is required: each is its own capability with its own catalogue. `stt`, `tts` and `s2s` are the [audio](https://vetta.sh/docs/api/audio.md#the-catalogues) models — the managed alias for the direction first, then pinned models.

Each entry:

**id** `string`

The model id you pass as `model` above, or to [`generate_image` / `generate_video`](https://vetta.sh/docs/capabilities/tools#generation-tools), or pin on an agent as `tools.configs.<tool>.config.models`.

**name** `string`

The model's display name.

**kind** `"image" | "video" | "stt" | "tts" | "s2s"`

Which capability it serves.

**description** `string`

What the model is good at.

```ts theme={"system"}
const video = await client.media.listModels({ kind: "video", search: "reel" });
await client.agents.update(agentId, {
  tools: {
    default_config: { permission: "allow" },
    configs: {
      generate_video: { enabled: true, permission: "allow", config: { models: [video.data[0].id] } },
    },
  },
});
```

No price is on the object. A generation is billed what it actually cost, once it has finished — see [Pricing](https://vetta.sh/docs/platform/pricing.md#media-generation--per-finished-job-media-component).

## stock.search

```ts theme={"system"}
client.media.stock.search(query: {
  query: string;
  count?: number;                                   // 1–30, default 10
  orientation?: "landscape" | "portrait" | "square";
  color?: string;                                   // a name or a hex value
  size?: "small" | "medium" | "large";            // which size `url` points at
}): Promise<{ data: StockPhoto[] }>
```

[`GET /v1/media/stock`](https://vetta.sh/docs/api/images). Not a cursor page: the library pages by number, and `count` is the whole page.

Each `StockPhoto`:

**id** `string`

The library's own id. Opaque, unprefixed, not a Naive Managed Agents resource.

**width** `number`

Pixel width of the original.

**height** `number`

Pixel height of the original.

**url** `string`

A direct image URL at the requested `size`.

**preview\_url** `string`

A small thumbnail.

**alt** `string | null`

A one-line description of the photo.

**photographer** `string | null`

Who took it — show this credit wherever the photo is used.

**attribution\_url** `string | null`

The page to link the credit to.

**dominant\_color** `string | null`

The average colour as a hex value.

```ts theme={"system"}
const { data } = await client.media.stock.search({ query: "office workspace", count: 3, orientation: "landscape" });
const hero = data[0];
// <img src={hero.url} alt={hero.alt ?? ""} />  Photo by <a href={hero.attribution_url}>{hero.photographer}</a>
```

A result is a URL, not a file; to hold the bytes as a `fil_`, import `url` through [`client.files`](https://vetta.sh/docs/sdk/files). The search is free and is booked as a `search` line at `$0`. A deploy with no stock photo library configured rejects with `feature_not_configured`.

## edits.create

```ts theme={"system"}
client.media.edits.create(body: EditRequest): Promise<EditJob>
```

`POST /v1/media/edits`. Submits a Mira edit and returns it `queued`. `video` is a `fil_` id or a public `http(s)` URL, `prompt` is what to change, and `references` is up to four pictures. `mode` is `scene`, `outfit_or_object` or `person_swap`. An `Idempotency-Key` is sent for you. Read the job with `client.media.edits.get(id)` (`GET /v1/media/edits/{id}`) until `status` is `completed`; `result.file_id` is the edit.

```ts theme={"system"}
const job = await client.media.edits.create({
  video: "fil_...",
  prompt: "the same people, on a rooftop at dusk",
  mode: "scene",
});
```

## clips.create

```ts theme={"system"}
client.media.clips.create(body: ClipCreate): Promise<MediaJob>
```

`POST /v1/media/clips`. Submits a clipping job and returns it `queued`; the clips arrive as [files](https://vetta.sh/docs/sdk/files.md) when it completes. `ClipCreate` is the [request body](https://vetta.sh/docs/api/clips.md#submit-a-clipping-job): `video_url` (public `http(s)` only), and optional `aspect_ratio`, `remove_silence`, `caption_preset` (`none | clean | bold | karaoke`), `language`, `min_seconds`, `max_seconds`, `title`. An `Idempotency-Key` is sent for you, so a retry replays rather than re-queues.

```ts theme={"system"}
const job = await client.media.clips.create({
  video_url: "https://cdn.example.com/keynote.mp4",
  caption_preset: "bold",
  language: "en",
  max_seconds: 45,
});
```

## clips.get

```ts theme={"system"}
client.media.clips.get(id: string): Promise<MediaJob>
```

`GET /v1/media/clips/{id}`. The job as it stands; once `status` is `completed`, `result.clips` holds each clip's `file_id`, `title`, `start_seconds`, `end_seconds`, `duration_seconds` and `virality` scores, and `cost_micro_usd` is what it cost.

```ts theme={"system"}
let job = await client.media.clips.get(id);
while (job.status === "queued" || job.status === "processing") {
  await new Promise((r) => setTimeout(r, 15_000));
  job = await client.media.clips.get(id);
}
if (job.result && "clips" in job.result) {
  for (const clip of job.result.clips) console.log(clip.title, clip.virality.total, clip.file_id);
}
```

Subscribe a [webhook](https://vetta.sh/docs/sdk/webhooks.md) to `media.job.completed` / `media.job.failed` to be told instead of polling.

## clips.list

```ts theme={"system"}
client.media.clips.list(query?: {
  status?: "queued" | "processing" | "completed" | "failed";
  limit?: number;
  after?: string;
}): Promise<Page<MediaJob>>
```

`GET /v1/media/clips`. Newest first. Only jobs submitted through the API are listed; what an agent's `clip_video` tool cuts inside a session lands in that session as files.

## audio.transcribe

```ts theme={"system"}
client.media.audio.transcribe(body: {
  file_id?: string;      // exactly one of file_id / url
  url?: string;
  model?: string;
  language?: string;     // ISO 639-1 hint
  timestamps?: boolean;  // default true
}): Promise<MediaJob>
```

`POST /v1/media/audio/transcriptions`. Answers a [`media_job`](https://vetta.sh/docs/api/audio#the-transcription-job) of `kind: "transcription"` — usually already `completed`, with `result.text` and `result.segments` filled in; a long recording the provider queues comes back `processing`, to be re-read with `audio.get`.

```ts theme={"system"}
const job = await client.media.audio.transcribe({ url: "https://cdn.example.com/call.mp3", language: "en" });
if (job.status === "completed" && job.result && "text" in job.result) console.log(job.result.text);
```

## audio.get

```ts theme={"system"}
client.media.audio.get(id: string): Promise<MediaJob>
```

`GET /v1/media/audio/transcriptions/{id}` — the same job, re-read.

## audio.speak

```ts theme={"system"}
client.media.audio.speak(body: {
  text: string;                    // 1–4 096 characters
  model?: string;
  voice?: string;
  format?: "mp3" | "wav" | "ogg";  // default mp3
  speed?: number;                  // 0.5–2
}): Promise<SpeechGeneration>
```

`POST /v1/media/audio/speech`. Synchronous; the reply's `file` is the stored [file](https://vetta.sh/docs/sdk/files.md), so the bytes are one `client.files.downloadBytes(speech.file.id)` away.

```ts theme={"system"}
const speech = await client.media.audio.speak({ text: "Your order has shipped." });
await writeFile("shipped.mp3", await client.files.downloadBytes(speech.file.id));
```

## audio.converse

```ts theme={"system"}
client.media.audio.converse(body: {
  file_id: string;                 // a stored recording of one spoken turn
  model?: string;
  voice?: string;
  format?: "mp3" | "wav" | "ogg";  // default mp3
}): Promise<SpeechGeneration>
```

`POST /v1/media/audio/conversations`. Synchronous, and the same `SpeechGeneration` as `speak`: the spoken reply to the turn in `file_id`, stored as a [file](https://vetta.sh/docs/sdk/files.md). The input is a stored file — `client.files.upload` or `client.files.import` a recording first.

```ts theme={"system"}
const turn = await client.files.import({ url: "https://cdn.example.com/question.wav" });
const reply = await client.media.audio.converse({ file_id: turn.id, format: "wav" });
await writeFile("reply.wav", await client.files.downloadBytes(reply.file.id));
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.