> ## 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.

# 3D models

> Generate a textured 3D model over REST — a queued job you read back, with a GLB file on it.

A 3D model takes from under a minute (from a photo) to over ten (from a description), so `POST /v1/media/meshes` does not wait: it answers `202` with a [media job](/docs/api/video#the-media-job-object) of `kind: "mesh"` in `queued`, and you read it back with [`GET /v1/media/{id}`](/docs/api/video#retrieve-a-job) until it is `completed` or `failed`. The finished model is a GLB [file](/docs/api/files). The same job is what an agent's `generate_3d_model` tool submits. A generated model is about appearance; for a part with real dimensions, build it in code with [`POST /v1/computers/{id}/build-3d`](/docs/api/computers#build-a-3d-model) — see [3D assets](/docs/capabilities/3d).

## Generate a 3D model

`POST /v1/media/meshes` → `202 Accepted` — scope `sessions:write`, [`Idempotency-Key`](/docs/api/overview#idempotency) **required**.

**prompt** `string`

What to model, up to 2,000 characters. Give this or `image_urls`, not both.

**image\_urls** `string[]`

One to four photos of the same object — stored `fil_` ids or public `https` URLs. Two to four are read as views of one object. A `fil_` this organization does not hold is `not_found`.

**model** `string`

A model id from [`GET /v1/media/models?kind=mesh`](/docs/api/media#search-models). Omitted, a description and photos each get the platform's default.

**texture** `boolean`

Default `true`. `false` returns geometry only, for less.

**rig** `boolean`

Default `false`. With a `prompt`, rigs the model and adds an idle animation. Rigging requires `texture`: a rigged model is always textured, so `rig: true` with `texture: false` is `validation_failed`, as is `rig` with `image_urls` or on a model that does not rig.

**seed** `integer`

Repeat an earlier result, on models that honour a seed.

```bash cURL theme={"system"}
curl -fsSL https://api.vetta.sh/v1/media/meshes \
  -H "authorization: Bearer sk_live_..." \
  -H "idempotency-key: $(uuidgen)" \
  -H "content-type: application/json" \
  -d '{ "image_urls": ["fil_01J..."], "texture": true }'
```

```ts SDK theme={"system"}
const job = await client.media.meshes.create({ image_urls: ["fil_01J..."] });
```

```bash CLI theme={"system"}
vetta media mesh --image fil_01J... --wait --out lantern.glb
```

```json 202 Accepted theme={"system"}
{
  "id": "med_01J...",
  "object": "media_job",
  "kind": "mesh",
  "status": "queued",
  "model": "example/photo-to-3d",
  "input": { "image_urls": ["fil_01J..."], "texture": true, "rig": false },
  "result": null,
  "error": null,
  "cost_micro_usd": null,
  "session_id": null,
  "created_at": "2026-10-17T12:00:00.000Z",
  "completed_at": null
}
```

Once `completed`, `result` holds the GLB:

```json theme={"system"}
{ "files": [{ "file_id": "fil_01K...", "content_type": "model/gltf-binary", "bytes": 8411204 }] }
```

Read it with [`GET /v1/files/{file_id}?download=true`](/docs/api/files#retrieve-a-file). The file has `kind: "model"`, `source.type = mesh_generation` and `source.job_id` = this job. List mesh jobs with `GET /v1/media?kind=mesh`. A job an agent submitted announces itself on its session's [event stream](/docs/api/events#event-types) as `media.job.queued`, then `media.job.completed` or `media.job.failed`, with `kind: "mesh"`.

## Billing

A job is one charge for the finished model. The amount is fixed by the model, `texture` and `rig`, and is debited once, on the `media` component, when the job completes. Render time, file size and polygon count leave it unchanged. A job that fails is not billed. `GET /v1/media/models?kind=mesh` lists every option as `prices[].micro_usd`, and [Pricing](/docs/platform/pricing#3d-assets) has the table.

## Errors

| Code | When |
| - | - |
| `validation_failed` | Missing `Idempotency-Key`; both or neither of `prompt` and `image_urls`; an empty `prompt`; more than 4 images, or a count the named `model` does not take (a single-photo model takes 1, the multi-view model 2–4); a `prompt` to a photo-only `model`; `rig` with `texture: false`, with images, or on a model that does not rig; an unknown `model`. |
| `not_found` | An `image_urls` `fil_` this organization does not hold. |
| `provider_error` | The model would not take the job. Nothing is queued or billed. |
| `feature_not_configured` | This deploy has no 3D generation, or the option combination has no price. It is refused, never served free. |


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