> **Reading as an AI agent?** This is the Markdown version of https://docs.meshy.ai/api/uv-unwrap.
>
> - Full docs index: https://docs.meshy.ai/llms.txt
> - Single-fetch full content: https://docs.meshy.ai/llms-full.txt
> - Tool-calling access via MCP server: https://docs.meshy.ai/api/ai

---
# UV Unwrap API

The UV Unwrap API automatically generates a high-quality UV unwrap for an existing 3D model. Use it as the prerequisite step before texturing — or any time you need a clean, non-overlapping UV layout for downstream tools (Blender, Substance Painter, Unreal).

The output is a "UV white model" — same shape as the input but with brand-new UV coordinates and no real texture (a 2×2 grey placeholder material is included to keep the glTF material slot valid; standard tools treat this as untextured).

> **Note:** **Limitations.** Auto UV currently supports meshes of up to **40,000 faces** — larger models are rejected with a `400`; run Remesh first to reduce the polycount. Quad and n-gon meshes are **triangulated** during UV generation, so the output is always a triangle mesh.

---

## POST /openapi/v1/uv-unwrap -- Create an UV Unwrap Task

This endpoint creates a new UV Unwrap task.

The task runs in the background. For how long it usually takes, see [Processing Times](/api/task-lifecycle#processing-times).

### Parameters

> **Note:** Exactly one of `input_task_id` or `model_url` is required. If both are provided, `input_task_id` takes priority.

  - `input_task_id` · *string* · **required**

  The ID of a completed Meshy API task whose GLB output you wish to UV-unwrap (for example an Image to 3D, Text to 3D, or Remesh result). The source task must have a status of `SUCCEEDED` and have produced a GLB file.

  If the source mesh exceeds the face-count ceiling of 40,000 faces, the request will be rejected with a `400` and you should run Remesh first to bring the polycount down.

  - `model_url` · *string* · **required**

  Provide a 3D model directly via a publicly accessible URL or data URI. **Only `.glb` is supported** — the API reads glTF binary and does not parse other formats. To UV-unwrap a model in another format (`.fbx`, `.obj`, `.stl`, `.gltf`), convert it to `.glb` first via the [Convert API](/api/convert), then pass the resulting task ID as `input_task_id` or its GLB output URL here.

  For Data URIs, use the MIME type `application/octet-stream`.

  Maximum file size: 100 MB.

  The same 40,000-face ceiling applies as for `input_task_id`: oversized meshes are rejected with a `400` — run Remesh first.

### Returns

The `result` property of the response contains the `id` of the newly created UV Unwrap task.

### Failure Modes

  - `400 - Bad Request`

  The request was unacceptable. Common causes:
  * **Missing parameter**: Either `input_task_id` or `model_url` must be provided.
  * **Invalid input task**: The `input_task_id` must refer to a successful task with a GLB result.
  * **Face count exceeded**: The source mesh has more faces than the UV Unwrap ceiling. Run Remesh first.
  * **Invalid model format**: The `model_url` points to a file with an unsupported extension.
  * **Unreachable URL**: The `model_url` could not be downloaded.
  * **Model file too large**: The `model_url` file exceeds 100 MB.

  - `401 - Unauthorized`

  Authentication failed. Please check your API key.

  - `402 - Payment Required`

  Insufficient credits to perform this task. UV Unwrap costs 5 credits per call.

  - `404 - Not Found`

  The feature is not enabled for your account. UV Unwrap is gated by a Statsig flag during rollout — contact Meshy support if you need access.

  - `429 - Too Many Requests`

  You have exceeded your rate limit.

  **cURL**

  ```bash
  # Chain from an existing Meshy task
  curl https://api.meshy.ai/openapi/v1/uv-unwrap \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
        "input_task_id": "0193bfc5-ee4f-73f8-8525-44b398884ce9"
      }'

  # Or from a publicly accessible model URL
  curl https://api.meshy.ai/openapi/v1/uv-unwrap \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
        "model_url": "https://example.com/path/to/model.glb"
      }'
  ```

  ```javascript
  import axios from 'axios';

  const headers = { Authorization: `Bearer ${YOUR_API_KEY}` };
  const payload = { input_task_id: "0193bfc5-ee4f-73f8-8525-44b398884ce9" };

  const { data } = await axios.post(
    "https://api.meshy.ai/openapi/v1/uv-unwrap",
    payload,
    { headers }
  );
  console.log(data); // { result: "<new-uv-unwrap-task-id>" }
  ```

  ```python
  import requests

  response = requests.post(
      "https://api.meshy.ai/openapi/v1/uv-unwrap",
      headers={"Authorization": f"Bearer {YOUR_API_KEY}"},
      json={"input_task_id": "0193bfc5-ee4f-73f8-8525-44b398884ce9"},
  )
  response.raise_for_status()
  print(response.json())
  ```

**Response**

```json
{
  "result": "019361c6-9b34-7b23-bef2-d0107c4d92e2"
}
```

---

## GET /openapi/v1/uv-unwrap/:id -- Retrieve an UV Unwrap Task

This endpoint retrieves the current state of an UV Unwrap task by ID.

### Returns

Returns an [UV Unwrap Task object](#the-uv-unwrap-task-object).

  **cURL**

  ```bash
  curl https://api.meshy.ai/openapi/v1/uv-unwrap/019361c6-9b34-7b23-bef2-d0107c4d92e2 \
  -H "Authorization: Bearer ${YOUR_API_KEY}"
  ```

  ```javascript
  import axios from 'axios';
  const headers = { Authorization: `Bearer ${YOUR_API_KEY}` };
  const { data } = await axios.get(
    `https://api.meshy.ai/openapi/v1/uv-unwrap/${taskId}`,
    { headers }
  );
  ```

  ```python
  import requests
  response = requests.get(
      f"https://api.meshy.ai/openapi/v1/uv-unwrap/{task_id}",
      headers={"Authorization": f"Bearer {YOUR_API_KEY}"},
  )
  response.raise_for_status()
  ```

See the [example task object](#example-uv-unwrap-task-object) below.

---

## DELETE /openapi/v1/uv-unwrap/:id -- Delete an UV Unwrap Task

Permanently delete an UV Unwrap task. The task and its outputs become inaccessible.

A task that is still `PENDING` is deleted and the credits consumed at
create-time are refunded.

A task that is already `IN_PROGRESS` cannot be deleted: the request is
rejected with `409 Conflict` and the task keeps running. Credits for a task
the worker has already started are not refundable, so deleting it mid-run
would cost you the credits and the result both. Wait for it to reach
`SUCCEEDED`, `FAILED` or `CANCELED`, then delete it.

A task in a terminal state (`SUCCEEDED`, `FAILED` or `CANCELED`) is deleted
without a refund.

  **cURL**

  ```bash
  curl https://api.meshy.ai/openapi/v1/uv-unwrap/019361c6-9b34-7b23-bef2-d0107c4d92e2 \
  -X DELETE \
  -H "Authorization: Bearer ${YOUR_API_KEY}"
  ```

---

## GET /openapi/v1/uv-unwrap -- List UV Unwrap Tasks

Returns a paginated list of the caller's UV Unwrap tasks, newest first. Standard pagination via `page_num` and `page_size`.

  **cURL**

  ```bash
  curl "https://api.meshy.ai/openapi/v1/uv-unwrap?page_num=1&page_size=20" \
  -H "Authorization: Bearer ${YOUR_API_KEY}"
  ```

---

## GET /openapi/v1/uv-unwrap/:id/stream -- Stream an UV Unwrap Task

Subscribe to task progress as Server-Sent Events. Each `message` event carries an [UV Unwrap Task object](#the-uv-unwrap-task-object); the stream closes once the task reaches `SUCCEEDED`, `FAILED`, or `CANCELED`.

Use this instead of polling `GET /openapi/v1/uv-unwrap/:id` for lower latency on completion.

  **cURL**

  ```bash
  curl https://api.meshy.ai/openapi/v1/uv-unwrap/019361c6-9b34-7b23-bef2-d0107c4d92e2/stream \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -N
  ```

---

## The UV Unwrap Task Object

  - `id` · *string*

  Unique identifier for the task.

  - `type` · *string*

  Always `uv-unwrap`.

  - `model_urls` · *object*

  Pre-signed download URLs for the generated UV white model. UV Unwrap always returns a single `glb` entry — the output preserves the input geometry, swaps in fresh UV coordinates, and uses a default grey material in place of any texture.

  - `thumbnail_url` · *string*

  Pre-signed URL to a PNG preview of the UV white model.

  - `progress` · *integer*

  Task progress, from `0` to `100`.

  - `status` · *string*

  One of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`.

  - `preceding_tasks` · *integer*

  Number of tasks queued ahead of this one. Present while status is `PENDING`.

  - `created_at` · *timestamp*

  Timestamp of task creation, in milliseconds.

  - `started_at` · *timestamp*

  Timestamp of when processing began, in milliseconds. `0` until started.

  - `finished_at` · *timestamp*

  Timestamp of completion, in milliseconds. `0` until finished.

  - `expires_at` · *timestamp*

  Timestamp after which the signed download URLs expire, in milliseconds.

  - `task_error` · *object*

  Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference.

  - `consumed_credits` · *integer*

  Credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). UV Unwrap charges 5 credits on success.

<span id="example-uv-unwrap-task-object" />

**Example UV Unwrap Task Object**

```json
{
  "id": "019361c6-9b34-7b23-bef2-d0107c4d92e2",
  "type": "uv-unwrap",
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019361c6-9b34-7b23-bef2-d0107c4d92e2/output/model.glb?Expires=***"
  },
  "thumbnail_url": "https://assets.meshy.ai/***/tasks/019361c6-9b34-7b23-bef2-d0107c4d92e2/output/preview.png?Expires=***",
  "progress": 100,
  "status": "SUCCEEDED",
  "preceding_tasks": 0,
  "created_at": 1716579120000,
  "started_at": 1716579122000,
  "finished_at": 1716579180000,
  "expires_at": 1716665580000,
  "task_error": {
    "message": ""
  },
  "consumed_credits": 5
}
```
