# Meshy API > Meshy is an AI-powered 3D model generation platform. The Meshy API is a RESTful API that allows you to programmatically generate 3D models, textures, images, rig characters, and animate them. - API Base URL: `https://api.meshy.ai/openapi/` - Documentation: https://docs.meshy.ai - Status Page: https://status.meshy.ai > **For agents:** For single-fetch full content (all docs pages concatenated), see https://docs.meshy.ai/llms-full.txt. For tool-calling access, install the Meshy MCP server — see https://docs.meshy.ai/api/ai. ## Instructions for Large Language Models When generating code that integrates with the Meshy API, follow these guidelines: ### 1. Authentication All requests require a Bearer token in the `Authorization` header: ``` Authorization: Bearer msy_YOUR_API_KEY ``` API keys are created at https://www.meshy.ai/settings/api and have the format `msy_`. **Tip:** For tool-calling access from MCP-compatible agents (Claude Code, Cursor, Windsurf, Claude Desktop, Codex CLI, etc.), install the Meshy MCP server instead of calling this REST API directly: ``` claude mcp add meshy --env MESHY_API_KEY=msy_YOUR_API_KEY -- npx -y @meshy-ai/meshy-mcp-server ``` See https://docs.meshy.ai/api/ai for the full install matrix (8 clients) and tool reference. ### 2. Asynchronous Task Model Meshy uses an asynchronous execution model. All generation endpoints return a task ID, not the result directly. You retrieve results via one of three mechanisms: - **Polling** — GET the task endpoint until `status` is terminal (shown in the examples below) - **SSE streaming** — connect to `//:id/stream` for real-time updates (see section 3) - **Webhooks** — register a URL to receive a POST when the task completes (see https://docs.meshy.ai/api/webhooks.md) **Correct pattern:** ```python import requests, time, os headers = {"Authorization": f"Bearer {os.environ['MESHY_API_KEY']}"} # Step 1: Create a task response = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json={"mode": "preview", "prompt": "a monster mask"}, ) task_id = response.json()["result"] # Step 2: Poll until completion while True: task = requests.get( f"https://api.meshy.ai/openapi/v2/text-to-3d/{task_id}", headers=headers, ).json() if task["status"] == "SUCCEEDED": break if task["status"] == "FAILED": raise Exception(task["task_error"]["message"]) time.sleep(5) # Step 3: Download result model_url = task["model_urls"]["glb"] ``` **WRONG pattern** (expecting synchronous result): ```python # WRONG - the POST does not return a model response = requests.post("https://api.meshy.ai/openapi/v2/text-to-3d", ...) model = response.json()["model_urls"] # WRONG ``` ### 3. SSE Streaming (Alternative to Polling) All task endpoints support Server-Sent Events streaming at `//:id/stream`: ```python import requests, json headers = { "Authorization": f"Bearer {API_KEY}", "Accept": "text/event-stream" } response = requests.get( f"https://api.meshy.ai/openapi/v2/text-to-3d/{task_id}/stream", headers=headers, stream=True ) for line in response.iter_lines(): if line and line.startswith(b"data:"): data = json.loads(line.decode("utf-8")[5:]) print(data["status"], data.get("progress")) if data["status"] in ["SUCCEEDED", "FAILED", "CANCELED"]: break response.close() ``` ### 4. Task Statuses All tasks follow the same lifecycle: `PENDING` -> `IN_PROGRESS` -> `SUCCEEDED` | `FAILED` | `CANCELED` ### 5. Timestamps All timestamps in the API are Unix epoch milliseconds (not seconds). For example, `1693569600000` represents September 1, 2023 12:00:00 PM UTC. ### 6. Model Output Formats 3D model outputs are available in multiple formats: GLB, FBX, OBJ, USDZ. Access them via `model_urls.glb`, `model_urls.fbx`, etc. Not all formats are always available; omitted properties mean that format was not generated. ### 7. Asset Retention Generated assets are retained for a maximum of **3 days** for non-Enterprise customers. Download and store models locally if you need them longer. ### 8. Rate Limits | Tier | Requests/Second | Queue Tasks | Priority | |------|-----------------|-------------|----------| | Pro | 20 | 10 | Default | | Studio | 20 | 20 | Higher | | Enterprise | 100 | 50+ | Highest | Exceeding limits returns `429 Too Many Requests`. ### 9. Choosing the Right AI Model - Use `"latest"` or `"meshy-6"` for the best quality (default). - Use `"meshy-5"` for the previous generation model. - `"latest"` always resolves to the newest model (currently Meshy 6). ### 10. Common Mistakes to Avoid - **Don't call CORS-restricted endpoints from browser JavaScript.** The API blocks CORS requests. Use a server-side proxy. - **Don't forget `enable_pbr: true`** if you need metallic/roughness/normal maps. - **Don't set both `texture_prompt` and `texture_image_url`** — if both are provided, `texture_prompt` takes precedence. - **Don't assume model format availability.** Check that the URL key exists in `model_urls` before downloading. --- ## Complete Code Example: Text to 3D (Preview + Refine) ```python import requests, os, time headers = {"Authorization": f"Bearer {os.environ['MESHY_API_KEY']}"} # 1. Create preview task preview_resp = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json={ "mode": "preview", "prompt": "a monster mask", "should_remesh": True, }, ) preview_resp.raise_for_status() preview_task_id = preview_resp.json()["result"] # 2. Poll preview task while True: task = requests.get( f"https://api.meshy.ai/openapi/v2/text-to-3d/{preview_task_id}", headers=headers, ).json() if task["status"] == "SUCCEEDED": break if task["status"] == "FAILED": raise Exception(task["task_error"]["message"]) time.sleep(5) # 3. Download preview model with open("preview_model.glb", "wb") as f: f.write(requests.get(task["model_urls"]["glb"]).content) # 4. Create refine task (texturing) refine_resp = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json={ "mode": "refine", "preview_task_id": preview_task_id, "enable_pbr": True, }, ) refine_resp.raise_for_status() refine_task_id = refine_resp.json()["result"] # 5. Poll refine task while True: task = requests.get( f"https://api.meshy.ai/openapi/v2/text-to-3d/{refine_task_id}", headers=headers, ).json() if task["status"] == "SUCCEEDED": break if task["status"] == "FAILED": raise Exception(task["task_error"]["message"]) time.sleep(5) # 6. Download refined (textured) model with open("refined_model.glb", "wb") as f: f.write(requests.get(task["model_urls"]["glb"]).content) ``` ## Complete Code Example: Image to 3D ```python import requests, os, time headers = {"Authorization": f"Bearer {os.environ['MESHY_API_KEY']}"} response = requests.post( "https://api.meshy.ai/openapi/v1/image-to-3d", headers=headers, json={ "image_url": "https://example.com/photo.jpg", "should_texture": True, "enable_pbr": True, }, ) response.raise_for_status() task_id = response.json()["result"] while True: task = requests.get( f"https://api.meshy.ai/openapi/v1/image-to-3d/{task_id}", headers=headers, ).json() if task["status"] == "SUCCEEDED": break if task["status"] == "FAILED": raise Exception(task["task_error"]["message"]) time.sleep(5) with open("model.glb", "wb") as f: f.write(requests.get(task["model_urls"]["glb"]).content) ``` --- --- # API Reference # Quickstart Source: https://docs.meshy.ai/api/quick-start # Quickstart Every request in this guide needs one. Creating a key takes less than a minute. Four steps to your first 3D model, using the Meshy REST API. > **Note:** **Using an AI coding assistant?** See our [AI Integration](/api/ai) page — install the Meshy MCP server for tool-calling access from Claude Code, Cursor, Windsurf, and other MCP-compatible tools, or point a plain chat agent at [`llms.txt`](/llms.txt). --- ## 1Get your API key Create an API key from your account settings — you won't be able to view it again after this screen, so store it somewhere safe. Every request authenticates with a `Bearer` token in the `Authorization` header — see [Authentication](/api/authentication). ![Open API Settings from the API menu, then create your key](/images/api/quick-start/api-key-settings.webp) > **Note:** **Security tip:** avoid pasting your key directly into scripts — store it as an environment variable instead: `export MESHY_API_KEY="msy_..."`. --- ## 2Make your first Image-to-3D request Export your key, then create your first task with [Image to 3D](/api/image-to-3d). Working from a text prompt or multiple photos instead? See [Text to 3D](/api/text-to-3d) or [Multi-Image to 3D](/api/multi-image-to-3d). **Export your key** ```bash export MESHY_API_KEY="" ``` > **Note:** Run this in your terminal (Terminal on macOS, Command Prompt or PowerShell on Windows) — not in a browser. Every example below uses this photo — swap in your own `image_url` to try something else. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/image-to-3d \ -X POST \ -H "Authorization: Bearer ${MESHY_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "image_url": "https://docs.meshy.ai/images/api/quick-start/source-photo.webp" }' ``` ```javascript const headers = { Authorization: `Bearer ${process.env.MESHY_API_KEY}` }; const { data } = await axios.post( 'https://api.meshy.ai/openapi/v1/image-to-3d', { image_url: 'https://docs.meshy.ai/images/api/quick-start/source-photo.webp' }, { headers }, ); const taskId = data.result; console.log('Task created:', taskId); ``` ```python import os import requests headers = {"Authorization": f"Bearer {os.environ['MESHY_API_KEY']}"} response = requests.post( "https://api.meshy.ai/openapi/v1/image-to-3d", headers=headers, json={"image_url": "https://docs.meshy.ai/images/api/quick-start/source-photo.webp"}, ) response.raise_for_status() task_id = response.json()["result"] print("Task created:", task_id) ``` --- ## 3Check task status Requests return a task ID immediately. Poll the same endpoint until `status` is `SUCCEEDED` — replace `` below with the ID returned in step 2. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/image-to-3d/ \ -H "Authorization: Bearer ${MESHY_API_KEY}" ``` ```javascript const headers = { Authorization: `Bearer ${process.env.MESHY_API_KEY}` }; let task; while (true) { const { data } = await axios.get( `https://api.meshy.ai/openapi/v1/image-to-3d/${taskId}`, { headers }, ); task = data; if (task.status === 'SUCCEEDED' || task.status === 'FAILED') break; console.log(task.status, task.progress); await new Promise((resolve) => setTimeout(resolve, 5000)); } ``` ```python import os import time import requests headers = {"Authorization": f"Bearer {os.environ['MESHY_API_KEY']}"} while True: response = requests.get( f"https://api.meshy.ai/openapi/v1/image-to-3d/{task_id}", headers=headers, ) response.raise_for_status() task = response.json() if task["status"] in ("SUCCEEDED", "FAILED"): break print(task["status"], task["progress"]) time.sleep(5) ``` **Response — SUCCEEDED** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "status": "SUCCEEDED", "progress": 100, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "task_error": { "message": "" } } ``` > **Note:** Polling not your style? Use [SSE streaming](/api/image-to-3d#stream-an-image-to-3d-task) or a [webhook](/api/webhooks) to get notified the moment a task finishes. --- ## 4Download your model Grab the model from `model_urls` in the response above. Each format (GLB, FBX, OBJ, USDZ, STL) is a signed, time-limited URL — or skip the command line and paste the URL directly into your browser's address bar to download it. **cURL** ```bash curl -L "" -o model.glb ``` ```javascript const { data } = await axios.get(task.model_urls.glb, { responseType: 'arraybuffer' }); fs.writeFileSync('model.glb', data); ``` ```python import requests response = requests.get(task["model_urls"]["glb"]) response.raise_for_status() with open("model.glb", "wb") as f: f.write(response.content) ``` > **Note:** Files are retained for 3 days on non-Enterprise plans — see [Asset Retention](/api/asset-retention). ### Put it all together Prefer one script that does the whole thing — create, poll, download? ```javascript const headers = { Authorization: `Bearer ${process.env.MESHY_API_KEY}` }; const imageUrl = 'https://docs.meshy.ai/images/api/quick-start/source-photo.webp'; // 1. Create the task const { data: created } = await axios.post( 'https://api.meshy.ai/openapi/v1/image-to-3d', { image_url: imageUrl }, { headers }, ); const taskId = created.result; // 2. Poll until it finishes let task; while (true) { const { data } = await axios.get(`https://api.meshy.ai/openapi/v1/image-to-3d/${taskId}`, { headers }); task = data; if (task.status === 'SUCCEEDED' || task.status === 'FAILED') break; await new Promise((resolve) => setTimeout(resolve, 5000)); } // 3. Download the result (only if the task succeeded) if (task.status !== 'SUCCEEDED') { throw new Error(`Task ${task.status}: ${task.task_error?.message || 'unknown error'}`); } const { data: model } = await axios.get(task.model_urls.glb, { responseType: 'arraybuffer' }); fs.writeFileSync('model.glb', model); console.log('Saved model.glb'); ``` ```python import os import time import requests headers = {"Authorization": f"Bearer {os.environ['MESHY_API_KEY']}"} image_url = "https://docs.meshy.ai/images/api/quick-start/source-photo.webp" # 1. Create the task response = requests.post( "https://api.meshy.ai/openapi/v1/image-to-3d", headers=headers, json={"image_url": image_url}, ) response.raise_for_status() task_id = response.json()["result"] # 2. Poll until it finishes while True: task = requests.get( f"https://api.meshy.ai/openapi/v1/image-to-3d/{task_id}", headers=headers, ).json() if task["status"] in ("SUCCEEDED", "FAILED"): break time.sleep(5) # 3. Download the result (only if the task succeeded) if task["status"] != "SUCCEEDED": raise SystemExit(f"Task {task['status']}: {task.get('task_error', {}).get('message', 'unknown error')}") model = requests.get(task["model_urls"]["glb"]) with open("model.glb", "wb") as f: f.write(model.content) print("Saved model.glb") ``` --- ## Explore common workflows Rig a humanoid mesh with a skeleton so it's ready to animate in Unity or Unreal. Set `model_type` to `lowpoly` on Image to 3D for a clean, game-ready mesh. Convert a finished model into a multi-color 3MF file, ready to slice and print. --- ## Next steps - Prefer a UI? Try the [API Playground](/api/playground) — configure a request, run it, and copy the generated code. - Browse the full [API reference](/api) for every endpoint. - Check [Pricing](/api/pricing), [Rate Limits](/api/rate-limits), and [Errors](/api/errors) before you go to production. - Watch the [Changelog](/api/changelog) for updates and bug fixes. - Have feedback or facing issues? Join our [Discord](https://discord.com/invite/KgD5yVM9Y4) community — we'd love to hear from you! --- # API Playground Source: https://docs.meshy.ai/api/playground # API Playground The Meshy API Playground is an interactive console for trying endpoints without writing any code. Configure a request, run a real generation, and copy the equivalent cURL, Python, or JavaScript when you're ready to build. > **Note:** The API Playground is available on the **Pro**, **Premium**, **Ultra**, **Studio**, and **Enterprise** plans. --- ## Overview [Open the Playground](https://www.meshy.ai/api-playground) from the web app to pick an endpoint, fill in parameters with inline guidance, and submit. Tasks run through the same asynchronous pipeline as the API — you'll watch the task move from `PENDING` to `SUCCEEDED` and can inspect the full response and the resulting model. ![Meshy API Playground interface showing an image-to-3D request with a live model preview and the equivalent cURL request and response](/images/playground/api-playground.png) When a request looks right, switch to the code view to copy a ready-to-run snippet in cURL, Python, or JavaScript and drop it straight into your project. New to the API? Start with the [Quickstart](/api/quick-start). ## Supported endpoints Which endpoints you can run in the Playground depends on your plan: - **Enterprise** — access to every API endpoint. - **Pro**, **Premium**, **Ultra**, and **Studio** — access to a subset of endpoints. You can browse the full list of endpoints under **API Endpoints** in the sidebar. ## Authentication & credits Requests are authorized with an API key passed in the `Authorization: Bearer` header, exactly like a direct API call. The Playground runs against your own account, so every request **uses your plan credits and counts toward your rate limits**, just like any other API call. Create and manage keys on the [API settings page](https://www.meshy.ai/settings/api), and see the [Authentication](/api/authentication) guide for details on key formats and security. --- # Authentication Source: https://docs.meshy.ai/api/authentication # Authentication Using the Meshy API requires authentication. This guide will show you how to create an account and API keys. --- ## API Keys ### Creating a Meshy Account Meshy API requires you to have a Meshy account to create and manage API keys. If a request is made to the API without an API key, the API will respond with an invalid credentials error. You can create a Meshy account by visiting the [Meshy official website](https://www.meshy.ai/) and sign up. ### Creating API Keys Once you have created a Meshy account, you can create API keys by visiting the [API settings page](https://www.meshy.ai/settings/api). You can create multiple API keys for different purposes. For example, you can create one API key for your iOS app and another for your web app. The usage of each API key is tracked separately, and you can revoke them at any time. To create an API key, click on the `Create API Key` button on the API page, and then enter a name for your API key. Once you have created an API key, you will be shown the API key value. You can copy the API key value and store it in a secure location. **You will not be able to see this API key value again.** ### Using API Keys Once you have created an API key, you can use it to authenticate your requests to the Meshy API. You can pass your API key to the API in the `Authorization` header, an example header is shown below. ```json { "Authorization": "Bearer msy_sOmEbOgUsApIkEyFoReXaMpLe1234567890" } ``` > **Note:** The `Bearer `   prefix in the header value is mandatory to interact with the Meshy API programatically. > You can learn more about it at [IETF RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750) --- ## Security We take security very seriously at Meshy, and we work hard to ensure that Meshy API is secure. We hope your data and your users' data is safe with us. Here are some high-level guidelines to help you keep your data and requests safe when using Meshy API, but please also make sure to follow the guidelines practiced at your team or workplace. ### Transport Layer Security While your data is encrypted at rest once it's stored in Meshy, Meshy API uses and enforces [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security), to encrypt data in transit. It means that all requests to and from Meshy API are sent over HTTPS, and any request made over HTTP will get an `301 Moved Permanently` status code. Although not recommended, in some cases, if you have to talk to HTTP, you need to explicity tell your HTTP client to follow HTTP to HTTPS redirections. Here are some examples: ```bash # use `-L` to follow HTTP to HTTPS redirections curl -L -X 'POST' \ https://api.meshy.ai/openapi/v1/text-to-texture ``` ```python import requests # use `allow_redirects=True` to follow HTTP to HTTPS redirections response = requests.post("https://api.meshy.ai/openapi/v1/text-to-texture", allow_redirects=True) ``` ```javascript // use `followRedirects: true` to follow HTTP to HTTPS redirections const response = await fetch("https://api.meshy.ai/openapi/v1/text-to-texture", { redirect: "follow", }); ``` ### API Key Safety > **Note:** Please note that even Meshy team members cannot view or recover revoked API keys for you! Once minted, API keys are **not** visible in the dashboard anymore, so please download and keep it safe and securely since anyone who obtains it can use it to talk to Meshy API on your behalf. If you believe your API key has been compromised, you can revoke it at any time from the dashboard, once revoked, it will no longer be valid. ### Security Disclosure If you believe you've discovered a security issue in Meshy API, please [get in touch](mailto:support@meshy.ai?subject=%5BSupport%5D%20Enter%20your%20question%20or%20problem%E2%80%A6&body=How%20can%20we%20assist%20you%3F%20Please%20provide%20any%20relevant%20details%20that%20will%20help%20us%20respond%20to%20your%20inquiry.) with us. We appreciate your responsible disclosure and will make every effort to acknowledge your contributions. --- # Errors Source: https://docs.meshy.ai/api/errors # Errors In this guide, we will talk about what happens when something goes wrong while you work with the Meshy API. --- ## Request Errors These errors are returned immediately when your API request is rejected. Check the HTTP status code and `message` field to understand what went wrong. ### Response Format The error response contains a single `message` field describing what went wrong: - `message` · *string* A short description of the error. ### Status Codes - `2xx` A 2xx status code indicates a successful response. - `200 - OK` By default if everything worked as expected a 200 status code will be returned. - `202 - Accepted` Your request has been accepted for processing, but the processing has not been completed. This is a non-committal response from Meshy API. For example, a request to create a new task will return a 202 status code. - `4xx` A 4xx status code indicates a client error. - `400 - Bad Request` The request was unacceptable, often due to missing a mandatory parameter or one of the parameters was malformed. - `401 - Unauthorized` No valid API key provided or the API key provided is not authorized to access the Meshy API endpoint. - `402 - Payment Required` Insufficient funds in the account associated with the provided API key. - `403 - Forbidden` Access to the requested resource is forbidden. This might happen if you try to access the Meshy API directly from client-side JavaScript code, as Cross-Origin Resource Sharing (CORS) requests from browsers are not permitted. Consider using a server-side proxy for such requests. For more details, see the [MDN CORS guide](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS/Errors). - `404 - Not Found` The requested resource doesn't exist. For example, when you try to retrieve a task by its ID but provided an invalid ID, you will get a 404 status code. - `429 - Too Many Requests` Too many requests hit the Meshy API too quickly. Please refer to the [Rate Limits](/api/rate-limits) guide for details. - `5xx` A 5xx status code indicates a server error. If you see one, please check our [status page](https://status.meshy.ai) for more information and contact us via [Discord](https://discord.com/invite/KgD5yVM9Y4) for help. **Example: 400 Bad Request** ```bash { "message": "Invalid model file extension: .3dm" } ``` --- ## Task Errors These errors occur after a task has been created and is processing. Check the `task_error` object on the task response for error details. The `task_error` object contains the following fields: - `type` · *string* The error category. Always present on failed tasks. See [Error Types](#error-types) below. - `message` · *string* A human-readable description of the error. Always present on failed tasks. - `code` · *string* A specific error code identifying the problem. Present when additional details are available. See [Error Codes](#error-codes) below. - `doc_url` · *string* A link to detailed documentation for this error code, including resolution guidance. Present when `code` is present. **Error with details** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "status": "FAILED", "task_error": { "type": "invalid_input", "code": "image_too_complex", "message": "The uploaded image is too complex for 3D generation.", "doc_url": "https://docs.meshy.ai/en/api/errors#image-too-complex" } } ``` **Error without details** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "status": "FAILED", "task_error": { "type": "server_error", "message": "An internal error occurred. Please retry." } } ``` --- ## Error Types The `type` field tells you the broad category of the failure. Use it to decide your retry strategy. - `invalid_input` Something is wrong with the input you provided. Check the `code` and `message` fields for specifics, fix the issue, and retry. - `timeout` Processing exceeded the time limit. This is often transient. Retry the request, and if it keeps failing, try simplifying your input. - `service_unavailable` The service is temporarily unavailable. Wait a moment and retry. - `server_error` An internal error occurred during processing. Retry the request. If the issue persists, contact support with your task ID. --- ## Error Codes When the `code` field is present, it identifies a specific, actionable problem. Below is the full reference for each error code. ### `image_too_complex` This error occurs when the input image or prompt describes a subject that is too geometrically complex for the 3D generation model to process. Common examples include: - **Dense piles of small objects** (e.g., a crate full of fruit, a stack of books) - **Intricate repeating patterns** (e.g., lattice structures, scaffolding, wire meshes) - **Complex building structures** (e.g., multi-story buildings with many windows and balconies) - **Multiple distinct objects in one image** instead of a single subject **Examples of inputs that are likely too complex:**
A crate of mixed berries An intricate cathedral ceiling A building under construction with scaffolding A honeycomb lattice sphere
**Resolution:** 1. **Use a single object per image.** The model works best with one clear subject. Don't include multiple separate objects in the same image or prompt. 2. **Simplify your subject.** Reduce the level of detail. For example, a simple vase instead of a vase filled with dozens of flowers. 3. **Avoid scene-level prompts.** Entire buildings, city blocks, interiors filled with furniture, or landscapes are likely to exceed the model's capacity. Focus on a single object instead. 4. **Avoid dense repeating structures.** Subjects like scaffolding, wire meshes, lattice patterns, or piles of many small items are common triggers. ### `model_missing_uv` This error occurs when you upload a model for texturing with `enable_original_uv` set to `true`, but the model has no UV coordinates. UV coordinates define how a 2D texture wraps onto the 3D surface of your model. ![No UVs vs Good UVs](/images/errors/uv_missing_vs_good.png) **Resolution:** The right fix depends on why you set `enable_original_uv` to `true`: - **If you need to preserve your model's original UV layout** (e.g., custom seam placement for precise texture mapping): your model must have valid UV coordinates. Verify UVs exist in your 3D software's UV editor before uploading. Note that STL files cannot store UV data, so use GLB, FBX, or OBJ instead. - **If you don't need specific UV control** (or you're not sure): omit `enable_original_uv` or set it to `false`. The system will automatically generate a UV layout for your model. The auto-generated UVs are optimized for coverage but you won't have control over where texture seams are placed. ### `model_insufficient_uv` This error occurs when a model has UV coordinates, but the UV coverage is too small for quality texturing. This commonly happens with models exported from 3D tools that generate placeholder or collapsed UVs without a proper unwrap. ![Insufficient UVs vs Good UVs](/images/errors/uv_insufficient_vs_good.png) **Resolution:** - **If you need to preserve your original UV layout:** re-unwrap the model's UVs in your 3D software. Ensure UV islands are properly spread across the UV space rather than collapsed into a small area. - **If you don't need specific UV control:** omit `enable_original_uv` or set it to `false`. The system will automatically generate a new UV layout. The tradeoff is you lose your original seam placement, but the auto-generated UVs will have proper coverage for texturing. ### `invalid_input` This is the fallback error code when the input fails validation but no more specific code applies. The `message` field contains the specific reason for the failure. Common causes include: - Empty or corrupted model files - Unsupported file format variations (e.g., ASCII FBX files, meshopt-compressed GLB) - No valid 3D objects found in the uploaded model (e.g., file contains only armatures, cameras, or lights) - Content that does not pass safety filters **Resolution:** Check the `message` field for specifics on what went wrong. Verify your input files and parameters match the endpoint's requirements. ### `moderation_blocked` This error occurs when your prompt or reference images are rejected by AI safety filters. The filter evaluates both the text prompt and any reference images together. **Resolution:** - Rephrase your text prompt to remove suggestive or sensitive descriptions. - Adjust reference images if they depict content that may trigger safety filters. ### `timeout` This error means your task's processing time exceeded the allowed limit. This can happen due to high system load or because the input is too complex to process within the time limit. **Resolution:** 1. **Retry the request.** Timeouts are often transient and a retry may succeed. 2. **Simplify your input.** If retries keep failing, your input may be too complex. Try reducing the level of detail in your image or prompt. See [`image_too_complex`](#image-too-complex) for guidance on what types of inputs are harder to process. ### `format_conversion_failed` This error occurs when the generated 3D model could not be converted to your requested output format. The model was generated successfully, but the conversion step failed. **Resolution:** 1. **Retry the request.** 2. **Try a different output format.** If a specific format keeps failing, switch to another format that suits your needs. --- ## Best Practices 1. **Implement retry logic.** For `timeout` and `service_unavailable` errors, implement exponential backoff retry logic. 2. **Log task IDs.** Always log the task ID for debugging purposes. Include it when contacting support. 3. **Validate inputs.** Ensure your input images and models meet the format requirements before submission. --- # Pricing Source: https://docs.meshy.ai/api/pricing # Pricing Simple and flexible pricing. --- Meshy API for generation is a pay-before-you-go product. You need to purchase API usage based on your application's need before using Meshy API. You can purchase additional credits for API usage from your [subscription settings page](https://www.meshy.ai/settings/subscription). For volume API pricing and custom contracts, please [contact sales](https://www.meshy.ai/contact). The Meshy API pricing is based on credits. Here's a detailed breakdown of the API pricing: | API | Price per call | | --- | --- | | Text to 3D (Preview) - Mesh Generation | Meshy-6 models and low poly models: 20 credits
Other models: 5 credits | | Text to 3D (Refine) - Texture Generation | 10 credits (`texture_resolution` `2k`/`4k`)
15 credits (`texture_resolution` `8k`) | | Image to 3D | Meshy-6 models: 20 credits (without texture), 30 credits (with texture), 35 credits (with 8K texture)
Low poly (Meshy T1) models: 20 credits (without texture), 30 credits (with texture), 35 credits (with 8K texture)
Smart Topology (Meshy T2) models: 5 credits (without texture), 15 credits (with texture), 20 credits (with 8K texture)
Other models: 5 credits (without texture), 15 credits (with texture) | | Multi Image to 3D | Meshy-6 models: 20 credits (without texture), 30 credits (with texture), 35 credits (with 8K texture)
Other models: 5 credits (without texture), 15 credits (with texture) | | Retexture | 10 credits (`texture_resolution` `2k`/`4k`)
15 credits (`texture_resolution` `8k`) | | Remesh | 5 credits | | Convert | 1 credit | | Resize | 1 credit | | Auto-Rigging | 5 credits | | Animation | 3 credits | | Text to Image | nano-banana: 3 credits, nano-banana-2: 6 credits, nano-banana-pro: 9 credits, gpt-image-2: 9 credits | | Image to Image | nano-banana: 3 credits, nano-banana-2: 6 credits, nano-banana-pro: 9 credits, gpt-image-2: 12 credits | | 3D Print (Multi-Color) | 10 credits | | 3D Print (Analyze Printability) | Free | | 3D Print (Repair Printability) | 10 credits | | Creative Lab — Keychain (Prototype) | 6 credits | | Creative Lab — Keychain (Build) | 30 credits | | Creative Lab — Fridge Magnet (Prototype) | 6 credits | | Creative Lab — Fridge Magnet (Build) | 30 credits | | Creative Lab — Figure (Prototype) | 6 credits | | Creative Lab — Figure (Build) | 30 credits | | Creative Lab — Vinyl Figure (Prototype) | 6 credits | | Creative Lab — Vinyl Figure (Build) | 30 credits | | Creative Lab — Brick Figure (Prototype) | 6 credits | | Creative Lab — Brick Figure (Build) | 30 credits | | Creative Lab — Lamp (Prototype) | 6 credits | | Creative Lab — Lamp (Build) | 30 credits | | Creative Lab — Keycap (Prototype) | 12 credits (one call always returns exactly one candidate) | | Creative Lab — Keycap (Build) | 50 credits | The API is subject to change in the future. If you need more API usage with a lower price, please [contact sales by filling out this form](https://www.meshy.ai/contact). --- # Rate Limits Source: https://docs.meshy.ai/api/rate-limits # Rate Limits Rate limits are restrictions that our API imposes on the number of times a user or client can access our services within a specified period of time. --- ## Why Limits We've put rate limits in place on our API to help create the best experience for everyone. Here's why they're important: - To keep our service safe and sound! Think of rate limits as friendly bouncers - they make sure nobody can overwhelm our API with too many requests at once. This helps protect our service from potential misuse and keeps everything running smoothly. - To make sure everyone gets their fair share. Just like sharing toys in a playground, we want to make sure all our users have equal access to the API. By gently limiting how many requests each user can make, we ensure nobody has to wait too long for their turn. - To keep performance zippy and reliable. By managing the overall flow of requests, we can maintain fast response times and stable service for all our wonderful users. It's like making sure a highway doesn't get too crowded - traffic flows better when we prevent congestion! --- ## How Limits Work Rate limits are measured in 2 ways: - **Requests per Second**: This is the number of network requests your can make per second. - **Queue Tasks**: This is the number of concurrent generation tasks your can run in queue at any given time. Queue tasks include Text to 3D, Image to 3D, Text to Texture, and Remesh endpoints. Other endpoints like Upload and Balance are not included in this limit. The limits are applied on a per-account basis. This means that the limits are shared across all of your API keys. Besides rate limits, task processing priority will also affect the speed of your tasks. Each user tier has specific rate limits and priority levels designed to match their needs. Here are the current limits by tier: | User Tier | Requests per Second | Queue Tasks | Priority Level | | --- | --- | --- | --- | | Pro | 20 | 10 | Default | | Premium | 20 | 30 | Higher than Pro | | Ultra | 20 | 100 | Highest | | Studio | 20 | 20 | Higher than Pro | | Enterprise | 100 | Default to 50, can be customized | Highest | If you exceed these limits, you'll receive a `429 Too Many Requests` response from our API. There are two types of hits that can trigger this, each with a different response: - **Request Hit**: This happens when you make too many requests per second. You'll receive a `429 Too Many Requests` response with a `RateLimitExceeded` message. - **Queue Hit**: This happens when you have too many concurrent generation tasks running. You'll receive a `429 Too Many Requests` response with a `NoMoreConcurrentTasks` message. --- # Asset Retention Source: https://docs.meshy.ai/api/asset-retention # Asset Retention Asset Retention is the amount of time that Meshy retains your generated assets. --- Please note that any models generated through our API will only be retained for a maximum of **3 days**. After this period, the models will be automatically deleted from our servers. If you're not an Enterprise customer, we kindly ask for your understanding and recommend downloading and storing your models locally if you need them for a longer duration. Enterprise customers can retain their models indefinitely. --- # Webhooks Source: https://docs.meshy.ai/api/webhooks # Webhooks Webhooks allow you to receive real-time updates from Meshy when your API tasks are completed or change status. Once configured, Meshy will POST event payloads in json format to the URLs you specify. --- ## Why Create Webhooks Using webhooks has several advantages, especially with regards to checking on API task statuses automatically. Webhooks require less effort and costs than continuously polling the API to get task status updates. Webhooks also allow near real-time updates and ultimately scale better than API polling. This also enables you to better manage your rate limits, especially if you are polling constantly. --- ## Setup & Configuration To enable webhooks, navigate to the API settings page when logged in to the Meshy web application. Find the "Webhooks" section below your API Keys and click the "Create Webhook" button. Provide your desired https URL to receive webhooks from and enable the webhook to automatically receive task updates from Meshy. You may have a maximum of 5 active webhooks per Meshy account. When a webhook is enabled, all API task status updates will be automatically sent to the payload URL. For security purposes, we only allow sending webhooks to https URLs at this time. If you would like to configure local testing, see the following section. --- ## Webhook Delivery Requirements For your webhook to function normally and continue receiving events: - Your server must respond with an **HTTP status code below 400** (e.g., `200 OK`, `202 Accepted`). - Any response with a status code `>= 400` will be treated as a failed delivery. - Multiple consecutive failures may: - Cause progress updates to be delayed or arrive out of order - Automatically disable your webhook after repeated attempts (see Auto-Disable Policy) **Tip:** Always return a success response after you validate and store the webhook payload, even if further processing happens asynchronously. --- ## Forwarding Webhooks for Local Testing If you would like to test your webhook code locally, which typically is at an http address, you can use a webhook proxy URL to forward webhooks to your computer or codespace. The below are recommended steps using smee.io, but you may use any service you'd like to generate a webhook proxy URL. ### Get a webhook proxy URL: 1. In your browser, navigate to https://smee.io/ 2. Click "Start a new channel" 3. Copy the full URL under "Webhook Proxy URL". You will use this URL in the following setup steps. ### Forward webhooks: 1. If you don't already have smee-client installed, run the following command in your terminal. ```text npm install --global smee-client ``` 2. To receive forwarded webhooks from smee.io, run the following command in your terminal. Replace `WEBHOOK_PROXY_URL` with your webhook proxy URL from earlier. ```text smee --url WEBHOOK_PROXY_URL --path /webhook --port 3000 ``` You should see output that looks like this, where `WEBHOOK_PROXY_URL` is your webhook proxy URL: ```text Forwarding WEBHOOK_PROXY_URL to http://127.0.0.1:3000/webhook Connected WEBHOOK_PROXY_URL ``` 3. Keep this running while you test out your webhook. When you want to stop forwarding webhooks, enter Ctrl+C. Note that the path is /webhook and the port is 3000. These values may come in handy when you want to set up your own code to receive webhook deliveries later on. ### Create a webhook: You may now use the webhook proxy URL to create a new webhook in the Meshy API settings page. --- ## Sample Response When a task status changes, Meshy will POST a webhook payload to your configured URL. The payload contains the task object in JSON format. For a complete description of all task object properties and example payloads, see: - [Text to 3D Task Object](/api/text-to-3d#example-text-to-3d-task-object) - [Image to 3D Task Object](/api/image-to-3d#example-image-to-3d-task-object) - [Multi-Image to 3D Task Object](/api/multi-image-to-3d#example-multi-image-to-3d-task-object) - [Remesh Task Object](/api/remesh#example-remesh-task-object) - [Retexture Task Object](/api/retexture#example-retexture-task-object) - [Rigging Task Object](/api/rigging#example-rigging-task-object) - [Animation Task Object](/api/animation#example-animation-task-object) --- # AI Integration Source: https://docs.meshy.ai/api/ai # AI Integration Meshy exposes two channels for AI agents and coding assistants: the Meshy MCP server for tool-calling, and `llms.txt` / `llms-full.txt` for docs ingestion. If you are integrating Meshy from Claude Code, Cursor, Windsurf, Codex, or any other MCP-compatible tool, install the MCP server below. If you are integrating from a plain chat agent with no MCP support, point it at [`https://docs.meshy.ai/llms.txt`](/llms.txt) instead. --- ## What is MCP The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard that lets AI assistants call external tools and retrieve structured context. The Meshy MCP server wraps the Meshy REST API as a set of tools your agent can invoke — generate a model, check a task, download the result — without hand-writing HTTP code. The MCP server is open source and published on npm as [`@meshy-ai/meshy-mcp-server`](https://www.npmjs.com/package/@meshy-ai/meshy-mcp-server). Source: [github.com/meshy-dev/meshy-mcp-server](https://github.com/meshy-dev/meshy-mcp-server). > **Note:** You need a Meshy API key. Create one at [https://www.meshy.ai/settings/api](https://www.meshy.ai/settings/api). The MCP server reads it from the `MESHY_API_KEY` environment variable. --- ## Quick Install **add-mcp** ```bash # Detects installed AI clients and configures Meshy for each npx add-mcp @meshy-ai/meshy-mcp-server --env MESHY_API_KEY=msy_YOUR_API_KEY ``` **Claude Code** ```bash # macOS / Linux / WSL claude mcp add meshy --env MESHY_API_KEY=msy_YOUR_API_KEY -- npx -y @meshy-ai/meshy-mcp-server # Windows PowerShell — use add-json to avoid `--` parsing issues claude mcp add-json meshy '{"command":"npx","args":["-y","@meshy-ai/meshy-mcp-server"],"env":{"MESHY_API_KEY":"msy_YOUR_API_KEY"}}' ``` **Cursor** ```json // .cursor/mcp.json { "mcpServers": { "meshy": { "command": "npx", "args": ["-y", "@meshy-ai/meshy-mcp-server"], "env": { "MESHY_API_KEY": "msy_YOUR_API_KEY" } } } } ``` **Windsurf** ```json // ~/.codeium/windsurf/mcp_config.json { "mcpServers": { "meshy": { "command": "npx", "args": ["-y", "@meshy-ai/meshy-mcp-server"], "env": { "MESHY_API_KEY": "msy_YOUR_API_KEY" } } } } ``` **Claude Desktop** ```json // ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) // %APPDATA%\Claude\claude_desktop_config.json (Windows) { "mcpServers": { "meshy": { "command": "npx", "args": ["-y", "@meshy-ai/meshy-mcp-server"], "env": { "MESHY_API_KEY": "msy_YOUR_API_KEY" } } } } ``` **Codex** ```bash codex mcp add meshy --env MESHY_API_KEY=msy_YOUR_API_KEY -- npx -y @meshy-ai/meshy-mcp-server ``` **VS Code** ```json // .vscode/mcp.json (workspace) or User settings > MCP Servers { "servers": { "meshy": { "command": "npx", "args": ["-y", "@meshy-ai/meshy-mcp-server"], "env": { "MESHY_API_KEY": "msy_YOUR_API_KEY" } } } } ``` **Other** ```json // Generic stdio MCP config. Consult your client's docs for the exact file. { "mcpServers": { "meshy": { "command": "npx", "args": ["-y", "@meshy-ai/meshy-mcp-server"], "env": { "MESHY_API_KEY": "msy_YOUR_API_KEY" } } } } ``` > **Note:** **Prefer a drop-in skill instead?** The open-source [`meshy-3d-agent`](https://github.com/meshy-dev/meshy-3d-agent) skill pack ships pre-written Meshy workflows (generate → poll → download) for Claude Code, Cursor, and OpenClaw. It calls the Meshy REST API directly — no MCP server required. > > ```bash > npx skills add meshy-dev/meshy-3d-agent > ``` --- ## Available Tools The MCP server exposes the Meshy REST API as tools, grouped by capability. ### 3D Generation - `meshy_text_to_3d` — create a 3D model from a text prompt - `meshy_image_to_3d` — create a 3D model from one image - `meshy_multi_image_to_3d` — create a 3D model from multiple images of the same object - `meshy_text_to_3d_refine` — add texture to a preview mesh ### Post-Processing - `meshy_remesh` — change topology and/or polycount of an existing model - `meshy_retexture` — apply a new texture to an existing model - `meshy_rig` — add a skeleton to a 3D humanoid character - `meshy_animate` — apply an animation to a rigged character ### Image Generation - `meshy_text_to_image` — 2D image from text - `meshy_image_to_image` — 2D image from a reference image ### Task Management - `meshy_get_task_status` — check task status and download URLs - `meshy_list_tasks` — list recent tasks, optionally filtered by type/status - `meshy_cancel_task` — cancel a pending or in-progress task - `meshy_download_model` — fetch a completed model file and save locally ### Workspace - `meshy_list_models` — list all models in the authenticated user's workspace ### 3D Printing - `meshy_send_to_slicer` — detect installed slicers and launch the model in one (runs locally on your machine; no Meshy API call) - `meshy_analyze_printability` — **currently returns a manual print-readiness checklist** (wall thickness, overhangs, manifold mesh, etc.). Will be upgraded to automated analysis once the Meshy printability API is available. - `meshy_process_multicolor` — convert a textured model into a multi-color 3MF file for printing ### Account - `meshy_check_balance` — query remaining credits > **Note:** Tool names and behaviors may evolve. The authoritative list lives in the [MCP server source](https://github.com/meshy-dev/meshy-mcp-server/tree/main/src/tools). --- ## Example Prompts Drop these into your MCP-enabled chat as a starting point. ``` Generate a 3D fox from the prompt "a cartoon fox sitting", preview it, then texture it with PBR maps. Download the final GLB to ./outputs. ``` ``` Take the image at https://example.com/sculpture.jpg and convert it into a riggable 3D character. Use `should_remesh: true` and 50k target polycount. ``` ``` What's my current Meshy credit balance? ``` ``` List my last 10 successful text-to-3d tasks and download the top 3 as GLB into ./downloads/. ``` --- ## llms.txt and llms-full.txt If your agent doesn't support MCP, or you want to ingest the Meshy docs into a prompt directly, point it at our plain-text surfaces: - [`llms.txt`](/llms.txt) — compact index + integration instructions (the correct async-polling pattern, auth rules, rate limits, model choice, common mistakes). - [`llms-full.txt`](/llms-full.txt) — every API page concatenated in a single file for single-fetch ingestion. - Per-page Markdown: append `.md` to any endpoint URL. Example: [`https://docs.meshy.ai/api/text-to-3d.md`](/api/text-to-3d.md). All three are regenerated every time the docs site builds, so they never drift from the HTML docs. --- ## FAQ ### Is the MCP server stateless? Yes. Your MESHY_API_KEY is used per request and never persisted on the server side. ### Does MCP cost the same as the REST API? Yes — every MCP tool call maps to a single REST call and consumes credits at the exact same rate. See the Pricing page for the full matrix. ### What are the rate limits? The MCP server shares the same rate-limit plane as the REST API. See the Rate Limits page for per-tier limits. ### What Meshy data can the MCP access? Only what the MESHY_API_KEY can access via REST. Scopes and permissions are identical. ### How do I report issues? File an issue at the meshy-mcp-server repository: https://github.com/meshy-dev/meshy-mcp-server/issues --- # Changelog Source: https://docs.meshy.ai/api/changelog # Changelog See all of the latest features and updates to the Meshy API and plugins. --- ## July 2026 ### `Jul 27` - New **[Creative Lab — Brick Figure API](/api/creative-lab-brick-figure)**: turn a photo into a brick-style collectible 3D minifigure. Same two-stage workflow as the [Figure API](/api/creative-lab-figure) — `prototype` (6 credits) generates a styled concept image, `build` (30 credits) turns it into a textured 3D model with GLB and OBJ + MTL outputs. See [Pricing](/api/pricing) for the full breakdown. ### `Jul 22` - New **[Creative Lab — Keycap API](/api/creative-lab-keycap)**: turn a photo into a full-color custom mechanical keyboard keycap. Two-stage workflow — `prototype` (12 credits) generates a finished-keycap design render, then `build` (50 credits) turns the design you pick (via `candidate_id`) into a textured 3D keycap model with GLB and OBJ bundle outputs, exported at real-world millimeter scale. Currently supports the standard Cherry MX 1u base (`cherry-mx-1x1-r1`); more standard sizes are planned. See [Pricing](/api/pricing) for the full breakdown. ### `Jul 21` - We now support **8K base color textures** via a new `texture_resolution` parameter (`2k` / `4k` / `8k`) on the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task), and [Retexture](/api/retexture#create-a-retexture-task) endpoints. At `8k`, PBR maps are generated at 4K and no emission map is produced. 8K texture generation costs 15 credits (`2k`/`4k` remain 10). See [Pricing](/api/pricing). - The `hd_texture` boolean is deprecated in favor of `texture_resolution` — it is still honored and equivalent to `texture_resolution: "4k"` for backward compatibility. ### `Jul 20` - New **[Creative Lab — Vinyl Figure API](/api/creative-lab-vinyl-figure)**: turn a photo into a big-head vinyl collectible 3D figure. Same two-stage workflow as the [Figure API](/api/creative-lab-figure) — `prototype` (6 credits) generates a styled concept image, `build` (30 credits) turns it into a textured 3D model with GLB and OBJ + MTL outputs. See [Pricing](/api/pricing) for the full breakdown. ### `Jul 13` - Added a new **Smart Topology** `model_type` to the [Image to 3D](/api/image-to-3d) API, offering two models via `ai_model`: `meshy-t1` — the current low-poly model — and `meshy-t2` — a new model with cleaner topology, natively separated parts, triangle output, and a face count you can set with `target_polycount`. `meshy-t2` is the default under `smart-topology`. The existing `model_type: lowpoly` is now deprecated but continues to serve traffic for backward compatibility. ### `Jul 7` - Added the `aspect_ratio` parameter to the [Image to Image](/api/image-to-image) API, so you can control the output image ratio when editing. Allowed values are `1:1`, `16:9`, `9:16`, `4:3`, `3:4` for the nano-banana models and `1:1`, `3:2`, `2:3` for `gpt-image-2`. Optional; defaults to `1:1`, and cannot be combined with `generate_multi_view`. ## June 2026 ### `Jun 17` - New **[API Playground](/api/playground)** docs page: an interactive console for trying endpoints without writing code, then copying the equivalent cURL, Python, or JavaScript. Available on the Pro, Premium, Ultra, Studio, and Enterprise plans. ### `Jun 15` - New **[UV Unwrap API](/api/uv-unwrap)**: generate a high-quality UV layout for an existing 3D model — the prerequisite step before texturing, or any time you need a clean, non-overlapping UV layout for downstream tools. Takes either an `input_task_id` (a completed Image to 3D, Text to 3D, or Remesh task) or a `model_url` (`.glb` only) and returns a "UV white model" with brand-new UV coordinates. 5 credits per call. Supports meshes of up to 40,000 faces (run [Remesh](/api/remesh) first if larger); quad and n-gon meshes are triangulated during UV generation. ### `Jun 12` - Updated **Creative Lab API** Build pricing to **30 credits** per call for [Keychain](/api/creative-lab-keychain), [Fridge Magnet](/api/creative-lab-fridge-magnet), and [Figure](/api/creative-lab-figure) (previously 20). [Lamp](/api/creative-lab-lamp) is unchanged at 30 credits. Prototype pricing is unchanged at 6 credits per image. See [Pricing](/api/pricing) for the full breakdown. ### `Jun 5` - Added the optional `alpha_thumbnail` parameter to the [Image to 3D](/api/image-to-3d), [Multi-Image to 3D](/api/multi-image-to-3d), [Text to 3D](/api/text-to-3d), [Retexture](/api/retexture), [Remesh](/api/remesh), and [Repair Printability](/api/repair-printability) APIs. When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it under the new `alpha_thumbnail_url` response field. The existing `thumbnail_url` is unchanged. Defaults to `false`. ### `Jun 1` - New **Creative Lab APIs**: a family of product-scoped endpoints that turn a source photo (or text prompt) into a 3D-printable consumer product. Four products at launch — [Keychain](/api/creative-lab-keychain), [Fridge Magnet](/api/creative-lab-fridge-magnet), [Figure](/api/creative-lab-figure), and [Lamp](/api/creative-lab-lamp). Each follows a two-stage `prototype` → `build` workflow chained via `input_task_id`, served under product-scoped URLs (`/openapi/creative-lab//v1/...`) with per-product versioning so products can evolve on independent version lines. Prototype: 6 credits per call. Build: 30 credits per call. --- ## May 2026 ### `May 26` - Added `multi_view_thumbnails` parameter to the [Multi-Image to 3D](/api/multi-image-to-3d) API. When set to `true`, the task additionally renders four cardinal-view thumbnails (front, right, back, left) and returns them under the new `thumbnail_urls` response field. The existing `thumbnail_url` field is unchanged. Adds approximately 3 seconds to task latency. ### `May 22` - The convert and resize functionality from the [Remesh API](/api/remesh) is now available as standalone [Convert API](/api/convert) and [Resize API](/api/resize) endpoints. The deprecated parameters on Remesh will continue to work for backward compatibility. ### `May 13` - Added `multi_view_thumbnails` parameter to the [Image to 3D](/api/image-to-3d) API. When set to `true`, the task additionally renders four cardinal-view thumbnails (front, right, back, left) and returns them under the new `thumbnail_urls` response field. The existing `thumbnail_url` field is unchanged. Adds approximately 3 seconds to task latency. ### `May 12` - Added `resize_longest_side` parameter to the [Remesh](/api/remesh) API. Resizes the model so the longest bounding-box dimension equals the specified value in meters. Mutually exclusive with `resize_height` and `auto_size`. ### `May 11` - Deprecated `symmetry_mode` parameter on [Text to 3D](/api/text-to-3d), [Image to 3D](/api/image-to-3d), and [Multi-Image to 3D](/api/multi-image-to-3d) endpoints. This parameter no longer affects output. ### `May 7` - New [Analyze Printability API](/api/analyze-printability): Analyze a succeeded Meshy task — or any 3D model URL — for FDM 3D printing readiness. Async create + stream pattern: POST returns a task_id, then GET / SSE stream return watertightness, volume, hole and non-manifold-edge metrics once SUCCEEDED. Free, no credits consumed. - New [Repair Printability API](/api/repair-printability): Repair a 3D model for FDM printability — fix non-manifold edges, degenerate faces, holes, and other topology issues. Accepts an existing Meshy `input_task_id` or a `model_url` (`.glb`, `.stl`, `.obj`). Output format matches the input. 10 credits per task. --- ## April 2026 ### `Apr 27` - Added `consumed_credits` field to all task responses across every API endpoint. Shows the number of credits consumed by each task. The field is present for tasks in `PENDING`, `IN_PROGRESS`, and `SUCCEEDED` statuses. Returns `0` for `FAILED` tasks (credits are automatically refunded on failure). See [Pricing](/api/pricing) for credit costs per endpoint. ### `Apr 24` - Added `model_url` parameter to the [Multi-Color Print](/api/multi-color-print#create-a-multi-color-3d-print-task) endpoint. Submit a textured 3D model directly (via URL or Data URI) instead of an `input_task_id` from a prior Meshy task. Supported formats: `.glb`, `.fbx`. When both `model_url` and `input_task_id` are provided, `input_task_id` takes priority. ### `Apr 21` - Added `input_task_id` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) endpoints. Reference a completed Text to Image or Image to Image task's output directly instead of providing `image_url` / `image_urls`. When both are supplied, `input_task_id` takes priority. ### `Apr 20` - Added `hd_texture` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task), and [Retexture](/api/retexture#create-a-retexture-task) endpoints. When enabled, the base color texture is generated at 4K (4096×4096) resolution for higher detail. Only supported for `meshy-6` and `latest`. Defaults to `false`. - The PBR bundle returned when `enable_pbr` is `true` now includes an `emission` map under `texture_urls` for `meshy-6` and `latest` tasks across [Image to 3D](/api/image-to-3d), [Multi-Image to 3D](/api/multi-image-to-3d), [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task), and [Retexture](/api/retexture). No request change is required. ### `Apr 14` - Added `decimation_mode` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task), and [Remesh](/api/remesh#create-a-remesh-task) endpoints. Sets the adaptive decimation polycount level: `1` (ultra), `2` (high), `3` (medium), or `4` (low). ### `Apr 12` - Restructured API documentation: added parameter grouping with dependent fields, inline defaults, required/deprecated badges, expandable sub-navigation, and split Multi-Image, Rigging, and Animation into separate pages. --- ## March 2026 ### `Apr 2` - Added `3mf` format support to `target_formats` parameter across all endpoints ([Image to 3D](/api/image-to-3d), [Text to 3D](/api/text-to-3d), [Remesh](/api/remesh), [Retexture](/api/retexture)). Note: 3MF is opt-in only and must be explicitly requested. - New [Multi-Color Print API](/api/multi-color-print): Convert 3D models to multi-color 3MF format for 3D printing. Supports 1-16 color palettes with configurable precision. 10 credits per task. ### `Mar 20` - Retired the Meshy-4 AI model. All API requests using `meshy-4` are no longer supported. Please migrate to `meshy-6` or `latest`. - Added `auto_size` and `origin_at` parameters to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D](/api/text-to-3d), and [Remesh](/api/remesh#create-a-remesh-task) endpoints. When `auto_size` is enabled, the service uses AI vision to estimate real-world height and resize the model automatically. `origin_at` sets the origin position (`bottom` or `center`). In the Remesh API, `auto_size` is mutually exclusive with `resize_height`. ### `Mar 17` - Added optional `target_formats` parameter to [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D](/api/text-to-3d), and [Retexture](/api/retexture#create-a-retexture-task) endpoints. Specify which 3D formats to generate (e.g., `["glb", "fbx"]`) to reduce task completion time. --- ## February 2026 ### `Feb 28` - Added `remove_lighting` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task), and [Retexture](/api/retexture#create-a-retexture-task) APIs. Removes highlights and shadows from the base color texture for cleaner results under custom lighting. Only supported for `meshy-6` and `latest`. Defaults to `true`. - The [Retexture](/api/retexture#create-a-retexture-task) and [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task) APIs now support `meshy-6` as an `ai_model` value for full Meshy 6 texturing. ### `Feb 25` - Added `image_enhancement` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) APIs for users who want to opt out of input image optimization and preserve the exact appearance of their input. Only supported for `meshy-6` and `latest`. Defaults to `true`. ### `Feb 20` - Added `model_type` parameter to the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task) API for generating low-poly meshes optimized for cleaner polygons. --- ## January 2026 ### `Jan 27` - Added detailed [Failure Modes](/api/errors#task-errors) documentation for all API endpoints, including common HTTP error codes (400, 401, 402, 404, 422, 429) and task failure reasons. This helps developers better understand and handle API errors. ### `Jan 26` - The [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) API now supports Meshy-6 for full mesh generation. The `ai_model` parameter now accepts `meshy-6` and `latest` resolves to Meshy 6. ### `Jan 22` - Deprecated `art_style` for the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task) API (Meshy-6). The parameter was designed for legacy models (Meshy-4 / Meshy-5) and will be removed in a future release. - Deprecated `enable_pbr` for the [Text to 3D](/api/text-to-3d) and [Image to 3D](/api/image-to-3d) APIs when `ai_model` is `meshy-4`. This parameter will be removed in a future release. - Updated the default value of `should_remesh` parameter for Meshy-6 in the [Text to 3D](/api/text-to-3d) and [Image to 3D](/api/image-to-3d) APIs. The parameter now defaults to `false` for `meshy-6`, and `true` for other models if not specified. ### `Jan 19` - The `latest` option for `ai_model` in the [Text to 3D (Preview)](/api/text-to-3d#create-a-text-to-3d-preview-task) and [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) APIs now resolves to Meshy 6. ### `Jan 12` - Added a new `model_type` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) API for generating low-poly meshes optimized for cleaner polygons. --- ## December 2025 ### `Dec 31` - Launched the [API Playground](https://www.meshy.ai/api-playground), a dedicated space for developers to explore API parameters and test requests directly on the Meshy website. - Introduced the [Text to Image API](/api/text-to-image) and [Image to Image API](/api/image-to-image), enabling AI-powered image generation from text prompts and image editing from reference images. Both APIs support the `nano-banana` and `nano-banana-pro` models, with optional multi-view generation. ### `Dec 22` - The `video_url` field in the [Text to 3D](/api/text-to-3d) API response is now deprecated and will be removed in a future release. ### `Dec 04` - Added a new `pose_mode` parameter to the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task), [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), and [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) APIs. This parameter accepts `a-pose`, `t-pose`, or an empty string (default). The `is_a_t_pose` parameter is now deprecated in favor of `pose_mode`. --- ## November 2025 ### `Nov 24` - The [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) APIs add an optional `save_pre_remeshed_model` parameter and expose `model_urls.pre_remeshed_glb` when a pre-remesh backup is requested. ### `Nov 06` - The [Text to 3D Refine API](/api/text-to-3d#create-a-text-to-3d-refine-task) now supports `ai_model = latest`, which resolves to Meshy 6 Preview. - The [Image to 3D API](/api/image-to-3d#create-an-image-to-3d-task) now defaults to Meshy-6-preview texturing when `ai_model = latest` and `should_texture = true`. - The [Multi-Image to 3D API](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) now supports `ai_model = latest`, running Meshy-6-preview for texturing by default while mesh generation remains Meshy-5. - The [Retexture API](/api/retexture) adds a `latest` option for `ai_model` (Meshy-6-preview) and now defaults to it when omitted. ### `Nov 04` - The [Remesh API](/api/remesh#create-a-remesh-task) now preserves textures for uploaded models. - The [Retexture API](/api/retexture) now preserves textures for uploaded models when the `enable_original_uv` option is enabled. --- ## October 2025 ### `Oct 28` - Added the `x-api-version` response header to indicate the current API server version. ### `Oct 20` - Added an optional `convert_format_only` boolean parameter to the [Remesh API](/api/remesh#create-a-remesh-task) to support converting the format of the input model file only. - Added `rigged_character_glb_url` to the response of [The Rigging Task Object](/api/rigging#the-rigging-task-object). ### `Oct 01` - Remove `text-to-voxel` APIs --- ## September 2025 ### `Sep 23` - Added a `latest` option for `ai_model` in the [Text to 3D](/api/text-to-3d#create-a-text-to-3d-preview-task) API to use Meshy 6 Preview. - Temporary 50% discount in place for Meshy-6-preview generation tasks to 10 credits that will last until Sep 30, 2025. After the discount period, the cost of Meshy-6-preview tasks will return to the normal 20 credits. ### `Sep 18` - Updated [API pricing](/api/pricing) for [Text to 3D](/api/text-to-3d) and [Image to 3D](/api/image-to-3d) to reflect different costs for Meshy 6 and other models. ### `Sep 16` - Added a `latest` option for `ai_model` in the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) API to use Meshy 6 Preview. ### `Sep 4` - Expanded `model_url` input support to `.glb`, `.gltf`, `.obj`, `.fbx`, `.stl` for [Remesh](/api/remesh#create-a-remesh-task) and [Retexture](/api/retexture). --- ## August 2025 ### `Aug 18` - Added an optional `is_a_t_pose` parameter to the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task), [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), and [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) APIs to generate models in an A/T pose. ### `Aug 13` - Meshy 5 is now stable for [Text to 3D](/api/text-to-3d) and [Image to 3D](/api/image-to-3d) (`ai_model`: `meshy-5`), delivering improved quality and consistency. --- ## July 2025 ### `Jul 31` - Support PBR texture maps in API via `enable_pbr` parameter for latest `meshy-5` model for [Text to 3D](/api/text-to-3d), [Image to 3D](/api/image-to-3d), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), and [Retexture](/api/retexture) endpoints. --- ## June 2025 ### `Jun 25 ` - Added the [Retexture API](/api/retexture), which allows users to retexture 3D models based on Meshy's latest foundation AI models. ### `Jun 19` - Added deletion APIs for [Text to 3D](/api/text-to-3d), [Image to 3D](/api/image-to-3d), [Remesh](/api/remesh), [Rigging](/api/rigging), and [Animation](/api/animation). - Added the `ai_model` parameter to the [Text to 3D Refine API](/api/text-to-3d#create-a-text-to-3d-refine-task). ### `Jun 17` - Added documentation for [Webhooks](/api/webhooks). ### `Jun 10` - The [Remesh API](/api/remesh#create-a-remesh-task) now supports base64-encoded GLB format models in the `model_url` parameter via Data URI. --- ## May 2025 ### `May 20` - Added an optional `moderation` parameter to the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task), [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task), [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task), and [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task) APIs. When enabled, input content is automatically screened for potentially harmful content before generation. ### `May 15` - Introduced the Auto-rigging & Animation API, enabling users to automatically rig and animate 3D models. [Learn more about Rigging](/api/rigging) and [Animation](/api/animation). --- ## April 2025 ### `Apr 29` - Introduced the [Multi-Image to 3D API](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), allowing generation of 3D models from 1 to 4 input images using the `meshy-5` AI model. - Added the `meshy-5` AI model option to the [Text to 3D](/api/text-to-3d) and [Image to 3D](/api/image-to-3d) APIs. The `latest` tag now also resolves to `meshy-5`. ### `Apr 17` - Added the `texture_image_url` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task) APIs, allowing users to guide the texture generation process with an image. --- ## March 2025 ### `Mar 28` - Added the `latest` parameter to the [Text to 3D](/api/text-to-3d#create-a-text-to-3d-preview-task) and [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) APIs, enabling access to our upcoming advanced AI models for improved generation quality. ### `Mar 14` - The [Text to Texture API](/api/text-to-texture#create-a-text-to-texture-task) now supports base64-encoded models in the `model_url` parameter via Data URI, similar to the `image_url` in the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) API. ### `Mar 06` - Updated pricing for API generation tasks: - Text to 3D (Preview): Increased from 2 to 5 credits per call - Text to 3D (Refine): Increased from 5 to 10 credits per call - Image to 3D: Now 5 credits without texture, 15 credits with texture - Text to Texture: Increased from 5 to 10 credits per call - Text to Voxel: Remains at 5 credits per call --- ## February 2025 ### `Feb 18` - Added a test mode API key `msy_dummy_api_key_for_test_mode_12345678` that allows developers to test API integration without consuming credits. All valid requests using this key will return the same sample task results. ### `Feb 13` - **Breaking Changes**: - Free tier task creation will end on `March 20, 2025`. After that, all API task requests will require a paid subscription. To keep your access smooth, we recommend upgrading before the deadline. - Use coupon code `APIACCESS` to enjoy a `40%` discount. Thank you for being with us! - Added Server-Sent Events (SSE) streaming endpoints for real-time task updates: - [Text to 3D Stream API](/api/text-to-3d#stream-a-text-to-3d-task) - [Image to 3D Stream API](/api/image-to-3d#stream-an-image-to-3d-task) - [Remesh Stream API](/api/remesh#stream-a-remesh-task) - [Text to Texture Stream API](/api/text-to-texture#stream-a-text-to-texture-task) ### `Feb 6` - Added the `texture_prompt` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task) APIs, allowing users to guide the texture generation process with a text prompt. --- ## January 2025 ### `Jan 23` - Added endpoints for listing tasks to the [Text to 3D](/api/text-to-3d#list-text-to-3d-tasks), [Image to 3D](/api/image-to-3d#list-image-to-3d-tasks), [Remesh](/api/remesh#list-remesh-tasks) and [Text to Texture](/api/text-to-texture#list-text-to-texture-tasks) APIs. ### `Jan 14` - Deprecated the legacy Text to 3D and Image to 3D APIs powered by Meshy-3 AI models. ### `Jan 07` - Added the `symmetry_mode` parameter to the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task) and [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) APIs, allowing for configurable symmetry settings. --- ## December 2024 ### `Dec 19` - Added the [Remesh APIs](/api/remesh), which allow users to remesh and export existing 3D models generated by other Meshy APIs into various formats. - Updated the polycount limits for our APIs to a range of 100-300,000 for Premium users. ### `Dec 12` - Deprecated the `model_url` property in all response objects. - Separated legacy Meshy-3 API from the latest Meshy-4 API. ### `Dec 10` - Added an `enable_pbr` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Text to 3D Refine](/api/text-to-3d#create-a-text-to-3d-refine-task) APIs. - Added a `should_texture` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) API. - Deprecated the `pbr` option in `art_style` parameter for the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task) API when using the `meshy-4` AI model. - Deprecated the `low-poly` option in `art_style` parameter for the [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task) API. ### `Dec 5` - Added a [Get Balance API](/api/balance) to allow users to retrieve their credit balance. - Added a `should_remesh` parameter to the [Image to 3D](/api/image-to-3d#create-an-image-to-3d-task) and [Text to 3D Preview](/api/text-to-3d#create-a-text-to-3d-preview-task) APIs. ### `Dec 3` - External APIs now use the `/openapi` prefix. Legacy paths remain supported, but we recommend switching to the new paths. --- ## November 2024 ### `Nov 14` - The [Image to 3D API](/api/image-to-3d#create-an-image-to-3d-task) now supports base64-encoded images. --- --- # Text to 3D API Source: https://docs.meshy.ai/api/text-to-3d # Text to 3D API Text to 3D API is a feature that allows you to integrate Meshy's Text to 3D capabilities into your own application. In this section, you'll find all the information you need to get started with this API. Text to 3D uses a two-step workflow. First, create a **preview** task (`mode: "preview"`) to generate a 3D mesh without texture, so you can evaluate the shape. Then, pass the completed preview's task ID to a **refine** task (`mode: "refine"`) to apply texture to the mesh. Both steps share the same endpoint. --- ## POST /openapi/v2/text-to-3d -- Create a Text to 3D Preview Task This endpoint creates a Text to 3D preview task, which generates an untextured 3D mesh (geometry only) from a text prompt. This is the first step of the two-step workflow. Once the preview succeeds, use the returned task ID to [create a refine task](#create-a-text-to-3d-refine-task) for texturing. Refer to [The Text to 3D Task Object](#the-text-to-3d-task-object) for the full response schema. ### Parameters - `mode` · *string* · **required** This field should be set to "preview" when creating a preview task. - `prompt` · *string* · **required** Describe what kind of object the 3D model is. Maximum 600 characters. - `model_type` · *string* · default: `standard` Specify the type of 3D mesh generation. Available values: * `standard`: Regular high-detail 3D mesh generation. * `lowpoly`: Generates low-poly mesh optimized for cleaner polygons. > **Note:** When `lowpoly` is selected, `ai_model`, `topology`, `target_polycount`, `should_remesh` are ignored. - `ai_model` · *string* · default: `latest` ID of the model to use. Available values: `meshy-5`, `meshy-6`, `latest` (Meshy 6). - `should_remesh` · *boolean* · default: `false (meshy-6), true (others)` Controls whether to enable the remesh phase. When set to `false`, the API will directly return the highest-precision triangular mesh. **Only when `should_remesh` is set:** - `topology` · *string* · default: `triangle` Specify the topology of the generated model. Available values: * `quad`: Generate a quad-dominant mesh. * `triangle`: Generate a decimated triangle mesh. - `target_polycount` · *integer* · default: `30,000` Specify the target number of polygons in the generated model. The actual number of polygons may deviate from the target depending on the complexity of the geometry. The valid value range varies depending on the user tier: * 100 to 300,000 (inclusive) - `decimation_mode` · *integer* Enable adaptive decimation by setting a polycount level. When set, `target_polycount` is ignored. Available values: * `1`: Adaptive — ultra polycount. * `2`: Adaptive — high polycount. * `3`: Adaptive — medium polycount. * `4`: Adaptive — low polycount. - `symmetry_mode` · *string* · default: `auto` · **deprecated** Deprecated. This parameter no longer affects output. The `symmetry_mode` field controls symmetry behavior during the model generation process. The valid values are: * `off`: Disables symmetry. * `auto`: Automatically determines and applies symmetry based on input geometry. * `on`: Enforces symmetry during generation. - `pose_mode` · *string* · default: `""` Specify the pose mode for the generated model. Available values: * `a-pose`: Generate the model in an A pose. * `t-pose`: Generate the model in a T pose. * `""` (empty string): No specific pose applied. - `is_a_t_pose` · *boolean* · default: `false` · **deprecated** Use `pose_mode` instead. Whether to generate the model in an A/T pose. - `art_style` · *string* · default: `realistic` · **deprecated** Not supported by Meshy-6. Requests using Meshy-6 will ignore `art_style`, and some combinations may cause errors. Available values: `realistic`, `sculpture`. > **Note:** `enable_pbr` should be set to `false` when using Sculpture style, as Sculpture style generates its own set of PBR maps. - `moderation` · *boolean* · default: `false` When set to `true`, the input content will automatically be screened for potentially harmful content. If harmful content is detected, the task will not proceed to generation. The text from `prompt` will be screened. - `target_formats` · *string[]* Specifies which 3D file formats to include in the output. Only the requested formats will be generated and returned, which can reduce task completion time. When omitted, all supported formats are included. Available values: `glb`, `obj`, `fbx`, `stl`, `usdz`, `3mf` > **Note:** When omitted, all formats except `3mf` are generated. `3mf` is only included when explicitly specified. - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. - `auto_size` · *boolean* · default: `false` When set to `true`, the service uses AI vision to automatically estimate the real-world height of the object and resize the model accordingly. The origin will default to `bottom` unless `origin_at` is explicitly set. **Only when `auto_size` is set:** - `origin_at` · *string* · default: `bottom` Position of the origin when `auto_size` is enabled. Available values: `bottom`, `center`. ### Returns The `result` property of the response contains the task `id` of the newly created Text to 3D task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: A required parameter (e.g., `prompt`, `mode`) is missing. * **Invalid parameter**: `art_style` is not one of the allowed values. * **Prompt too long**: The `prompt` exceeds the character limit. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Simple preview with required params only curl https://api.meshy.ai/openapi/v2/text-to-3d \ -H 'Authorization: Bearer ${YOUR_API_KEY}' \ -H 'Content-Type: application/json' \ -d '{ "mode": "preview", "prompt": "a monster mask" }' # Preview with remesh and A-pose curl https://api.meshy.ai/openapi/v2/text-to-3d \ -H 'Authorization: Bearer ${YOUR_API_KEY}' \ -H 'Content-Type: application/json' \ -d '{ "mode": "preview", "prompt": "a futuristic robot warrior", "should_remesh": true, "target_polycount": 100000, "pose_mode": "a-pose", "target_formats": ["glb"] }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Simple preview with required params only const payload = { mode: 'preview', prompt: 'a monster mask', }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v2/text-to-3d', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // Preview with remesh and A-pose const advancedPayload = { mode: 'preview', prompt: 'a futuristic robot warrior', should_remesh: true, target_polycount: 100000, pose_mode: 'a-pose', target_formats: ['glb'], }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v2/text-to-3d', advancedPayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Simple preview with required params only payload = { "mode": "preview", "prompt": "a monster mask", } response = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # Preview with remesh and A-pose advanced_payload = { "mode": "preview", "prompt": "a futuristic robot warrior", "should_remesh": True, "target_polycount": 100000, "pose_mode": "a-pose", "target_formats": ["glb"], } response = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json=advanced_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## POST /openapi/v2/text-to-3d -- Create a Text to 3D Refine Task This endpoint creates a Text to 3D refine task, which applies texture to a completed preview mesh. You must provide the `preview_task_id` from a [successful preview task](#create-a-text-to-3d-preview-task). This is the second step of the two-step workflow. ### Parameters - `mode` · *string* · **required** This field should be set to "refine" when creating a refine task. - `preview_task_id` · *string* · **required** The corresponding preview task id. The status of the given preview task must be `SUCCEEDED`. - `enable_pbr` · *boolean* · default: `false` Generate PBR Maps (metallic, roughness, normal) in addition to the base color. An emission map is also included when `ai_model` is `meshy-6` or `latest`, except at `texture_resolution: 8k` (no emission map is produced). - `texture_resolution` · *string* · default: `2k` Base color texture resolution. One of `2k` (2048×2048), `4k` (4096×4096), or `8k` (8192×8192). Higher resolutions capture more surface detail. Only applies to the `refine` mode. > **Note:** `4k` and `8k` require `ai_model` `meshy-6` or `latest`. At `8k`, no emission map is produced and only triangle meshes are supported. - `hd_texture` · *boolean* · default: `false` · **deprecated** Use `texture_resolution` instead — equivalent to `texture_resolution: "4k"`. When both are set, `texture_resolution` takes precedence. - `texture_prompt` · *string* Provide an additional text prompt to guide the texturing process. Maximum 600 characters. - `texture_image_url` · *string* Provide a 2d image to guide the texturing process. We currently support `.jpg`, `.jpeg`, and `.png` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,` > **Note:** Image texturing may not work optimally if there are substantial geometry differences between the original asset and uploaded image. Only one of `texture_image_url` or `texture_prompt` may be used to guide the texturing process. If both parameters are provided, then `texture_prompt` will be used to texture the model by default. - `ai_model` · *string* · default: `latest` ID of the model to use for refining. Available values: `meshy-5`, `meshy-6`, `latest` (Meshy 6). - `moderation` · *boolean* · default: `false` When set to `true`, the input content will automatically be screened for potentially harmful content. If harmful content is detected, the task will not proceed to generation. Both the text from `texture_prompt` and the image from `texture_image_url` will be screened. - `remove_lighting` · *boolean* · default: `true` Removes highlights and shadows from the base color texture, producing a cleaner result that works better under custom lighting setups. > **Note:** Only supported when `ai_model` is `meshy-6` or `latest`. - `target_formats` · *string[]* Specifies which 3D file formats to include in the output. Only the requested formats will be generated and returned, which can reduce task completion time. When omitted, all supported formats are included. Available values: `glb`, `obj`, `fbx`, `stl`, `usdz`, `3mf` > **Note:** When omitted, all formats except `3mf` are generated. `3mf` is only included when explicitly specified. - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. - `auto_size` · *boolean* · default: `false` When set to `true`, the service uses AI vision to automatically estimate the real-world height of the object and resize the model accordingly. The origin will default to `bottom` unless `origin_at` is explicitly set. **Only when `auto_size` is set:** - `origin_at` · *string* · default: `bottom` Position of the origin when `auto_size` is enabled. Available values: `bottom`, `center`. ### Returns The `result` property of the response contains the task `id` of the newly created Text to 3D task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Invalid task ID**: The `preview_task_id` is invalid or does not exist. * **Task not ready**: The preview task has not succeeded yet. * **Model mismatch**: The preview task's AI model is incompatible with the requested refine model. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The preview task specified by `preview_task_id` was not found. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Basic refine task curl https://api.meshy.ai/openapi/v2/text-to-3d \ -H 'Authorization: Bearer ${YOUR_API_KEY}' \ -H 'Content-Type: application/json' \ -d '{ "mode": "refine", "preview_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "enable_pbr": true }' # Refine with auto-size and GLB format curl https://api.meshy.ai/openapi/v2/text-to-3d \ -H 'Authorization: Bearer ${YOUR_API_KEY}' \ -H 'Content-Type: application/json' \ -d '{ "mode": "refine", "preview_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["glb"], "auto_size": true }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Basic refine task const payload = { mode: 'refine', preview_task_id: '018a210d-8ba4-705c-b111-1f1776f7f578', enable_pbr: true, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v2/text-to-3d', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // Refine with auto-size and GLB format const advancedPayload = { mode: 'refine', preview_task_id: '018a210d-8ba4-705c-b111-1f1776f7f578', target_formats: ['glb'], auto_size: true, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v2/text-to-3d', advancedPayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Basic refine task payload = { "mode": "refine", "preview_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "enable_pbr": True, } response = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # Refine with auto-size and GLB format advanced_payload = { "mode": "refine", "preview_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["glb"], "auto_size": True, } response = requests.post( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, json=advanced_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## GET /openapi/v2/text-to-3d/:id -- Retrieve a Text to 3D Task This endpoint allows you to retrieve a Text to 3D task given a valid task `id`. Refer to [The Text to 3D Task Object](#the-text-to-3d-task-object) to see which properties are included with Text to 3D task object. This endpoint works for both preview and refine tasks. ### Parameters - `id` · *path* Unique identifier for the Text to 3D task to retrieve. ### Returns The response contains the Text to 3D task object. Check [The Text to 3D Task Object](#the-text-to-3d-task-object) section for details. ### Examples
Mode Sample Model
Preview Preview model
Refine Refined model
**cURL** ```bash curl https://api.meshy.ai/openapi/v2/text-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v2/text-to-3d/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v2/text-to-3d/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-3d-preview", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.mtl?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "prompt": "a monster mask", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 20 } ``` --- ## DELETE /openapi/v2/text-to-3d/:id -- Delete a Text to 3D Task This endpoint permanently deletes a Text to 3D task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the Text to 3D task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v2/text-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v2/text-to-3d/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v2/text-to-3d/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v2/text-to-3d -- List Text to 3D Tasks This endpoint allows you to retrieve a list of Text to 3D tasks. ### Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Text to 3D Task Objects](#the-text-to-3d-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v2/text-to-3d?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v2/text-to-3d?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v2/text-to-3d", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-3d-preview", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.mtl?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "prompt": "a monster mask", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 20 } ] ``` --- ## GET /openapi/v2/text-to-3d/:id/stream -- Stream a Text to 3D Task This endpoint streams real-time updates for a Text to 3D task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Text to 3D task to stream. ### Returns Returns a stream of [The Text to 3D Task Objects](#the-text-to-3d-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v2/text-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v2/text-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v2/text-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 0, "status": "PENDING" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 50, "status": "IN_PROGRESS" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-3d-preview", "progress": 100, "status": "SUCCEEDED", "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***" }, "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 20 } ``` --- ## The Text to 3D Task Object The Text to 3D Task object is a work unit that Meshy keeps track of to generate a 3D model from a **text** input. There are two stages of the Text to 3D API, `preview` and `refine`. Preview stage is for generating a mesh-only 3D model, and refine stage is for generating a textured 3D model based on the preview stage's result. The object has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the Text to 3D task. Possible values are `text-to-3d-preview` for preview stage tasks and `text-to-3d-refine` for refine stage tasks. - `model_urls` · *object* Downloadable URL to the textured 3D model file generated by Meshy. The property for a format will be omitted if the format is not generated instead of returning an empty string. - `glb` · *string* Downloadable URL to the GLB file. - `fbx` · *string* Downloadable URL to the FBX file. - `usdz` · *string* Downloadable URL to the USDZ file. - `obj` · *string* Downloadable URL to the OBJ file. - `mtl` · *string* Downloadable URL to the MTL file. - `stl` · *string* Downloadable URL to the STL file. - `3mf` · *string* Downloadable URL to the 3MF file. Only present when `3mf` was requested via `target_formats`. - `prompt` · *string* This is unmodified `prompt` that was used to create the task. - `negative_prompt` · *string* · **deprecated** Maintained for backward compatibility. This field has no functional impact on generated models. - `art_style` · *string* · **deprecated** The unmodified `art_style` that was used to create the preview task. Not supported by Meshy-6. - `texture_richness` · *string* · **deprecated** Maintained for backward compatibility. This field has no functional impact on generated models. - `texture_prompt` · *string* Additional text prompt provided to guide the texturing process during the refine stage. - `texture_image_url` · *string* Downloadable URL to the texture image that was used to guide the texturing process. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. - `alpha_thumbnail_url` · *string* Downloadable URL to a transparent-background (RGBA) version of `thumbnail_url`. Only present when the task was created with `alpha_thumbnail: true` and the transparent preview was successfully rendered; otherwise this field is omitted. - `video_url` · *string* · **deprecated** Downloadable URL to the preview video. Will be removed in a future release. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `texture_urls` · *array* An array of texture URL objects that are generated from the task. Normally this only contains **one** texture URL object. Each texture URL has the following properties: - `base_color` · *string* Downloadable URL to the base color map image. - `metallic` · *string* Downloadable URL to the metallic map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `normal` · *string* Downloadable URL to the normal map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `roughness` · *string* Downloadable URL to the roughness map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `emission` · *string* Downloadable URL to the emission map image. > **Note:** If the task is created with `enable_pbr: false`, or `ai_model` is `meshy-5`, this property will be omitted. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Text to 3D Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-3d-preview", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.mtl?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***" }, "prompt": "a monster mask", "texture_prompt": "green slimy skin with scales and warts", "texture_image_url": "", "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 20 } ``` --- # Image to 3D API Source: https://docs.meshy.ai/api/image-to-3d # Image to 3D API Image to 3D API is a feature that allows you to integrate Meshy's Image to 3D capabilities into your own application. In this section, you'll find all the information you need to get started with this API. --- ## POST /openapi/v1/image-to-3d -- Create an Image to 3D Task This endpoint allows you to create a new Image to 3D task. Refer to [The Image to 3D Task Object](#the-image-to-3d-task-object) to see which properties are included with Image to 3D task object. ### Parameters > **Note:** Only one of `input_task_id` or `image_url` is **required**. If both are provided, `input_task_id` takes priority. - `input_task_id` · *string* · **required** The ID of a completed image-generation task whose output should be used as the input image. This task must be one of the following tasks: Text to Image or Image to Image. In addition, it must have been run via the API, have a status of `SUCCEEDED`, and produce exactly one image. - `image_url` · *string* · **required** Provide an image for Meshy to use in model creation. We currently support `.jpg`, `.jpeg`, and `.png` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `model_type` · *string* · default: `standard` Specify the type of 3D mesh generation. Available values: * `standard`: Regular high-detail 3D mesh generation. * `smart-topology`: Choose a Smart Topology model with `ai_model` (`meshy-t1` or `meshy-t2`). * `lowpoly` (deprecated): Generates low-poly mesh optimized for cleaner polygons. We recommend using `smart-topology` instead. > **Note:** When `smart-topology` is selected, `topology`, `should_remesh`, and `save_pre_remeshed_model` are ignored. > **Note:** When `lowpoly` is selected, `ai_model`, `topology`, `target_polycount`, `should_remesh`, and `save_pre_remeshed_model` are ignored. - `ai_model` · *string* · default: `latest` ID of the model to use. The available values depend on `model_type`. Standard generation (`model_type: standard`): * `meshy-5`, `meshy-6`, `latest` (Meshy 6) Smart Topology generation (`model_type: smart-topology`): * `meshy-t2` (default, recommended): the Smart Topology model — cleaner topology, natively separated parts, triangle output, and a face count you can set with `target_polycount`. * `meshy-t1`: the old low-poly model; does not support setting a face count with `target_polycount`. - `should_texture` · *boolean* · default: `true` Determines if textures are generated. Setting it to `false` skips the texture phase, providing a mesh without textures. **Only when `should_texture` is set:** - `enable_pbr` · *boolean* · default: `false` Generate PBR Maps (metallic, roughness, normal) in addition to the base color. An emission map is also included when `ai_model` is `meshy-6` or `latest`, except at `texture_resolution: 8k` (no emission map is produced). - `texture_resolution` · *string* · default: `2k` Base color texture resolution. One of `2k` (2048×2048), `4k` (4096×4096), or `8k` (8192×8192). Higher resolutions capture more surface detail. > **Note:** `4k` and `8k` are not available with `ai_model: meshy-5`. At `8k`, no emission map is produced and `topology: quad` is not supported. - `hd_texture` · *boolean* · default: `false` · **deprecated** Use `texture_resolution` instead — equivalent to `texture_resolution: "4k"`. When both are set, `texture_resolution` takes precedence. - `texture_prompt` · *string* Provide a text prompt to guide the texturing process. Maximum 600 characters. - `texture_image_url` · *string* Provide a 2d image to guide the texturing process. We currently support `.jpg`, `.jpeg`, and `.png` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,` > **Note:** Image texturing may not work optimally if there are substantial geometry differences between the original asset and uploaded image. Only one of `texture_image_url` or `texture_prompt` may be used to guide the texturing process. If both parameters are provided, then `texture_prompt` will be used to texture the model by default. Texturing via either text or image will cost 10 credits per task. - `should_remesh` · *boolean* · default: `false (meshy-6), true (others)` Controls whether to enable the remesh phase. When set to `false`, the API returns the highest-precision triangular mesh. **Only when `should_remesh` is set:** - `topology` · *string* · default: `triangle` Specify the topology of the generated model. Available values: * `quad`: Generate a quad-dominant mesh. * `triangle`: Generate a decimated triangle mesh. - `decimation_mode` · *integer* Enable adaptive decimation by setting a polycount level. When set, `target_polycount` is ignored. Available values: * `1`: Adaptive — ultra polycount. * `2`: Adaptive — high polycount. * `3`: Adaptive — medium polycount. * `4`: Adaptive — low polycount. - `save_pre_remeshed_model` · *boolean* · default: `false` When set to `true`, Meshy also stores an extra GLB file before the remesh phase completes. - `target_polycount` · *integer* Target number of polygons (faces) in the output. The actual count may deviate from the target depending on the geometry. `target_polycount` takes effect in two independent cases: * **Remesh** — with `should_remesh: true` on a `standard` model. The mesh is remeshed (decimated) to approximately this count. Range 100 to 300,000, default 30,000. If `decimation_mode` is set, it takes priority and `target_polycount` is ignored. * **Smart Topology** — with `model_type: smart-topology` and `ai_model: meshy-t2`. The model is generated directly at this face count; no remesh runs and `should_remesh` is not required. Range 100 to 15,000, default 4,000. - `symmetry_mode` · *string* · default: `auto` · **deprecated** Deprecated. This parameter no longer affects output. The `symmetry_mode` field controls symmetry behavior during the model generation process. The valid values are: * `off`: Disables symmetry. * `auto`: Automatically determines and applies symmetry based on input geometry. * `on`: Enforces symmetry during generation. - `pose_mode` · *string* · default: `""` Specify the pose mode for the generated model. Available values: * `a-pose`: Generate the model in an A pose. * `t-pose`: Generate the model in a T pose. * `""` (empty string): No specific pose applied. - `is_a_t_pose` · *boolean* · default: `false` · **deprecated** Use `pose_mode` instead. Whether to generate the model in an A/T pose. - `image_enhancement` · *boolean* · default: `true` Optimizes the input image for better results. Set to `false` to preserve the exact appearance of the input image without any style processing. > **Note:** Only supported when `ai_model` is `meshy-6` or `latest`. - `remove_lighting` · *boolean* · default: `true` Removes highlights and shadows from the base color texture, producing a cleaner result that works better under custom lighting setups. > **Note:** Only supported when `ai_model` is `meshy-6` or `latest`. - `moderation` · *boolean* · default: `false` When set to `true`, the input content will automatically be screened for potentially harmful content. If harmful content is detected, the task will not proceed to generation. The content from the `image_url`, `texture_image_url`, and `texture_prompt` inputs will be screened. - `target_formats` · *string[]* Specifies which 3D file formats to include in the output. Only the requested formats will be generated and returned, which can reduce task completion time. When omitted, all supported formats are included. Available values: `glb`, `obj`, `fbx`, `stl`, `usdz`, `3mf` > **Note:** When omitted, all formats except `3mf` are generated. `3mf` is only included when explicitly specified. - `auto_size` · *boolean* · default: `false` When set to `true`, the service uses AI vision to automatically estimate the real-world height of the object and resize the model accordingly. The origin will default to `bottom` unless `origin_at` is explicitly set. - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. - `multi_view_thumbnails` · *boolean* · default: `false` When set to `true`, the task additionally renders four cardinal-view thumbnails (front, right, back, left) and returns them under `thumbnail_urls` on the GET response. The existing `thumbnail_url` field is unchanged and continues to point at the front view, so existing clients are unaffected. > **Note:** Adds approximately 3 seconds to task latency. **Only when `auto_size` is set:** - `origin_at` · *string* · default: `bottom` Position of the origin when `auto_size` is enabled. Available values: `bottom`, `center`. ### Returns The `result` property of the response contains the task `id` of the newly created Image to 3D task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `image_url` or `input_task_id` must be provided. * **Invalid input task**: The `input_task_id` must refer to a `SUCCEEDED` Text to Image or Image to Image task that produces exactly one image. * **Invalid image format**: The provided `image_url` is not a supported format (.jpg, .jpeg, .png). * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Invalid parameter combination**: `enable_pbr` is only supported when `should_texture` is true. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Simple request with required params curl https://api.meshy.ai/openapi/v1/image-to-3d \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' # With remesh, PBR, and A-pose curl https://api.meshy.ai/openapi/v1/image-to-3d \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "", "enable_pbr": true, "should_remesh": true, "target_polycount": 100000, "should_texture": true, "pose_mode": "a-pose", "target_formats": ["glb"] }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Simple request with required params const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/image-to-3d', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // With remesh, PBR, and A-pose const advancedPayload = { image_url: "", enable_pbr: true, should_remesh: true, target_polycount: 100000, should_texture: true, pose_mode: "a-pose", target_formats: ["glb"], }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/image-to-3d', advancedPayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Simple request with required params payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/v1/image-to-3d", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # With remesh, PBR, and A-pose advanced_payload = { "image_url": "", "enable_pbr": True, "should_remesh": True, "target_polycount": 100000, "should_texture": True, "pose_mode": "a-pose", "target_formats": ["glb"], } response = requests.post( "https://api.meshy.ai/openapi/v1/image-to-3d", headers=headers, json=advanced_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## GET /openapi/v1/image-to-3d/:id -- Retrieve an Image to 3D Task This endpoint allows you to retrieve an Image to 3D task given a valid task `id`. Refer to [The Image to 3D Task Object](#the-image-to-3d-task-object) to see which properties are included with Image to 3D task object. ### Parameters - `id` · *path* Unique identifier for the Image to 3D task to retrieve. ### Returns The response contains the Image to 3D task object. Check [The Image to 3D Task Object](#the-image-to-3d-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/image-to-3d/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/image-to-3d/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ``` --- ## DELETE /openapi/v1/image-to-3d/:id -- Delete an Image to 3D Task This endpoint permanently deletes an Image to 3D task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the Image to 3D task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/image-to-3d/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/image-to-3d/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/image-to-3d -- List Image to 3D Tasks This endpoint allows you to retrieve a list of Image to 3D tasks. ### Parameters #### Optional attributes - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Image to 3D Task Objects](#the-image-to-3d-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/image-to-3d?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/image-to-3d?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/image-to-3d", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ] ``` --- ## GET /openapi/v1/image-to-3d/:id/stream -- Stream an Image to 3D Task This endpoint streams real-time updates for an Image to 3D task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Image to 3D task to stream. ### Returns Returns a stream of [The Image to 3D Task Objects](#the-image-to-3d-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 0, "status": "PENDING" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ``` --- ## The Image to 3D Task Object The Image to 3D Task object is a work unit that Meshy keeps track of to generate a 3D model from an **image** input. The object has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the Image to 3D task. The value is `image-to-3d`. - `model_urls` · *object* Downloadable URL to the textured 3D model file generated by Meshy. The property for a format will be omitted if the format is not generated instead of returning an empty string. - `glb` · *string* Downloadable URL to the GLB file. - `fbx` · *string* Downloadable URL to the FBX file. - `obj` · *string* Downloadable URL to the OBJ file. - `usdz` · *string* Downloadable URL to the USDZ file. - `mtl` · *string* Downloadable URL to the MTL file, returned alongside OBJ exports when textures are present. - `stl` · *string* Downloadable URL to the STL file. - `3mf` · *string* Downloadable URL to the 3MF file. Only present when `3mf` was requested via `target_formats`. - `pre_remeshed_glb` · *string* Downloadable URL to the original GLB output before remeshing. > **Note:** Available only when the task was created with both `should_remesh: true` and `save_pre_remeshed_model: true`. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. Equivalent to `thumbnail_urls.front` when present, kept for backwards compatibility. - `alpha_thumbnail_url` · *string* Downloadable URL to a transparent-background (RGBA) version of `thumbnail_url`. Only present when the task was created with `alpha_thumbnail: true` and the transparent preview was successfully rendered; otherwise this field is omitted. - `thumbnail_urls` · *object* Downloadable URLs for four cardinal-view thumbnails of the generated 3D model. Each value is a signed URL to a 512×512 PNG rendered with the same materials and lighting as `thumbnail_url`. Useful for previewing the model from multiple angles in batch pipelines without downloading the GLB. > **Note:** Only present when the task was created with `multi_view_thumbnails: true` and has reached `SUCCEEDED`. Older tasks and tasks created without the opt-in will not include this field. - `front` · *string* Front view, 0° rotation around the vertical axis (matches `thumbnail_url`). - `right` · *string* Right view, 90° rotation. - `back` · *string* Back view, 180° rotation. - `left` · *string* Left view, 270° rotation. - `texture_prompt` · *string* The text prompt that was used to guide the texturing process. - `texture_image_url` · *string* Downloadable URL to the texture image that was used to guide the texturing process. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `texture_urls` · *array* An array of texture URL objects that are generated from the task. Normally this only contains **one** texture URL object. Each texture URL has the following properties: - `base_color` · *string* Downloadable URL to the base color map image. - `metallic` · *string* Downloadable URL to the metallic map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `normal` · *string* Downloadable URL to the normal map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `roughness` · *string* Downloadable URL to the roughness map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `emission` · *string* Downloadable URL to the emission map image. > **Note:** If the task is created with `enable_pbr: false`, or `ai_model` is `meshy-5`, this property will be omitted. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Image to 3D Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "texture_image_url": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ``` --- # Multi-Image to 3D API Source: https://docs.meshy.ai/api/multi-image-to-3d # Multi-Image to 3D API Multi-Image to 3D API is a feature that allows you to integrate Meshy's Multi-Image to 3D capabilities into your own application. In this section, you'll find all the information you need to get started with this API. --- ## POST /openapi/v1/multi-image-to-3d -- Create a Multi-Image to 3D Task This endpoint allows you to create a new Multi-Image to 3D task. Refer to [The Multi-Image to 3D Task Object](#the-multi-image-to-3d-task-object) to see which properties are included with Multi-Image to 3D task object. ### Parameters > **Note:** Only one of `input_task_id` or `image_urls` is **required**. If both are provided, `input_task_id` takes priority. - `input_task_id` · *string* · **required** The ID of a completed image-generation task whose output (1-4 images) should be used as the input. This task must be one of the following tasks: Text to Image, Image to Image, Text to Image Multi-View, or Image to Image Multi-View. In addition, it must have been run via the API and have a status of `SUCCEEDED`. - `image_urls` · *array* · **required** Provide 1 to 4 images for Meshy to use in model creation. We currently support `.jpg`, `.jpeg`, and `.png` formats. All images should depict the same object from different angles for best results. There are two ways to provide each image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `ai_model` · *string* · default: `latest` ID of the model to use. Available values: `meshy-5`, `meshy-6`, `latest` (Meshy 6). - `should_texture` · *boolean* · default: `true` Determines if textures are generated. Setting it to `false` skips the texture phase, providing a mesh without textures. **Only when `should_texture` is set:** - `enable_pbr` · *boolean* · default: `false` Generate PBR Maps (metallic, roughness, normal) in addition to the base color. An emission map is also included when `ai_model` is `meshy-6` or `latest`, except at `texture_resolution: 8k` (no emission map is produced). - `texture_resolution` · *string* · default: `2k` Base color texture resolution. One of `2k` (2048×2048), `4k` (4096×4096), or `8k` (8192×8192). Higher resolutions capture more surface detail. > **Note:** `4k` and `8k` require `ai_model` `meshy-6` or `latest`. At `8k`, no emission map is produced and only triangle meshes are supported. - `hd_texture` · *boolean* · default: `false` · **deprecated** Use `texture_resolution` instead — equivalent to `texture_resolution: "4k"`. When both are set, `texture_resolution` takes precedence. - `texture_prompt` · *string* Provide a text prompt to guide the texturing process. Maximum 600 characters. - `texture_image_url` · *string* Provide a 2d image to guide the texturing process. We currently support `.jpg`, `.jpeg`, and `.png` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,` > **Note:** Image texturing may not work optimally if there are substantial geometry differences between the original asset and uploaded image. Only one of `texture_image_url` or `texture_prompt` may be used to guide the texturing process. If both parameters are provided, then `texture_prompt` will be used to texture the model by default. - `should_remesh` · *boolean* · default: `false (meshy-6), true (others)` Controls whether to enable the remesh phase. When set to `false`, the API returns the highest-precision triangular mesh. **Only when `should_remesh` is set:** - `topology` · *string* · default: `triangle` Specify the topology of the generated model. Available values: * `quad`: Generate a quad-dominant mesh. * `triangle`: Generate a decimated triangle mesh. - `target_polycount` · *integer* · default: `30,000` Specify the target number of polygons in the generated model. The actual number of polygons may deviate from the target depending on the complexity of the geometry. The valid value range varies depending on the user tier: * 100 to 300,000 (inclusive) - `decimation_mode` · *integer* Enable adaptive decimation by setting a polycount level. When set, `target_polycount` is ignored. Available values: * `1`: Adaptive — ultra polycount. * `2`: Adaptive — high polycount. * `3`: Adaptive — medium polycount. * `4`: Adaptive — low polycount. - `save_pre_remeshed_model` · *boolean* · default: `false` When set to `true`, Meshy also stores an extra GLB file before the remesh phase completes. - `symmetry_mode` · *string* · default: `auto` · **deprecated** Deprecated. This parameter no longer affects output. The `symmetry_mode` field controls symmetry behavior during the model generation process. The valid values are: * `off`: Disables symmetry. * `auto`: Automatically determines and applies symmetry based on input geometry. * `on`: Enforces symmetry during generation. - `pose_mode` · *string* · default: `""` Specify the pose mode for the generated model. Available values: * `a-pose`: Generate the model in an A pose. * `t-pose`: Generate the model in a T pose. * `""` (empty string): No specific pose applied. - `is_a_t_pose` · *boolean* · default: `false` · **deprecated** Use `pose_mode` instead. Whether to generate the model in an A/T pose. - `image_enhancement` · *boolean* · default: `true` Optimizes the input images for better results. Set to `false` to preserve the exact appearance of the input images without any style processing. > **Note:** Only supported when `ai_model` is `meshy-6` or `latest`. - `remove_lighting` · *boolean* · default: `true` Removes highlights and shadows from the base color texture, producing a cleaner result that works better under custom lighting setups. > **Note:** Only supported when `ai_model` is `meshy-6` or `latest`. - `moderation` · *boolean* · default: `false` When set to `true`, the input content will automatically be screened for potentially harmful content. If harmful content is detected, the task will not proceed to generation. Each image from `image_urls` and the text from `texture_prompt` will be screened. - `target_formats` · *string[]* Specifies which 3D file formats to include in the output. Only the requested formats will be generated and returned, which can reduce task completion time. Available values: `glb`, `obj`, `fbx`, `stl`, `usdz`, `3mf` > **Note:** When omitted, all formats except `3mf` are generated. `3mf` is only included when explicitly specified. - `auto_size` · *boolean* · default: `false` When set to `true`, the service uses AI vision to automatically estimate the real-world height of the object and resize the model accordingly. The origin will default to `bottom` unless `origin_at` is explicitly set. - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. - `multi_view_thumbnails` · *boolean* · default: `false` When set to `true`, the task additionally renders four cardinal-view thumbnails (front, right, back, left) and returns them under `thumbnail_urls` on the GET response. The existing `thumbnail_url` field is unchanged and continues to point at the front view, so existing clients are unaffected. > **Note:** Adds approximately 3 seconds to task latency. **Only when `auto_size` is set:** - `origin_at` · *string* · default: `bottom` Position of the origin when `auto_size` is enabled. Available values: `bottom`, `center`. ### Returns The `result` property of the response contains the task `id` of the newly created Multi-Image to 3D task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `image_urls` or `input_task_id` must be provided. * **Invalid input task**: The `input_task_id` must refer to a `SUCCEEDED` Text to Image, Image to Image, or multi-view variant task. * **Invalid image count**: `image_urls` must contain between 1 and 4 images. * **Invalid image format**: One or more images in `image_urls` are not supported formats. * **Unreachable URL**: One or more `image_urls` could not be downloaded. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Simple request curl https://api.meshy.ai/openapi/v1/multi-image-to-3d \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_urls": [ "", "" ] }' # With PBR texturing and GLB format curl https://api.meshy.ai/openapi/v1/multi-image-to-3d \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_urls": [ "", "" ], "should_texture": true, "enable_pbr": true, "target_formats": ["glb"] }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Simple request const payload = { image_urls: [ "", "" ], }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/multi-image-to-3d', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // With PBR texturing and GLB format const advancedPayload = { image_urls: [ "", "" ], should_texture: true, enable_pbr: true, target_formats: ["glb"], }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/multi-image-to-3d', advancedPayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests # Simple request payload = { "image_urls": [ "", "" ], } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Simple request response = requests.post( "https://api.meshy.ai/openapi/v1/multi-image-to-3d", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # With PBR texturing and GLB format advanced_payload = { "image_urls": [ "", "" ], "should_texture": True, "enable_pbr": True, "target_formats": ["glb"], } response = requests.post( "https://api.meshy.ai/openapi/v1/multi-image-to-3d", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## GET /openapi/v1/multi-image-to-3d/:id -- Retrieve a Multi-Image to 3D Task This endpoint allows you to retrieve a Multi-Image to 3D task given a valid task `id`. Refer to [The Multi-Image to 3D Task Object](#the-multi-image-to-3d-task-object) to see which properties are included with Multi-Image to 3D task object. ### Parameters - `id` · *path* Unique identifier for the Multi-Image to 3D task to retrieve. ### Returns The response contains the Multi-Image to 3D task object. Check [The Multi-Image to 3D Task Object](#the-multi-image-to-3d-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/multi-image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/multi-image-to-3d/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/multi-image-to-3d/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "multi-image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ``` --- ## DELETE /openapi/v1/multi-image-to-3d/:id -- Delete a Multi-Image to 3D Task This endpoint permanently deletes a Multi-Image to 3D task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the Multi-Image to 3D task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/multi-image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/multi-image-to-3d/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/multi-image-to-3d/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/multi-image-to-3d -- List Multi-Image to 3D Tasks This endpoint allows you to retrieve a list of Multi-Image to 3D tasks. ### Parameters #### Optional attributes - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Multi-Image to 3D Task Objects](#the-multi-image-to-3d-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/multi-image-to-3d?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/multi-image-to-3d?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/multi-image-to-3d", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "multi-image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ] ``` --- ## GET /openapi/v1/multi-image-to-3d/:id/stream -- Stream a Multi-Image to 3D Task This endpoint streams real-time updates for a Multi-Image to 3D task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Multi-Image to 3D task to stream. ### Returns Returns a stream of [The Multi-Image to 3D Task Objects](#the-multi-image-to-3d-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/multi-image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/multi-image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/multi-image-to-3d/018a210d-8ba4-705c-b111-1f1776f7f578/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```text // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 0, "status": "PENDING" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "multi-image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30 } ``` --- ## The Multi-Image to 3D Task Object The Multi-Image to 3D Task object is a work unit that Meshy keeps track of to generate a 3d model from multiple images (between 1 to 4 inclusive). The images should be of the same object, ideally from different views or angles. The object has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the Multi-Image to 3D task. The value is `multi-image-to-3d`. - `model_urls` · *object* Downloadable URL to the textured 3D model file generated by Meshy. The property for a format will be omitted if the format is not generated instead of returning an empty string. - `glb` · *string* Downloadable URL to the GLB file. - `fbx` · *string* Downloadable URL to the FBX file. - `obj` · *string* Downloadable URL to the OBJ file. - `usdz` · *string* Downloadable URL to the USDZ file. - `mtl` · *string* Downloadable URL to the MTL file, returned alongside OBJ exports when textures are present. - `stl` · *string* Downloadable URL to the STL file. - `3mf` · *string* Downloadable URL to the 3MF file. Only present when `3mf` was requested via `target_formats`. - `pre_remeshed_glb` · *string* Downloadable URL to the original GLB output before remeshing. > **Note:** Available only when the task was created with both `should_remesh: true` and `save_pre_remeshed_model: true`. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. Equivalent to `thumbnail_urls.front` when present, kept for backwards compatibility. - `alpha_thumbnail_url` · *string* Downloadable URL to a transparent-background (RGBA) version of `thumbnail_url`. Only present when the task was created with `alpha_thumbnail: true` and the transparent preview was successfully rendered; otherwise this field is omitted. - `thumbnail_urls` · *object* Downloadable URLs for four cardinal-view thumbnails of the generated 3D model. Each value is a signed URL to a 512×512 PNG rendered with the same materials and lighting as `thumbnail_url`. Useful for previewing the model from multiple angles in batch pipelines without downloading the GLB. > **Note:** Only present when the task was created with `multi_view_thumbnails: true` and has reached `SUCCEEDED`. Older tasks and tasks created without the opt-in will not include this field. - `front` · *string* Front view, 0° rotation around the vertical axis (matches `thumbnail_url`). - `right` · *string* Right view, 90° rotation. - `back` · *string* Back view, 180° rotation. - `left` · *string* Left view, 270° rotation. - `texture_prompt` · *string* The text prompt that was used to guide the texturing process. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `texture_urls` · *array* An array of texture URL objects that are generated from the task. Normally this only contains **one** texture URL object. Each texture URL has the following properties: - `base_color` · *string* Downloadable URL to the base color map image. - `metallic` · *string* Downloadable URL to the metallic map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `normal` · *string* Downloadable URL to the normal map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `roughness` · *string* Downloadable URL to the roughness map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `emission` · *string* Downloadable URL to the emission map image. > **Note:** If the task is created with `enable_pbr: false`, or `ai_model` is `meshy-5`, this property will be omitted. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Multi-Image to 3D Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "multi-image-to-3d", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***", "pre_remeshed_glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/pre_remeshed_model.glb?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "thumbnail_urls": { "front": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_front.png?Expires=***", "right": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_right.png?Expires=***", "back": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_back.png?Expires=***", "left": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview_left.png?Expires=***" }, "texture_prompt": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 30, } ``` --- # Remesh API Source: https://docs.meshy.ai/api/remesh # Remesh API The Remesh API allows you to remesh and export existing 3D models generated by other Meshy APIs (like Image to 3D or Text to 3D) into various formats. This section provides details on how to use the Remesh API. --- ## POST /openapi/v1/remesh -- Create a Remesh Task This endpoint creates a new remesh task. > **Note:** For format conversion and resizing, use the dedicated [Convert API](/api/convert) and [Resize API](/api/resize). The deprecated parameters below will continue to work, but we recommend the new endpoints for new integrations. ### Parameters > **Note:** Only 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 the completed Image to 3D or Text to 3D task you wish to remesh. This task must be one of the following tasks: Text to 3D Preview, Text to 3D Refine, Image to 3D or Retexture. In addition, it must have a status of `SUCCEEDED`. - `model_url` · *string* · **required** Please provide a 3D model for Meshy to remesh via a publicly accessible URL or data URI. Supported formats: `.glb`, `.gltf`, `.obj`, `.fbx`, `.stl`. For Data URIs, use the MIME type: `application/octet-stream`. - `target_formats` · *string[]* · default: `["glb"]` A list of target formats for the remeshed model. When omitted, only GLB is generated. Available values: `glb`, `fbx`, `obj`, `usdz`, `blend`, `stl`, `3mf`. - `topology` · *string* · default: `triangle` Specify the topology of the generated model. Available values: * `quad`: Generate a quad-dominant mesh. * `triangle`: Generate a decimated triangle mesh. - `target_polycount` · *integer* · default: `30,000` Specify the target number of polygons in the generated model. The actual number of polygons may deviate from the target depending on the complexity of the geometry. The valid value range varies depending on the user tier: * 100 to 300,000 (inclusive) - `decimation_mode` · *integer* Enable adaptive decimation by setting a polycount level. When set, `target_polycount` is ignored. Available values: * `1`: Adaptive — ultra polycount. * `2`: Adaptive — high polycount. * `3`: Adaptive — medium polycount. * `4`: Adaptive — low polycount. - `resize_height` · *number* · default: `0` · **deprecated** Resize the model to a certain height measured in meters. We recommend using the dedicated [Resize API](/api/resize) instead. > **Note:** `auto_size`, `resize_height`, and `resize_longest_side` are mutually exclusive. - `resize_longest_side` · *number* · default: `0` · **deprecated** Resize the model so the longest bounding-box dimension equals the specified value in meters. We recommend using the dedicated [Resize API](/api/resize) instead. > **Note:** `auto_size`, `resize_height`, and `resize_longest_side` are mutually exclusive. - `auto_size` · *boolean* · default: `false` · **deprecated** When set to `true`, the service uses AI vision to automatically estimate the real-world height of the object and resize the model accordingly. We recommend using the dedicated [Resize API](/api/resize) instead. > **Note:** `auto_size`, `resize_height`, and `resize_longest_side` are mutually exclusive. **Only when `auto_size` is set:** - `origin_at` · *string* · default: `bottom` · **deprecated** Position of the origin. We recommend using the dedicated [Resize API](/api/resize) instead. Available values: `bottom`, `center`. - `convert_format_only` · *boolean* · **deprecated** If `true`, the service will only change the format of the input model file, ignoring other inputs like `topology`, `resize_height`, and `target_polycount`. We recommend using the dedicated [Convert API](/api/convert) instead. > **Note:** `target_formats` must be provided if `convert_format_only` is set to `true`. - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. ### Returns The `result` property of the response contains the `id` of the newly created remesh task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `model_url` or `input_task_id` must be provided. * **Invalid input task**: The `input_task_id` must refer to a successful task from a supported model. * **Invalid model format**: The `model_url` points to a file with an unsupported extension. * **Unreachable URL**: The `model_url` could not be downloaded. * **Invalid topology**: The `topology` parameter is invalid. * **Mutually exclusive parameters**: `auto_size` and `resize_height` cannot both be set. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Basic remesh with custom formats and resize curl https://api.meshy.ai/openapi/v1/remesh \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["glb", "fbx"], "topology": "quad", "target_polycount": 50000, "resize_height": 1.0, "origin_at": "bottom" }' # Quad remesh with auto-size curl https://api.meshy.ai/openapi/v1/remesh \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["glb", "fbx"], "topology": "quad", "target_polycount": 50000, "auto_size": true }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Basic remesh with custom formats and resize const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", target_formats: ["glb", "fbx"], topology: "quad", target_polycount: 50000, resize_height: 1.0, origin_at: "bottom" }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/remesh', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // Quad remesh with auto-size const autoSizePayload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", target_formats: ["glb", "fbx"], topology: "quad", target_polycount: 50000, auto_size: true }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/remesh', autoSizePayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Basic remesh with custom formats and resize payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["glb", "fbx"], "topology": "quad", "target_polycount": 50000, "resize_height": 1.0, "origin_at": "bottom" } response = requests.post( "https://api.meshy.ai/openapi/v1/remesh", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # Quad remesh with auto-size auto_size_payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["glb", "fbx"], "topology": "quad", "target_polycount": 50000, "auto_size": True } response = requests.post( "https://api.meshy.ai/openapi/v1/remesh", headers=headers, json=auto_size_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "0193bfc5-ee4f-73f8-8525-44b398884ce9" } ``` --- ## GET /openapi/v1/remesh/:id -- Retrieve a Remesh Task This endpoint retrieves a remesh task by its ID. ### Parameters - `id` · *path* The ID of the remesh task to retrieve. ### Returns The Remesh Task object. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/remesh/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/remesh/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/remesh/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "remesh", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.usdz?Expires=***", "blend": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.blend?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.stl?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, } ``` --- ## DELETE /openapi/v1/remesh/:id -- Delete a Remesh Task This endpoint permanently deletes a remesh task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the remesh task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/remesh/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/remesh/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/remesh/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/remesh -- List Remesh Tasks This endpoint allows you to retrieve a list of Remesh tasks. ### Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Remesh Task Objects](#the-remesh-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/remesh?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/remesh?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/remesh", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "remesh", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.usdz?Expires=***", "blend": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.blend?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.stl?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null } ] ``` --- ## GET /openapi/v1/remesh/:id/stream -- Stream a Remesh Task This endpoint streams real-time updates for a Remesh task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Remesh task to stream. ### Returns Returns a stream of [The Remesh Task Objects](#the-remesh-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/remesh/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/remesh/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/remesh/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "progress": 0, "status": "PENDING" } event: message data: { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "remesh", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.usdz?Expires=***", "blend": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.blend?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.stl?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, } ``` --- ## The Remesh Task Object The Remesh Task object represents a work unit that Meshy uses to remesh and export an existing 3D model into various formats. The object has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the Remesh task. The value is `remesh`. - `model_urls` · *object* Downloadable URL to the textured 3D model file generated by Meshy. The property for a format will be omitted if the format is not generated instead of returning an empty string. - `glb` · *string* Downloadable URL to the GLB file. - `fbx` · *string* Downloadable URL to the FBX file. - `obj` · *string* Downloadable URL to the OBJ file. - `usdz` · *string* Downloadable URL to the USDZ file. - `blend` · *string* Downloadable URL to the Blender file. - `stl` · *string* Downloadable URL to the STL file. - `3mf` · *string* Downloadable URL to the 3MF file. Only present when `3mf` was requested via `target_formats`. - `thumbnail_url` · *string* Downloadable URL to a preview image rendered from the remeshed model. - `alpha_thumbnail_url` · *string* Downloadable URL to a transparent-background (RGBA) version of `thumbnail_url`. Only present when the task was created with `alpha_thumbnail: true` and the transparent preview was successfully rendered; otherwise this field is omitted. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Remesh Task Object** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "remesh", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.usdz?Expires=***", "blend": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.blend?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.stl?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": { "message": "" }, "consumed_credits": 5 } ``` --- # Convert API Source: https://docs.meshy.ai/api/convert # Convert API The Convert API allows you to convert existing 3D models into different file formats. --- ## POST /openapi/v1/convert -- Create a Convert Task This endpoint creates a new format conversion task. ### Parameters > **Note:** Only 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 task whose model you wish to convert. The task must have a status of `SUCCEEDED`. - `model_url` · *string* · **required** A publicly accessible URL or data URI pointing to a 3D model file. Supported formats: `.glb`, `.gltf`, `.obj`, `.fbx`, `.stl`. For Data URIs, use the MIME type: `application/octet-stream`. - `target_formats` · *string[]* · **required** A list of output formats for the converted model. Available values: `glb`, `fbx`, `obj`, `usdz`, `blend`, `stl`, `3mf`. ### Returns The `result` property of the response contains the `id` of the newly created convert task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `model_url` or `input_task_id` must be provided. * **Missing target_formats**: At least one target format must be specified. * **Invalid input task**: The `input_task_id` must refer to a successful task. * **Invalid model format**: The `model_url` points to a file with an unsupported extension. * **Unreachable URL**: The `model_url` could not be downloaded. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. ```bash curl https://api.meshy.ai/openapi/v1/convert \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["fbx", "stl"] }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", target_formats: ["fbx", "stl"] }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/convert', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "target_formats": ["fbx", "stl"] } response = requests.post( "https://api.meshy.ai/openapi/v1/convert", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "0193bfc5-ee4f-73f8-8525-44b398884ce9" } ``` --- ## GET /openapi/v1/convert/:id -- Retrieve a Convert Task This endpoint retrieves a convert task by its ID. ### Parameters - `id` · *path* The ID of the convert task to retrieve. ### Returns The Convert Task object. ```bash curl https://api.meshy.ai/openapi/v1/convert/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/convert/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/convert/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "convert", "model_urls": { "glb": "", "fbx": "https://assets.meshy.ai/.../model.fbx?Expires=...", "obj": "", "usdz": "", "stl": "https://assets.meshy.ai/.../model.stl?Expires=..." }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 1 } ``` --- ## DELETE /openapi/v1/convert/:id -- Delete a Convert Task This endpoint permanently deletes a convert task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the convert task to delete. ### Returns Returns `200 OK` on success. ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/convert/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/convert/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/convert/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/convert -- List Convert Tasks This endpoint allows you to retrieve a list of convert tasks. ### Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Convert Task Objects](#the-convert-task-object). ```bash curl https://api.meshy.ai/openapi/v1/convert?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/convert?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/convert", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "convert", "model_urls": { "fbx": "https://assets.meshy.ai/.../model.fbx?Expires=...", "stl": "https://assets.meshy.ai/.../model.stl?Expires=..." }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 1 } ] ``` --- ## GET /openapi/v1/convert/:id/stream -- Stream a Convert Task This endpoint streams real-time updates for a convert task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the convert task to stream. ### Returns Returns a stream of [The Convert Task Objects](#the-convert-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. ```bash curl -N https://api.meshy.ai/openapi/v1/convert/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/convert/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/convert/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Message event examples illustrate task progress. event: message data: { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "progress": 0, "status": "PENDING" } event: message data: { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "convert", "model_urls": { "fbx": "https://assets.meshy.ai/.../model.fbx?Expires=...", "stl": "https://assets.meshy.ai/.../model.stl?Expires=..." }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 1 } ``` --- ## The Convert Task Object The Convert Task object represents a format conversion job. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `convert`. - `model_urls` · *object* Downloadable URLs for the converted model files. Only the formats specified in `target_formats` will have URLs. Other format properties will be empty strings. - `progress` · *integer* Progress of the task (0-100). - `status` · *string* Status of the task. Possible values: `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. `0` if not started. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. `0` if not finished. - `task_error` · *object* Error object if the task failed. See [Errors](/api/errors) for more details. - `consumed_credits` · *integer* The number of credits consumed by this task (1 credit per convert task). Returns `0` for `FAILED` tasks. --- # Resize API Source: https://docs.meshy.ai/api/resize # Resize API The Resize API allows you to resize existing 3D models to real-world dimensions. You can specify an exact height, a longest-side constraint, or let AI automatically estimate the appropriate size. --- ## POST /openapi/v1/resize -- Create a Resize Task This endpoint creates a new resize task. ### Parameters > **Note:** Only 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 task whose model you wish to resize. The task must have a status of `SUCCEEDED`. The output format will be GLB. - `model_url` · *string* · **required** A publicly accessible URL or data URI pointing to a 3D model file. Supported formats: `.glb`, `.gltf`, `.obj`, `.fbx`, `.stl`. For Data URIs, use the MIME type: `application/octet-stream`. The output format will preserve the original format of the input model. > **Note:** Exactly one resize mode is **required**: `resize_height`, `resize_longest_side`, or `auto_size`. These three parameters are mutually exclusive. - `resize_height` · *number* Resize the model to a specific height measured in meters. - `resize_longest_side` · *number* Resize the model so that its longest side matches this value, measured in meters. The aspect ratio is preserved. - `auto_size` · *boolean* When set to `true`, the service uses AI vision to automatically estimate the real-world height of the object and resize the model accordingly. The origin will default to `bottom` unless `origin_at` is explicitly set. - `origin_at` · *string* · default: `bottom` Position of the origin after resizing. Available values: `bottom`, `center`. ### Returns The `result` property of the response contains the `id` of the newly created resize task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `model_url` or `input_task_id` must be provided. * **Missing resize mode**: At least one of `resize_height`, `resize_longest_side`, or `auto_size` must be specified. * **Mutually exclusive parameters**: `resize_height`, `resize_longest_side`, and `auto_size` cannot be combined. * **Invalid input task**: The `input_task_id` must refer to a successful task. * **Invalid model format**: The `model_url` points to a file with an unsupported extension. * **Unreachable URL**: The `model_url` could not be downloaded. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Simple: resize to a specific height curl https://api.meshy.ai/openapi/v1/resize \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "resize_height": 1.8 }' # Advanced: resize longest side with custom origin curl https://api.meshy.ai/openapi/v1/resize \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "model_url": "https://example.com/model.glb", "resize_longest_side": 2.0, "origin_at": "center" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Simple: resize to a specific height const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", resize_height: 1.8 }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/resize', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // Advanced: resize longest side with custom origin const advancedPayload = { model_url: "https://example.com/model.glb", resize_longest_side: 2.0, origin_at: "center" }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/resize', advancedPayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Simple: resize to a specific height payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "resize_height": 1.8 } response = requests.post( "https://api.meshy.ai/openapi/v1/resize", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # Advanced: resize longest side with custom origin advanced_payload = { "model_url": "https://example.com/model.glb", "resize_longest_side": 2.0, "origin_at": "center" } response = requests.post( "https://api.meshy.ai/openapi/v1/resize", headers=headers, json=advanced_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "0193bfc5-ee4f-73f8-8525-44b398884ce9" } ``` --- ## GET /openapi/v1/resize/:id -- Retrieve a Resize Task This endpoint retrieves a resize task by its ID. ### Parameters - `id` · *path* The ID of the resize task to retrieve. ### Returns The Resize Task object. ```bash curl https://api.meshy.ai/openapi/v1/resize/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/resize/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/resize/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "resize", "model_urls": { "glb": "https://assets.meshy.ai/.../model.glb?Expires=..." }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 1 } ``` --- ## DELETE /openapi/v1/resize/:id -- Delete a Resize Task This endpoint permanently deletes a resize task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the resize task to delete. ### Returns Returns `200 OK` on success. ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/resize/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/resize/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/resize/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/resize -- List Resize Tasks This endpoint allows you to retrieve a list of resize tasks. ### Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Resize Task Objects](#the-resize-task-object). ```bash curl https://api.meshy.ai/openapi/v1/resize?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/resize?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/resize", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "resize", "model_urls": { "glb": "https://assets.meshy.ai/.../model.glb?Expires=..." }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 1 } ] ``` --- ## GET /openapi/v1/resize/:id/stream -- Stream a Resize Task This endpoint streams real-time updates for a resize task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the resize task to stream. ### Returns Returns a stream of [The Resize Task Objects](#the-resize-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. ```bash curl -N https://api.meshy.ai/openapi/v1/resize/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/resize/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/resize/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Message event examples illustrate task progress. event: message data: { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "progress": 0, "status": "PENDING" } event: message data: { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "resize", "model_urls": { "glb": "https://assets.meshy.ai/.../model.glb?Expires=..." }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 1 } ``` --- ## The Resize Task Object The Resize Task object represents a resize job. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `resize`. - `model_urls` · *object* Downloadable URL for the resized model file. When using `input_task_id`, the output is always GLB. When using `model_url`, the output preserves the original format. - `progress` · *integer* Progress of the task (0-100). - `status` · *string* Status of the task. Possible values: `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. `0` if not started. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. `0` if not finished. - `task_error` · *object* Error object if the task failed. See [Errors](/api/errors) for more details. - `consumed_credits` · *integer* The number of credits consumed by this task (1 credit per resize task). Returns `0` for `FAILED` tasks. --- # UV Unwrap API Source: https://docs.meshy.ai/api/uv-unwrap # 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. ### 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`. 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. - `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: "" } ``` ```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. **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. **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 } ``` --- # Rigging API Source: https://docs.meshy.ai/api/rigging # Rigging API The Rigging API allows you to programmatically add a skeleton (armature) to 3D humanoid models, binding the mesh to it so they are ready for animation. For applying animations to a rigged character, see the [Animation API](/api/animation). Please note that programmatic rigging currently only works well with standard humanoid (bipedal) assets with clearly defined limbs and body structure at this time. --- ## POST /openapi/v1/rigging -- Create a Rigging Task This endpoint allows you to create a new rigging task for a given 3D model. Upon successful completion, it provides a rigged character in standard formats and optionally basic walking/running animations. Currently, auto-rigging is not suitable for the following models: - Untextured meshes - Non-humanoid assets - Humanoid assets with unclear limb and body structure > **Note:** When using `input_task_id`, models with more than **300,000 faces** are not supported for rigging. Please use the [Remesh API](/api/remesh) to reduce the face count before rigging. > **Note:** When using `model_url`, the character's face must point toward the +Z axis (the standard glTF forward direction). Models facing other axes will fail pose estimation. ### Parameters > **Note:** Only 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 input task that needs to be rigged. We currently support textured humanoid models. - `model_url` · *string* · **required** Please provide a 3D model for Meshy to rig via a publicly accessible URL or Data URI. We currently support textured humanoid GLB files (`.glb` format). - `height_meters` · *number* · default: `1.7` The approximate height of the character model in meters. This aids in scaling and rigging accuracy. It must be a positive number. - `texture_image_url` · *string* The model's UV-unwrapped base color texture image. Publicly accessible URL or Data URI. We currently support `.png` formats. ### Returns The `result` property of the response contains the task `id` of the newly created rigging task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `model_url` or `input_task_id` must be provided. * **Invalid model format**: The `model_url` points to a file with an unsupported extension (only .glb supported). * **Unreachable URL**: The `model_url` could not be downloaded. * **Invalid input task**: The `input_task_id` does not refer to a valid API task. * **Face count exceeded**: The input model has more than 300,000 faces. Please use the [Remesh API](/api/remesh) to reduce the face count before rigging. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `422 - Unprocessable Entity` Pose estimation failed. The provided model may not be a valid humanoid character. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Rig a model from a URL curl https://api.meshy.ai/openapi/v1/rigging \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "model_url": "YOUR_MODEL_URL_OR_DATA_URI", "height_meters": 1.8 }' ``` ```javascript import axios from 'axios' // Rig a model from a URL const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { model_url: "YOUR_MODEL_URL_OR_DATA_URI", height_meters: 1.8 }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/rigging', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests # Rig a model from a URL payload = { "model_url": "YOUR_MODEL_URL_OR_DATA_URI", "height_meters": 1.8 } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.post( "https://api.meshy.ai/openapi/v1/rigging", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018b314a-a1b5-716d-c222-2f1776f7f579" } ``` --- ## GET /openapi/v1/rigging/:id -- Retrieve a Rigging Task This endpoint allows you to retrieve a rigging task given a valid task `id`. Refer to [The Rigging Task Object](#the-rigging-task-object) to see which properties are included. ### Parameters - `id` · *path* Unique identifier for the rigging task to retrieve. ### Returns The response contains the Rigging Task object. Check [The Rigging Task Object](#the-rigging-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/rigging/018b314a-a1b5-716d-c222-2f1776f7f579 -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018b314a-a1b5-716d-c222-2f1776f7f579'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/rigging/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018b314a-a1b5-716d-c222-2f1776f7f579" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/rigging/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018b314a-a1b5-716d-c222-2f1776f7f579", "type": "rig", "status": "SUCCEEDED", "created_at": 1747032400453, "progress": 100, "started_at": 1747032401314, "finished_at": 1747032418417, "expires_at": 1747291618417, "task_error": { "message": "" }, "consumed_credits": 5, "result": { "rigged_character_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Character_output.fbx?Expires=...", "rigged_character_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Character_output.glb?Expires=...", "basic_animations": { "walking_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Walking_withSkin.glb?Expires=...", "walking_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Walking_withSkin.fbx?Expires=...", "walking_armature_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Walking_withSkin_armature.glb?Expires=...", "running_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Running_withSkin.glb?Expires=...", "running_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Running_withSkin.fbx?Expires=...", "running_armature_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Running_withSkin_armature.glb?Expires=..." } }, "preceding_tasks": 0 } ``` --- ## DELETE /openapi/v1/rigging/:id -- Delete a Rigging Task This endpoint permanently deletes a rigging task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the rigging task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/rigging/018b314a-a1b5-716d-c222-2f1776f7f579 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018b314a-a1b5-716d-c222-2f1776f7f579' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/rigging/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018b314a-a1b5-716d-c222-2f1776f7f579" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/rigging/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/rigging -- List Rigging Tasks Returns a paginated list of the caller's rigging tasks, newest first. Standard pagination via `page_num` and `page_size`. Note that tasks created through the API are managed through the API — they do not appear in the web app's My Assets. Use this endpoint to find a task whose ID you no longer have. **cURL** ```bash curl "https://api.meshy.ai/openapi/v1/rigging?page_num=1&page_size=20" \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` --- ## GET /openapi/v1/rigging/:id/stream -- Stream a Rigging Task This endpoint streams real-time updates for a Rigging task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Rigging task to stream. ### Returns Returns a stream of [The Rigging Task Objects](#the-rigging-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/rigging/018b314a-a1b5-716d-c222-2f1776f7f579/stream -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/rigging/018b314a-a1b5-716d-c222-2f1776f7f579/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } task_id = "018b314a-a1b5-716d-c222-2f1776f7f579" response = requests.get( f'https://api.meshy.ai/openapi/v1/rigging/{task_id}/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data_str = line.decode('utf-8')[5:] try: data = json.loads(data_str) print(data) if data.get('status') in ['SUCCEEDED', 'FAILED', 'CANCELED']: break except json.JSONDecodeError: print(f"Failed to decode JSON: {data_str}") response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018b314a-a1b5-716d-c222-2f1776f7f579", "progress": 0, "status": "PENDING" } event: message data: { "id": "018b314a-a1b5-716d-c222-2f1776f7f579", "progress": 50, "status": "IN_PROGRESS" } event: message data: { // Example of a SUCCEEDED task stream item, mirroring The Rigging Task Object structure "id": "018b314a-a1b5-716d-c222-2f1776f7f579", "type": "rig", "status": "SUCCEEDED", "created_at": 1747032400453, "progress": 100, "started_at": 1747032401314, "finished_at": 1747032418417, "expires_at": 1747291618417, "task_error": { "message": "" }, "consumed_credits": 5, "result": { "rigged_character_fbx_url": "https://assets.meshy.ai/.../Character_output.fbx?...", "rigged_character_glb_url": "https://assets.meshy.ai/.../Character_output.glb?...", "basic_animations": { "walking_glb_url": "https://assets.meshy.ai/.../Animation_Walking_withSkin.glb?...", "walking_fbx_url": "https://assets.meshy.ai/.../Animation_Walking_withSkin.fbx?...", "walking_armature_glb_url": "https://assets.meshy.ai/.../Animation_Walking_withSkin_armature.glb?...", "running_glb_url": "https://assets.meshy.ai/.../Animation_Running_withSkin.glb?...", "running_fbx_url": "https://assets.meshy.ai/.../Animation_Running_withSkin.fbx?...", "running_armature_glb_url": "https://assets.meshy.ai/.../Animation_Running_withSkin_armature.glb?..." } }, "preceding_tasks": 0 } ``` --- ## The Rigging Task Object The Rigging Task object represents the work unit for rigging a character. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the Rigging task. The value is `rig`. - `status` · *string* Status of the task. Possible values: `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task (0-100). `0` if not started, `100` if succeeded. - `created_at` · *timestamp* Timestamp (milliseconds since epoch) when the task was created. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp (milliseconds since epoch) when the task started processing. `0` if not started. - `finished_at` · *timestamp* Timestamp (milliseconds since epoch) when the task finished. `0` if not finished. - `expires_at` · *timestamp* Timestamp (milliseconds since epoch) when the task result assets expire and may be deleted. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `result` · *object* Contains the output asset URLs if the task `SUCCEEDED`, `null` otherwise. - `rigged_character_fbx_url` · *string* Downloadable URL for the rigged character in FBX format. - `rigged_character_glb_url` · *string* Downloadable URL for the rigged character in GLB format. - `basic_animations` · *object (optional)* Contains URLs for default animations. (e.g. if `generate_basic_animations` was implicitly true or enabled by default). - `walking_glb_url` · *string* Downloadable URL for walking animation in GLB format (with skin). - `walking_fbx_url` · *string* Downloadable URL for walking animation in FBX format (with skin). - `walking_armature_glb_url` · *string* Downloadable URL for walking animation armature in GLB format. - `running_glb_url` · *string* Downloadable URL for running animation in GLB format (with skin). - `running_fbx_url` · *string* Downloadable URL for running animation in FBX format (with skin). - `running_armature_glb_url` · *string* Downloadable URL for running animation armature in GLB format. - `preceding_tasks` · *integer* The count of preceding tasks in the queue. Meaningful only if status is `PENDING`. **Example Rigging Task Object** ```json { "id": "018b314a-a1b5-716d-c222-2f1776f7f579", "type": "rig", "status": "SUCCEEDED", "created_at": 1747032400453, "progress": 100, "started_at": 1747032401314, "finished_at": 1747032418417, "expires_at": 1747291618417, "task_error": { "message": "" }, "consumed_credits": 5, "result": { "rigged_character_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Character_output.fbx?Expires=...", "rigged_character_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Character_output.glb?Expires=...", "basic_animations": { "walking_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Walking_withSkin.glb?Expires=...", "walking_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Walking_withSkin.fbx?Expires=...", "walking_armature_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Walking_withSkin_armature.glb?Expires=...", "running_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Running_withSkin.glb?Expires=...", "running_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Running_withSkin.fbx?Expires=...", "running_armature_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018b314a-a1b5-716d-c222-2f1776f7f579/output/Animation_Running_withSkin_armature.glb?Expires=..." } }, "preceding_tasks": 0 } ``` --- # Animation API Source: https://docs.meshy.ai/api/animation # Animation API Endpoints for discovering available animations and applying them to rigged characters. --- ## POST /openapi/v1/animations -- Create an Animation Task This endpoint allows you to create a new task to apply a specific animation action to a previously rigged character. Includes post-processing options. ### Parameters - `rig_task_id` · *string* · **required** The `id` of a successfully completed rigging task (from `POST /openapi/v1/rigging`). The character from this task will be animated. - `action_id` · *integer* · **required** The identifier of the animation action to apply. See the [Animation Library Reference](/api/animation-library) for a complete list of available animations. - `post_process` · *object* Optional post-processing for the animation output. Omit it to receive the standard animation files. **Only when `post_process` is set:** - `operation_type` · *string* · **required** The type of operation to perform. Available values: `change_fps`, `fbx2usdz`, `extract_armature`. - `fps` · *integer* · default: `30` The target frame rate. Applicable only when `operation_type` is `change_fps`. Allowed values: `24`, `25`, `30`, `60`. ### Returns The `result` property of the response contains the task `id` of the newly created animation task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `rig_task_id` or `action_id` is missing. * **Invalid rig task**: The `rig_task_id` is invalid or refers to a failed/non-existent task. * **Invalid action ID**: The `action_id` does not correspond to a valid animation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The rigging task specified by `rig_task_id` was not found. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Animate a rigged model with required params only curl https://api.meshy.ai/openapi/v1/animations \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "rig_task_id": "018b314a-a1b5-716d-c222-2f1776f7f579", "action_id": 92 }' # With post-processing to change FPS curl https://api.meshy.ai/openapi/v1/animations \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "rig_task_id": "018b314a-a1b5-716d-c222-2f1776f7f579", "action_id": 92, "post_process": { "operation_type": "change_fps", "fps": 24 } }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Animate a rigged model with required params only const payload = { rig_task_id: "018b314a-a1b5-716d-c222-2f1776f7f579", action_id: 92 }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/animations', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // With post-processing to change FPS const advancedPayload = { rig_task_id: "018b314a-a1b5-716d-c222-2f1776f7f579", action_id: 92, post_process: { operation_type: "change_fps", fps: 24 } }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/animations', advancedPayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Animate a rigged model with required params only payload = { "rig_task_id": "018b314a-a1b5-716d-c222-2f1776f7f579", "action_id": 92 } response = requests.post( "https://api.meshy.ai/openapi/v1/animations", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # With post-processing to change FPS advanced_payload = { "rig_task_id": "018b314a-a1b5-716d-c222-2f1776f7f579", "action_id": 92, "post_process": { "operation_type": "change_fps", "fps": 24 } } response = requests.post( "https://api.meshy.ai/openapi/v1/animations", headers=headers, json=advanced_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018c425b-b2c6-727e-d333-3c1887i9h791" } ``` --- ## GET /openapi/v1/animations/:id -- Retrieve an Animation Task This endpoint allows you to retrieve an animation task given a valid task `id`. Refer to [The Animation Task Object](#the-animation-task-object) to see which properties are included. ### Parameters - `id` · *path* Unique identifier for the animation task to retrieve. ### Returns The response contains the Animation Task object. Check [The Animation Task Object](#the-animation-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/animations/018c425b-b2c6-727e-d333-3c1887i9h791 -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018c425b-b2c6-727e-d333-3c1887i9h791'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/animations/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018c425b-b2c6-727e-d333-3c1887i9h791" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/animations/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018c425b-b2c6-727e-d333-3c1887i9h791", "type": "animate", "status": "SUCCEEDED", "created_at": 1747032440896, "progress": 100, "started_at": 1747032441210, "finished_at": 1747032457530, "expires_at": 1747291657530, "task_error": { "message": "" }, "consumed_credits": 3, "result": { "animation_glb_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018c425b-b2c6-727e-d333-3c1887i9h791/output/Animation_Reaping_Swing_withSkin.glb?Expires=...", "animation_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018c425b-b2c6-727e-d333-3c1887i9h791/output/Animation_Reaping_Swing_withSkin.fbx?Expires=...", "processed_usdz_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018c425b-b2c6-727e-d333-3c1887i9h791/output/processed.usdz?Expires=...", "processed_armature_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018c425b-b2c6-727e-d333-3c1887i9h791/output/processed_armature.fbx?Expires=...", "processed_animation_fps_fbx_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018c425b-b2c6-727e-d333-3c1887i9h791/output/processed_60fps.fbx?Expires=..." }, "preceding_tasks": 0 } ``` --- ## DELETE /openapi/v1/animations/:id -- Delete an Animation Task This endpoint permanently deletes an animation task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the animation task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/animations/018b314a-a1b5-716d-c222-2f1776f7f579 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018b314a-a1b5-716d-c222-2f1776f7f579' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/animations/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018b314a-a1b5-716d-c222-2f1776f7f579" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/animations/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/animations -- List Animation Tasks Returns a paginated list of the caller's animation tasks, newest first. Standard pagination via `page_num` and `page_size`. Note that tasks created through the API are managed through the API — they do not appear in the web app's My Assets. Use this endpoint to find a task whose ID you no longer have. **cURL** ```bash curl "https://api.meshy.ai/openapi/v1/animations?page_num=1&page_size=20" \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` --- ## GET /openapi/v1/animations/:id/stream -- Stream an Animation Task This endpoint streams real-time updates for an Animation task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Animation task to stream. ### Returns Returns a stream of [The Animation Task Objects](#the-animation-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/animations/018c425b-b2c6-727e-d333-3c1887i9h791/stream -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/animations/018c425b-b2c6-727e-d333-3c1887i9h791/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } task_id = "018c425b-b2c6-727e-d333-3c1887i9h791" response = requests.get( f'https://api.meshy.ai/openapi/v1/animations/{task_id}/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data_str = line.decode('utf-8')[5:] try: data = json.loads(data_str) print(data) if data.get('status') in ['SUCCEEDED', 'FAILED', 'CANCELED']: break except json.JSONDecodeError: print(f"Failed to decode JSON: {data_str}") response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018c425b-b2c6-727e-d333-3c1887i9h791", "progress": 0, "status": "PENDING" } event: message data: { "id": "018c425b-b2c6-727e-d333-3c1887i9h791", "progress": 50, "status": "IN_PROGRESS" } event: message data: { // Example of a SUCCEEDED task stream item, mirroring The Animation Task Object structure "id": "018c425b-b2c6-727e-d333-3c1887i9h791", "type": "animate", "status": "SUCCEEDED", "created_at": 1747032440896, "progress": 100, "started_at": 1747032441210, "finished_at": 1747032457530, "expires_at": 1747291657530, "task_error": { "message": "" }, "consumed_credits": 3, "result": { "animation_glb_url": "https://assets.meshy.ai/.../Animation_Reaping_Swing_withSkin.glb?...", "animation_fbx_url": "https://assets.meshy.ai/.../Animation_Reaping_Swing_withSkin.fbx?...", "processed_usdz_url": "https://assets.meshy.ai/.../processed.usdz?...", "processed_armature_fbx_url": "https://assets.meshy.ai/.../processed_armature.fbx?...", "processed_animation_fps_fbx_url": "https://assets.meshy.ai/.../processed_60fps.fbx?..." }, "preceding_tasks": 0 } ``` --- ## The Animation Task Object The Animation Task object represents the work unit for applying an animation to a rigged character. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the Animation task. The value is `animate`. - `status` · *string* Status of the task. Possible values: `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task (0-100). - `created_at` · *timestamp* Timestamp (milliseconds since epoch) when the task was created. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp (milliseconds since epoch) when the task started processing. `0` if not started. - `finished_at` · *timestamp* Timestamp (milliseconds since epoch) when the task finished. `0` if not finished. - `expires_at` · *timestamp* Timestamp (milliseconds since epoch) when the task result assets expire. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `result` · *object* Contains the output animation URLs if the task `SUCCEEDED`. - `animation_glb_url` · *string* Downloadable URL for the animation in GLB format. - `animation_fbx_url` · *string* Downloadable URL for the animation in FBX format. - `processed_usdz_url` · *string* Downloadable URL for the processed animation in USDZ format. - `processed_armature_fbx_url` · *string* Downloadable URL for the processed armature in FBX format. - `processed_animation_fps_fbx_url` · *string* Downloadable URL for the animation with changed FPS in FBX format (e.g., if `change_fps` operation was used). - `preceding_tasks` · *integer* The count of preceding tasks in the queue. Meaningful only if status is `PENDING`. **Example Animation Task Object** ```json { "id": "018c425b-b2c6-727e-d333-3c1887i9h791", "type": "animate", "status": "SUCCEEDED", "created_at": 1747032440896, "progress": 100, "started_at": 1747032441210, "finished_at": 1747032457530, "expires_at": 1747291657530, "task_error": { "message": "" }, "consumed_credits": 3, "result": { "animation_glb_url": "https://assets.meshy.ai/.../Animation_Reaping_Swing_withSkin.glb?...", "animation_fbx_url": "https://assets.meshy.ai/.../Animation_Reaping_Swing_withSkin.fbx?...", "processed_usdz_url": "https://assets.meshy.ai/.../processed.usdz?...", "processed_armature_fbx_url": "https://assets.meshy.ai/.../processed_armature.fbx?...", "processed_animation_fps_fbx_url": "https://assets.meshy.ai/.../processed_60fps.fbx?..." }, "preceding_tasks": 0 } ``` --- # Retexture API Source: https://docs.meshy.ai/api/retexture # Retexture API Retexture API is a feature that allows you to integrate Meshy's AI retexturing capabilities into your own application. In this section, you'll find all the information you need to get started with this API. --- ## POST /openapi/v1/retexture -- Create a Retexture Task This endpoint allows you to create a new Retexture task. Refer to [The Retexture Task Object](#the-retexture-task-object) to see which properties are included with Retexture task object. ### Parameters > **Note:** Only 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 the completed Image to 3D or Text to 3D task you wish to retexture. This task must be one of the following tasks: Text to 3D Preview, Text to 3D Refine, Image to 3D or Remesh. In addition, it must have a status of `SUCCEEDED`. - `model_url` · *string* · **required** Provide a 3D model for Meshy to texture. Supported formats: `.glb`, `.gltf`, `.obj`, `.fbx`, `.stl`. There are two ways to provide the model: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the model. Use MIME type `application/octet-stream`. Example: `data:application/octet-stream;base64,`. > **Note:** Only one of `text_style_prompt` or `image_style_url` is **required**. If both are provided, `image_style_url` takes priority. - `text_style_prompt` · *string* · **required** Describe your desired texture style of the object using text. Maximum 600 characters. - `image_style_url` · *string* · **required** Provide a 2d image to guide the texturing process. We currently support `.jpg`, `.jpeg`, and `.png` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,` > **Note:** Image texturing may not work optimally if there are substantial geometry differences between the original asset and uploaded image. - `ai_model` · *string* · default: `latest` ID of the AI model to use for retexturing. Available values: `meshy-5`, `meshy-6`, `latest` (Meshy 6). - `enable_original_uv` · *boolean* · default: `false` Keep the model's existing UV layout instead of generating a new one. - If you are retexturing a model that Meshy generated (via `input_task_id`, or a `model_url` that points to a Meshy output), set this to `true` to reuse its optimized UV layout. - If you are retexturing a third-party model you uploaded, set `true` when it already has good UVs you want to keep, or leave it `false` to let Meshy unwrap fresh UVs (best for models that lack proper UV mapping). - `enable_pbr` · *boolean* · default: `false` Generate PBR Maps (metallic, roughness, normal) in addition to the base color. An emission map is also included when `ai_model` is `meshy-6` or `latest`, except at `texture_resolution: 8k` (no emission map is produced). - `texture_resolution` · *string* · default: `2k` Base color texture resolution. One of `2k` (2048×2048), `4k` (4096×4096), or `8k` (8192×8192). Higher resolutions capture more surface detail. > **Note:** `4k` and `8k` require `ai_model` `meshy-6` or `latest`. At `8k`, no emission map is produced and only triangle meshes are supported. - `hd_texture` · *boolean* · default: `false` · **deprecated** Use `texture_resolution` instead — equivalent to `texture_resolution: "4k"`. When both are set, `texture_resolution` takes precedence. - `remove_lighting` · *boolean* · default: `true` Removes highlights and shadows from the base color texture, producing a cleaner result that works better under custom lighting setups. > **Note:** Only supported when `ai_model` is `meshy-6` or `latest`. - `target_formats` · *string[]* Specifies which 3D file formats to include in the output. Only the requested formats will be generated and returned, which can reduce task completion time. When omitted, all supported formats are included. Available values: `glb`, `obj`, `fbx`, `stl`, `usdz`, `3mf` > **Note:** When omitted, all formats except `3mf` are generated. `3mf` is only included when explicitly specified. - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. ### Returns The `result` property of the response contains the task `id` of the newly created Retexture task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `model_url` or `input_task_id` must be provided. * **Missing style**: Either `text_style_prompt` or `image_style_url` must be provided. * **Invalid input task**: The `input_task_id` must refer to a successful task from a supported model. * **Invalid model format**: The `model_url` points to a file with an unsupported extension. * **Unreachable URL**: The `model_url` or `image_style_url` could not be downloaded. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Retexture with text prompt curl https://api.meshy.ai/openapi/v1/retexture \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "model_url": "https://cdn.meshy.ai/model/example_model_2.glb", "text_style_prompt": "red fangs, Samurai outfit that fused with japanese batik style", "enable_original_uv": true, "enable_pbr": true }' # Retexture with image style and PBR curl https://api.meshy.ai/openapi/v1/retexture \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "model_url": "https://cdn.meshy.ai/model/example_model_2.glb", "image_style_url": "https://cdn.meshy.ai/image/example_image.jpg", "ai_model": "latest", "enable_pbr": true, "enable_original_uv": true }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Retexture with text prompt const payload = { model_url: 'https://cdn.meshy.ai/model/example_model_2.glb', text_style_prompt: 'red fangs, Samurai outfit that fused with japanese batik style', enable_original_uv: true, enable_pbr: true, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/retexture', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } // Retexture with image style and PBR const imageStylePayload = { model_url: 'https://cdn.meshy.ai/model/example_model_2.glb', image_style_url: 'https://cdn.meshy.ai/image/example_image.jpg', ai_model: 'latest', enable_pbr: true, enable_original_uv: true, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/retexture', imageStylePayload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Retexture with text prompt payload = { "model_url": "https://cdn.meshy.ai/model/example_model_2.glb", "text_style_prompt": "red fangs, Samurai outfit that fused with japanese batik style", "enable_original_uv": True, "enable_pbr": True } response = requests.post( "https://api.meshy.ai/openapi/v1/retexture", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) # Retexture with image style and PBR image_style_payload = { "model_url": "https://cdn.meshy.ai/model/example_model_2.glb", "image_style_url": "https://cdn.meshy.ai/image/example_image.jpg", "ai_model": "latest", "enable_pbr": True, "enable_original_uv": True } response = requests.post( "https://api.meshy.ai/openapi/v1/retexture", headers=headers, json=image_style_payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## GET /openapi/v1/retexture/:id -- Retrieve a Retexture Task This endpoint allows you to retrieve a Retexture task given a valid task `id`. Refer to [The Retexture Task Object](#the-retexture-task-object) to see which properties are included with Retexture task object. ### Parameters - `id` · *path* Unique identifier for the Retexture task to retrieve. ### Returns The response contains the Retexture task object. Check [The Retexture Task Object](#the-retexture-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/retexture/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/retexture/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/retexture/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "retexture", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.mtl?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "text_style_prompt": "red fangs, Samurai outfit that fused with japanese batik style", "texture_image_url": "", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "task_error": { "message": "" }, "consumed_credits": 10 } ``` --- ## DELETE /openapi/v1/retexture/:id -- Delete a Retexture Task This endpoint permanently deletes a retexture task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the retexture task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/retexture/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/retexture/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/retexture/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/retexture -- List Retexture Tasks This endpoint allows you to retrieve a list of Retexture tasks. ### Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Retexture Task Objects](#the-retexture-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/retexture?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/retexture?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/retexture", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "retexture", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "text_style_prompt": "red fangs, Samurai outfit that fused with japanese batik style", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 10 } ] ``` --- ## GET /openapi/v1/retexture/:id/stream -- Stream a Retexture Task This endpoint streams real-time updates for a Retexture task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Retexture task to stream. ### Returns Returns a stream of [The Retexture Task Objects](#the-retexture-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/retexture/018a210d-8ba4-705c-b111-1f1776f7f578/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/retexture/018a210d-8ba4-705c-b111-1f1776f7f578/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/retexture/018a210d-8ba4-705c-b111-1f1776f7f578/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 0, "status": "PENDING" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 50, "status": "IN_PROGRESS" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "retexture", "progress": 100, "status": "SUCCEEDED", "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.obj?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.mtl?Expires=***", "stl": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.stl?Expires=***" }, "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 10 } ``` --- ## The Retexture Task Object The Retexture Task object is a work unit that Meshy uses to generate a 3D texture from a either text or image inputs. The model has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the Retexture task. The value is `retexture`. - `model_urls` · *object* Downloadable URL to the textured 3D model file generated by Meshy. - `glb` · *string* Downloadable URL to the GLB file. - `fbx` · *string* Downloadable URL to the FBX file. - `obj` · *string* Downloadable URL to the OBJ file. - `usdz` · *string* Downloadable URL to the USDZ file. - `mtl` · *string* Downloadable URL to the MTL file, returned alongside OBJ exports when textures are present. - `stl` · *string* Downloadable URL to the STL file. - `3mf` · *string* Downloadable URL to the 3MF file. Only present when `3mf` was requested via `target_formats`. - `text_style_prompt` · *string* This is the text prompt that was used to create the texturing task. - `image_style_url` · *string* This is the image input that was used to create the texturing task. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. - `alpha_thumbnail_url` · *string* Downloadable URL to a transparent-background (RGBA) version of `thumbnail_url`. Only present when the task was created with `alpha_thumbnail: true` and the transparent preview was successfully rendered; otherwise this field is omitted. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `texture_urls` · *array* An array of texture URL objects that are generated from the task. Normally this only contains **one** texture URL object. Each texture URL has the following properties: - `base_color` · *string* Downloadable URL to the base color map image. - `metallic` · *string* Downloadable URL to the metallic map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `normal` · *string* Downloadable URL to the normal map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `roughness` · *string* Downloadable URL to the roughness map image. > **Note:** If the task is created with `enable_pbr: false`, this property will be omitted. - `emission` · *string* Downloadable URL to the emission map image. > **Note:** If the task is created with `enable_pbr: false`, or `ai_model` is `meshy-5`, this property will be omitted. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** This property only presents when the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Retexture Task Model** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "retexture", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.glb?Expires=***", "fbx": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.fbx?Expires=***", "usdz": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/model.usdz?Expires=***" }, "text_style_prompt": "red fangs, Samurai outfit that fused with japanese batik style", "image_style_url": "https://assets.meshy.ai/***/image/example_image.jpg?Expires=***", "thumbnail_url": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/preview.png?Expires=***", "progress": 100, "started_at": 1692771667037, "created_at": 1692771650657, "expires_at": 1692771679037, "finished_at": 1692771669037, "status": "SUCCEEDED", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0.png?Expires=***", "metallic": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_metallic.png?Expires=XXX", "normal": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_normal.png?Expires=XXX", "roughness": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_roughness.png?Expires=XXX", "emission": "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/texture_0_emission.png?Expires=XXX" } ], "preceding_tasks": 0, "task_error": { "message": "" }, "consumed_credits": 10 } ``` --- # Text to Image API Source: https://docs.meshy.ai/api/text-to-image # Text to Image API Text to Image API is a feature that allows you to integrate Meshy's AI image generation capabilities into your own application. Generate high-quality images from text prompts using our powerful AI models. --- ## POST /openapi/v1/text-to-image -- Create a Text to Image Task This endpoint allows you to create a new Text to Image task. Refer to [The Text to Image Task Object](#the-text-to-image-task-object) to see which properties are included with Text to Image task object. ### Parameters - `ai_model` · *string* · **required** ID of the model to use for image generation. Available values: * `nano-banana`: Standard model (3 credits per image) * `nano-banana-2`: Balanced model with stronger capability than standard (6 credits per image) * `nano-banana-pro`: Pro model with enhanced quality (9 credits per image) * `gpt-image-2`: OpenAI GPT Image 2, a high-fidelity image model with restricted aspect-ratio support (9 credits per image) - `prompt` · *string* · **required** A text description of the image you want to generate. Be descriptive for best results. - `generate_multi_view` · *boolean* · default: `false` When set to `true`, generates a multi-view image showing the subject from multiple angles. > **Note:** When `generate_multi_view` is `true`, the `aspect_ratio` parameter cannot be set. - `pose_mode` · *string* Specify the pose mode for character generation. When omitted, the image is generated without any pose presets. Available values: `a-pose`, `t-pose` - `aspect_ratio` · *string* · default: `1:1` Specify the aspect ratio of the generated image. Allowed values depend on the selected `ai_model`: * `nano-banana`, `nano-banana-2`, `nano-banana-pro`: `1:1`, `16:9`, `9:16`, `4:3`, `3:4` * `gpt-image-2`: `1:1`, `3:2`, `2:3` only Available values: * `1:1`: Square format * `16:9`: Widescreen landscape (not supported by `gpt-image-2`) * `9:16`: Widescreen portrait (not supported by `gpt-image-2`) * `4:3`: Standard landscape (not supported by `gpt-image-2`) * `3:4`: Standard portrait (not supported by `gpt-image-2`) * `3:2`: Landscape (only supported by `gpt-image-2`) * `2:3`: Portrait (only supported by `gpt-image-2`) ### Returns The `result` property of the response contains the task `id` of the newly created Text to Image task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: A required parameter (e.g., `ai_model`, `prompt`) is missing. * **Invalid parameter**: `ai_model` or `aspect_ratio` is not one of the allowed values. * **Conflict**: `generate_multi_view` and `aspect_ratio` cannot be used simultaneously. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Generate an image from a text prompt curl https://api.meshy.ai/openapi/v1/text-to-image \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "ai_model": "nano-banana", "prompt": "A majestic dragon soaring through clouds at sunset", "aspect_ratio": "16:9" }' ``` ```javascript import axios from 'axios' // Generate an image from a text prompt const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { ai_model: "nano-banana", prompt: "A majestic dragon soaring through clouds at sunset", aspect_ratio: "16:9" }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/text-to-image', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests # Generate an image from a text prompt payload = { "ai_model": "nano-banana", "prompt": "A majestic dragon soaring through clouds at sunset", "aspect_ratio": "16:9" } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.post( "https://api.meshy.ai/openapi/v1/text-to-image", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## GET /openapi/v1/text-to-image/:id -- Retrieve a Text to Image Task This endpoint allows you to retrieve a Text to Image task given a valid task `id`. Refer to [The Text to Image Task Object](#the-text-to-image-task-object) to see which properties are included with Text to Image task object. ### Parameters - `id` · *path* Unique identifier for the Text to Image task to retrieve. ### Returns The response contains the Text to Image task object. Check [The Text to Image Task Object](#the-text-to-image-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/text-to-image/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/text-to-image/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/text-to-image/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-image", "ai_model": "nano-banana", "prompt": "A majestic dragon soaring through clouds at sunset", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ] } ``` --- ## DELETE /openapi/v1/text-to-image/:id -- Delete a Text to Image Task This endpoint permanently deletes a Text to Image task, including all associated images and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the Text to Image task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/text-to-image/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/text-to-image/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/text-to-image/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/text-to-image -- List Text to Image Tasks This endpoint allows you to retrieve a list of Text to Image tasks. ### Parameters - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Text to Image Task Objects](#the-text-to-image-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/text-to-image?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/text-to-image?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/text-to-image", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-image", "ai_model": "nano-banana", "prompt": "A majestic dragon soaring through clouds at sunset", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ] } ] ``` --- ## GET /openapi/v1/text-to-image/:id/stream -- Stream a Text to Image Task This endpoint streams real-time updates for a Text to Image task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Text to Image task to stream. ### Returns Returns a stream of [The Text to Image Task Objects](#the-text-to-image-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/text-to-image/018a210d-8ba4-705c-b111-1f1776f7f578/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/text-to-image/018a210d-8ba4-705c-b111-1f1776f7f578/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/text-to-image/018a210d-8ba4-705c-b111-1f1776f7f578/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```text // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 0, "status": "PENDING" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-image", "ai_model": "nano-banana", "prompt": "A majestic dragon soaring through clouds at sunset", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ] } ``` --- ## The Text to Image Task Object The Text to Image Task object is a work unit that Meshy keeps track of to generate an image from a **text prompt** input. The object has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* The type of image generation task. For Text to Image tasks, this will always be `text-to-image`. - `ai_model` · *string* The AI model used for this task. Possible values are `nano-banana`, `nano-banana-2`, `nano-banana-pro`, or `gpt-image-2`. - `prompt` · *string* The text prompt that was used to generate the image. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `image_urls` · *array* An array of downloadable URLs to the generated images. When `generate_multi_view` is enabled, this array contains three image URLs representing different viewing angles. Otherwise, it contains a single image URL. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Text to Image Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "text-to-image", "ai_model": "nano-banana", "prompt": "A majestic dragon soaring through clouds at sunset", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "preceding_tasks": 0, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ], "task_error": { "message": "" }, "consumed_credits": 3 } ``` --- # Image to Image API Source: https://docs.meshy.ai/api/image-to-image # Image to Image API Image to Image API is a feature that allows you to integrate Meshy's AI image editing capabilities into your own application. Transform and edit existing images using reference images and text prompts with our powerful AI models. --- ## POST /openapi/v1/image-to-image -- Create an Image to Image Task This endpoint allows you to create a new Image to Image task. Refer to [The Image to Image Task Object](#the-image-to-image-task-object) to see which properties are included with Image to Image task object. ### Parameters - `ai_model` · *string* · **required** ID of the model to use for image generation. Available values: * `nano-banana`: Standard model (3 credits per image) * `nano-banana-2`: Balanced model with stronger capability than standard (6 credits per image) * `nano-banana-pro`: Pro model with enhanced quality (9 credits per image) * `gpt-image-2`: OpenAI GPT Image 2, a high-fidelity image edit model (12 credits per image) - `prompt` · *string* · **required** A text description of the transformation or edit you want to apply to the reference images. - `reference_image_urls` · *array* · **required** An array of 1 to 5 reference images to use for the image editing task. We currently support `.jpg`, `.jpeg`, and `.png` formats. There are two ways to provide each image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `generate_multi_view` · *boolean* · default: `false` When set to `true`, generates a multi-view image showing the subject from multiple angles. > **Note:** When `generate_multi_view` is `true`, the `aspect_ratio` parameter cannot be set. - `aspect_ratio` · *string* · default: `1:1` Specify the aspect ratio of the output image. Allowed values depend on the selected `ai_model`: * `nano-banana`, `nano-banana-2`, `nano-banana-pro`: `1:1`, `16:9`, `9:16`, `4:3`, `3:4` * `gpt-image-2`: `1:1`, `3:2`, `2:3` only Available values: * `1:1`: Square format * `16:9`: Widescreen landscape (not supported by `gpt-image-2`) * `9:16`: Widescreen portrait (not supported by `gpt-image-2`) * `4:3`: Standard landscape (not supported by `gpt-image-2`) * `3:4`: Standard portrait (not supported by `gpt-image-2`) * `3:2`: Landscape (only supported by `gpt-image-2`) * `2:3`: Portrait (only supported by `gpt-image-2`) ### Returns The `result` property of the response contains the task `id` of the newly created Image to Image task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: A required parameter (e.g., `ai_model`, `prompt`, `reference_image_urls`) is missing. * **Invalid image format**: One or more reference images are not supported formats. * **Unreachable URL**: One or more `reference_image_urls` could not be downloaded. * **Invalid parameter**: `aspect_ratio` is not one of the allowed values for the selected `ai_model`. * **Conflict**: `generate_multi_view` and `aspect_ratio` cannot be used simultaneously. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Transform a reference image with a text prompt curl https://api.meshy.ai/openapi/v1/image-to-image \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", "reference_image_urls": [ "" ] }' ## Using Data URI example curl https://api.meshy.ai/openapi/v1/image-to-image \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", "reference_image_urls": [ "data:image/png;base64,${YOUR_BASE64_ENCODED_IMAGE_DATA}" ] }' ``` ```javascript import axios from 'axios' // Transform a reference image with a text prompt const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { ai_model: "nano-banana", prompt: "Transform this into a cyberpunk style artwork", // Using data URI example // reference_image_urls: ['data:image/png;base64,${YOUR_BASE64_ENCODED_IMAGE_DATA}'], reference_image_urls: [ "" ] }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/image-to-image', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests # Transform a reference image with a text prompt payload = { "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", # Using data URI example # "reference_image_urls": [f"data:image/png;base64,{YOUR_BASE64_ENCODED_IMAGE_DATA}"], "reference_image_urls": [ "" ] } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.post( "https://api.meshy.ai/openapi/v1/image-to-image", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## GET /openapi/v1/image-to-image/:id -- Retrieve an Image to Image Task This endpoint allows you to retrieve an Image to Image task given a valid task `id`. Refer to [The Image to Image Task Object](#the-image-to-image-task-object) to see which properties are included with Image to Image task object. ### Parameters - `id` · *path* Unique identifier for the Image to Image task to retrieve. ### Returns The response contains the Image to Image task object. Check [The Image to Image Task Object](#the-image-to-image-task-object) section for details. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/image-to-image/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/image-to-image/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/image-to-image/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-image", "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ] } ``` --- ## DELETE /openapi/v1/image-to-image/:id -- Delete an Image to Image Task This endpoint permanently deletes an Image to Image task, including all associated images and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the Image to Image task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/image-to-image/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/image-to-image/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/image-to-image/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/image-to-image -- List Image to Image Tasks This endpoint allows you to retrieve a list of Image to Image tasks. ### Parameters - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The Image to Image Task Objects](#the-image-to-image-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/image-to-image?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/image-to-image?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/image-to-image", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-image", "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ] } ] ``` --- ## GET /openapi/v1/image-to-image/:id/stream -- Stream an Image to Image Task This endpoint streams real-time updates for an Image to Image task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the Image to Image task to stream. ### Returns Returns a stream of [The Image to Image Task Objects](#the-image-to-image-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/image-to-image/018a210d-8ba4-705c-b111-1f1776f7f578/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/image-to-image/018a210d-8ba4-705c-b111-1f1776f7f578/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/image-to-image/018a210d-8ba4-705c-b111-1f1776f7f578/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```text // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "progress": 0, "status": "PENDING" } event: message data: { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-image", "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ] } ``` --- ## The Image to Image Task Object The Image to Image Task object is a work unit that Meshy keeps track of to generate an image from **reference images** and a **text prompt** input. The object has the following properties: ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* The type of image generation task. For Image to Image tasks, this will always be `image-to-image`. - `ai_model` · *string* The AI model used for this task. Possible values are `nano-banana`, `nano-banana-2`, `nano-banana-pro`, or `gpt-image-2`. - `prompt` · *string* The text prompt that was used to guide the image transformation. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `image_urls` · *array* An array of downloadable URLs to the generated images. When `generate_multi_view` is enabled, this array contains three image URLs representing different viewing angles. Otherwise, it contains a single image URL. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **Example Image to Image Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "image-to-image", "ai_model": "nano-banana", "prompt": "Transform this into a cyberpunk style artwork", "status": "SUCCEEDED", "progress": 100, "created_at": 1692771650657, "started_at": 1692771667037, "finished_at": 1692771669037, "expires_at": 1692771679037, "preceding_tasks": 0, "image_urls": [ "https://assets.meshy.ai/***/tasks/018a210d-8ba4-705c-b111-1f1776f7f578/output/image.png?Expires=***" ], "task_error": { "message": "" }, "consumed_credits": 3 } ``` --- # Multi-Color Print API Source: https://docs.meshy.ai/api/multi-color-print # Multi-Color Print API Convert 3D models into multi-color 3MF format for 3D printing, with a configurable color palette of up to 16 colors. --- ## POST /openapi/v1/print/multi-color -- Create a Multi-Color 3D Print Task This endpoint creates a new multi-color 3D print task. The task converts a 3D model into a multi-color 3MF file suitable for 3D printing. ### Parameters > **Note:** Only 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 succeeded task to use as input. Supported task types: [Image to 3D](/api/image-to-3d), [Multi-Image to 3D](/api/multi-image-to-3d#create-a-multi-image-to-3d-task), [Text to 3D](/api/text-to-3d), [Remesh](/api/remesh), and [Retexture](/api/retexture). The task must have a status of `SUCCEEDED`. - `model_url` · *string* · **required** Publicly accessible URL or Data URI of a 3D model. We currently support `.glb` and `.fbx` formats. - `max_colors` · *integer* · default: `4` Maximum number of colors in the output palette. Valid range: `1` to `16`. ### Returns The `result` property of the response contains the `id` of the newly created 3D print task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Either `model_url` or `input_task_id` must be provided. * **Invalid model format**: The `model_url` points to a file with an unsupported extension (only `.glb` and `.fbx` are supported). * **Unreachable URL**: The `model_url` could not be downloaded. * **Invalid input task**: The `input_task_id` must refer to a successful task. * **Invalid max_colors**: Value must be between 1 and 16. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Convert a 3D model to multi-color 3MF for printing curl https://api.meshy.ai/openapi/v1/print/multi-color \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "max_colors": 8 }' ``` ```javascript import axios from 'axios' // Convert a 3D model to multi-color 3MF for printing const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", max_colors: 8 }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/print/multi-color', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests # Convert a 3D model to multi-color 3MF for printing payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "max_colors": 8 } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.post( "https://api.meshy.ai/openapi/v1/print/multi-color", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "0193bfc5-ee4f-73f8-8525-44b398884ce9" } ``` --- ## GET /openapi/v1/print/multi-color/:id -- Retrieve a Multi-Color 3D Print Task This endpoint retrieves a multi-color 3D print task by its ID. ### Parameters - `id` · *path* The ID of the 3D print task to retrieve. ### Returns The 3D Print Task object. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/print/multi-color/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/print/multi-color/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/print/multi-color/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-multi-color", "model_urls": { "3mf": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.3mf?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 10 } ``` --- ## DELETE /openapi/v1/print/multi-color/:id -- Delete a Multi-Color 3D Print Task This endpoint permanently deletes a multi-color 3D print task, including all associated models and data. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the multi-color 3D print task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/print/multi-color/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/print/multi-color/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/print/multi-color/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/print/multi-color -- List Multi-Color 3D Print Tasks This endpoint allows you to retrieve a list of multi-color 3D print tasks. ### Parameters #### Optional attributes - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [The 3D Print Task Objects](#the-3d-print-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/print/multi-color?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/print/multi-color?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/print/multi-color", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-multi-color", "model_urls": { "3mf": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.3mf?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 10 } ] ``` --- ## GET /openapi/v1/print/multi-color/:id/stream -- Stream a Multi-Color 3D Print Task This endpoint streams real-time updates for a multi-color 3D print task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the multi-color 3D print task to stream. ### Returns Returns a stream of [The 3D Print Task Objects](#the-3d-print-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/print/multi-color/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/print/multi-color/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/print/multi-color/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "a43b5c6d-7e8f-901a-234b-567c890d1e2f", "progress": 0, "status": "PENDING" } event: message data: { "id": "a43b5c6d-7e8f-901a-234b-567c890d1e2f", "type": "print-multi-color", "model_urls": { "3mf": "https://assets.meshy.ai/***/tasks/a43b5c6d-7e8f-901a-234b-567c890d1e2f/output/model.3mf?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 10 } ``` --- ## The 3D Print Task Object - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the 3D Print task. The value is `print-multi-color`. - `model_urls` · *object* Downloadable URL to the 3D model file generated by Meshy. The property for a format will be omitted if the format is not generated instead of returning an empty string. - `3mf` · *string* Downloadable URL to the multi-color 3MF file. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **The 3D Print Task Object** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-multi-color", "model_urls": { "3mf": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.3mf?Expires=***" }, "progress": 100, "status": "SUCCEEDED", "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "task_error": null, "consumed_credits": 10 } ``` --- # Analyze Printability API Source: https://docs.meshy.ai/api/analyze-printability # Analyze Printability API Analyze a 3D model for FDM printability — watertightness, volume, holes, non-manifold edges, and degenerate faces. --- ## POST /openapi/v1/print/analyze -- Create an Analyze Printability Task This endpoint creates a new analyze-printability task. The task evaluates a 3D model and reports its printability metrics. If the input task already has cached printability, the returned task is immediately ready and the first `GET` on it will return the analysis result without going through the worker. ### Parameters > **Note:** Only 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 succeeded task you own. Supported task types: [Image to 3D](/api/image-to-3d), [Multi-Image to 3D](/api/multi-image-to-3d), [Text to 3D](/api/text-to-3d), [Remesh](/api/remesh), and [Retexture](/api/retexture). The task must use Meshy 6 (or any Preview model) and must have a status of `SUCCEEDED`. - `model_url` · *string* · **required** URL of a 3D model to analyze. Supported formats: `.glb`, `.stl`, `.obj`. Maximum file size: 100 MB. Must use `http`, `https`, or a `data:` URL (data URLs bypass extension checks). ### Returns The `result` property of the response contains the `id` of the newly created analyze-printability task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: neither `input_task_id` nor `model_url` was provided. * **Invalid UUID**: `input_task_id` is not a valid UUID. * **Invalid model URL**: `model_url` is malformed, uses an unsupported scheme, or has an unsupported file extension. * **Model file too large**: `model_url` body exceeded 100 MB. * **Task not succeeded**: the referenced task is still pending, in progress, or failed. - `401 - Unauthorized` Authentication failed. Please check your API key. - `403 - Forbidden` The task exists but is owned by a different user. - `404 - Not Found` Common causes: * The task does not exist or has been deleted. * The task uses a model older than Meshy 6, or its mode does not produce a 3D asset. * The underlying model file is no longer available in storage. - `429 - Too Many Requests` You have exceeded your pending-task quota or rate limit. **cURL** ```bash # Analyze an existing task curl https://api.meshy.ai/openapi/v1/print/analyze \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578" }' # Or analyze a model URL directly curl https://api.meshy.ai/openapi/v1/print/analyze \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "model_url": "https://example.com/model.glb" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578" }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/print/analyze', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578" } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.post( "https://api.meshy.ai/openapi/v1/print/analyze", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "0193bfc5-ee4f-73f8-8525-44b398884ce9" } ``` --- ## GET /openapi/v1/print/analyze/:id -- Retrieve an Analyze Printability Task This endpoint retrieves an analyze-printability task by its ID. ### Parameters - `id` · *path* The ID of the analyze-printability task to retrieve. ### Returns The [Analyze Printability Task Object](#the-analyze-printability-task-object). The `printability` field is `null` until the task reaches `SUCCEEDED`. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/print/analyze/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/print/analyze/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/print/analyze/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-analyze", "status": "SUCCEEDED", "progress": 100, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "expires_at": 1715725401000, "task_error": null, "printability": { "_version": "v1", "status": "warning", "issue_count": 1, "error_count": 0, "warning_count": 1, "metrics": { "is_watertight": true, "volume": 1.316167354292668, "non_manifold_edges": 0, "degenerate_faces": 43242, "holes": 0 }, "evaluated_at": 1700000001000 }, "consumed_credits": 0 } ``` --- ## DELETE /openapi/v1/print/analyze/:id -- Delete an Analyze Printability Task This endpoint permanently deletes an analyze-printability task and its cached result. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the analyze-printability task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/print/analyze/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/print/analyze/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/print/analyze/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/print/analyze -- List Analyze Printability Tasks This endpoint allows you to retrieve a list of analyze-printability tasks. ### Parameters #### Optional attributes - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [Analyze Printability Task Objects](#the-analyze-printability-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/print/analyze?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/print/analyze?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/print/analyze", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-analyze", "status": "SUCCEEDED", "progress": 100, "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "expires_at": 1715725401000, "task_error": null, "printability": { "_version": "v1", "status": "warning", "issue_count": 1, "error_count": 0, "warning_count": 1, "metrics": { "is_watertight": true, "volume": 1.316167354292668, "non_manifold_edges": 0, "degenerate_faces": 43242, "holes": 0 }, "evaluated_at": 1700000001000 }, "consumed_credits": 0 } ] ``` --- ## GET /openapi/v1/print/analyze/:id/stream -- Stream an Analyze Printability Task This endpoint streams real-time updates for an analyze-printability task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the analyze-printability task to stream. ### Returns Returns a stream of [Analyze Printability Task Objects](#the-analyze-printability-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. The `printability` block is sent only once the task reaches `SUCCEEDED`. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/print/analyze/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/print/analyze/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/print/analyze/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "a43b5c6d-7e8f-901a-234b-567c890d1e2f", "progress": 0, "status": "PENDING" } event: message data: { "id": "a43b5c6d-7e8f-901a-234b-567c890d1e2f", "type": "print-analyze", "status": "SUCCEEDED", "progress": 100, "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "expires_at": 1715725401000, "task_error": null, "printability": { "_version": "v1", "status": "warning", "issue_count": 1, "error_count": 0, "warning_count": 1, "metrics": { "is_watertight": true, "volume": 1.316167354292668, "non_manifold_edges": 0, "degenerate_faces": 43242, "holes": 0 }, "evaluated_at": 1700000001000 }, "consumed_credits": 0 } ``` --- ## The Analyze Printability Task Object - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the analyze-printability task. The value is `print-analyze`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result will expire from the system, in milliseconds. `0` if the task has not yet finished. - `task_error` · *object* Error information if the task has failed. This property is `null` if the task has not failed. See [Errors](/api/errors) for more details. - `message` · *string* Error message describing what went wrong. - `printability` · *object* Printability evaluation result. `null` until the task reaches `SUCCEEDED`. - `_version` · *string* Schema version of the printability result. Currently `v1`. - `status` · *string* Overall status. One of: * `healthy`: no errors and no warnings. * `warning`: at least one warning, no errors. * `error`: at least one error. * `unknown`: the model could not be analyzed. - `issue_count` · *integer* Total count of issues, equal to `error_count + warning_count`. - `error_count` · *integer* Number of error-level issues. Errors are raised when the model is **not watertight**, has **non-positive volume**, or has **non-manifold edges**. - `warning_count` · *integer* Number of warning-level issues. Warnings are raised when the model contains **degenerate faces** or **holes**. - `metrics` · *object* Raw geometry metrics returned by the evaluator. - `is_watertight` · *boolean* `true` when the mesh has no boundary edges (i.e., is closed). - `volume` · *number* Volume of the model in cubic meters. - `non_manifold_edges` · *integer* Count of non-manifold edges. - `degenerate_faces` · *integer* Count of degenerate faces (zero-area or invalid faces). - `holes` · *integer* Count of holes (boundary loops) in the mesh. - `evaluated_at` · *timestamp* Timestamp of when the analysis was computed, in milliseconds since epoch. - `consumed_credits` · *integer* Always `0`. This endpoint is free. **The Analyze Printability Task Object** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-analyze", "status": "SUCCEEDED", "progress": 100, "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000001000, "expires_at": 1715725401000, "task_error": null, "printability": { "_version": "v1", "status": "warning", "issue_count": 1, "error_count": 0, "warning_count": 1, "metrics": { "is_watertight": true, "volume": 1.316167354292668, "non_manifold_edges": 0, "degenerate_faces": 43242, "holes": 0 }, "evaluated_at": 1700000001000 }, "consumed_credits": 0 } ``` --- # Repair Printability API Source: https://docs.meshy.ai/api/repair-printability # Repair Printability API Repair a 3D model for FDM printability — fix non-manifold edges, degenerate faces, holes, and other topology issues so the mesh is print-ready. --- ## POST /openapi/v1/print/repair -- Create a Repair Printability Task This endpoint creates a new repair-printability task. The task runs topology repair on a 3D model and returns a watertight, print-ready version. The output format matches the input format. If you submit an `.stl` via `model_url`, the response's `model_urls.stl` will hold the repaired mesh and the other format fields will be empty. The `input_task_id` path always reads the source task's GLB, so the output is `.glb`. ### Parameters > **Note:** Only one of `input_task_id` or `model_url` is **required**. If both are provided, `input_task_id` takes priority. > **Note:** Existing textures are removed during repair due to geometry changes. To add textures back, use the [Retexture API](/api/retexture) on the repaired model. - `input_task_id` · *string* · **required** The ID of a succeeded task you own. Supported task types: [Image to 3D](/api/image-to-3d), [Multi-Image to 3D](/api/multi-image-to-3d), [Text to 3D](/api/text-to-3d), [Remesh](/api/remesh), and [Retexture](/api/retexture). The task must have a status of `SUCCEEDED` and must have produced a GLB asset. - `model_url` · *string* · **required** URL of a 3D model to repair. Supported formats: `.glb`, `.stl`, `.obj`. Maximum file size: 100 MB. Must use `http`, `https`, or a `data:` URL (data URLs bypass extension checks). - `alpha_thumbnail` · *boolean* · default: `false` When set to `true`, the task additionally renders a transparent-background (RGBA) version of the preview and returns it as `alpha_thumbnail_url` on the GET response. The existing `thumbnail_url` field is unchanged. ### Returns The `result` property of the response contains the `id` of the newly created repair-printability task. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: neither `input_task_id` nor `model_url` was provided. * **Invalid UUID**: `input_task_id` is not a valid UUID. * **Invalid model URL**: `model_url` is malformed, uses an unsupported scheme, or has an unsupported file extension. * **Model file too large**: `model_url` body exceeded 100 MB. * **Task not succeeded**: the referenced task is still pending, in progress, or failed. * **Missing GLB**: the referenced task has no GLB asset to repair. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Common causes: * **Free plan**: task creation requires a paid plan. Upgrade at the [subscription page](https://www.meshy.ai/settings/subscription). * **Insufficient credits**: the workspace credit limit was reached. - `404 - Not Found` The referenced task does not exist or is owned by a different user. - `429 - Too Many Requests` You have exceeded your pending-task quota or rate limit. **cURL** ```bash # Repair an existing task curl https://api.meshy.ai/openapi/v1/print/repair \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578" }' # Or repair a model URL directly curl https://api.meshy.ai/openapi/v1/print/repair \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "model_url": "https://example.com/model.stl" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578" }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/v1/print/repair', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578" } headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.post( "https://api.meshy.ai/openapi/v1/print/repair", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "0193bfc5-ee4f-73f8-8525-44b398884ce9" } ``` --- ## GET /openapi/v1/print/repair/:id -- Retrieve a Repair Printability Task This endpoint retrieves a repair-printability task by its ID. ### Parameters - `id` · *path* The ID of the repair-printability task to retrieve. ### Returns The [Repair Printability Task Object](#the-repair-printability-task-object). The `model_urls` block is empty until the task reaches `SUCCEEDED`. Only the `model_urls` field matching the input format is populated. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/print/repair/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f'; const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/print/repair/${taskId}`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( f"https://api.meshy.ai/openapi/v1/print/repair/{task_id}", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-repair", "status": "SUCCEEDED", "progress": 100, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000030000, "expires_at": 1715725401000, "task_error": null, "model_urls": { "glb": "", "fbx": "", "obj": "", "stl": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.stl?Expires=***", "usdz": "", "3mf": "", "mtl": "" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/preview.png?Expires=***", "texture_urls": [], "consumed_credits": 10 } ``` --- ## DELETE /openapi/v1/print/repair/:id -- Delete a Repair Printability Task This endpoint permanently deletes a repair-printability task and its repaired output. This action is irreversible. ### Path Parameters - `id` · *path* The ID of the repair-printability task to delete. ### Returns Returns `200 OK` on success. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/v1/print/repair/a43b5c6d-7e8f-901a-234b-567c890d1e2f \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = 'a43b5c6d-7e8f-901a-234b-567c890d1e2f' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/v1/print/repair/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "a43b5c6d-7e8f-901a-234b-567c890d1e2f" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/v1/print/repair/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 200 Ok on success. ``` --- ## GET /openapi/v1/print/repair -- List Repair Printability Tasks This endpoint allows you to retrieve a list of repair-printability tasks. ### Parameters #### Optional attributes - `page_num` · *integer* Page number for pagination. Starts and defaults to `1`. - `page_size` · *integer* Page size limit. Defaults to `10` items. Maximum allowed is `50` items. - `sort_by` · *string* Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of [Repair Printability Task Objects](#the-repair-printability-task-object). **cURL** ```bash curl https://api.meshy.ai/openapi/v1/print/repair?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; try { const response = await axios.get( `https://api.meshy.ai/openapi/v1/print/repair?page_size=10`, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/print/repair", headers=headers, params={"page_size": 10} ) response.raise_for_status() print(response.json()) ``` **Response** ```json [ { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-repair", "status": "SUCCEEDED", "progress": 100, "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000030000, "expires_at": 1715725401000, "task_error": null, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.glb?Expires=***", "fbx": "", "obj": "", "stl": "", "usdz": "", "3mf": "", "mtl": "" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/preview.png?Expires=***", "texture_urls": [], "consumed_credits": 10 } ] ``` --- ## GET /openapi/v1/print/repair/:id/stream -- Stream a Repair Printability Task This endpoint streams real-time updates for a repair-printability task using Server-Sent Events (SSE). ### Parameters - `id` · *path* Unique identifier for the repair-printability task to stream. ### Returns Returns a stream of [Repair Printability Task Objects](#the-repair-printability-task-object) as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. The `model_urls` block is sent only once the task reaches `SUCCEEDED`. **cURL** ```bash curl -N https://api.meshy.ai/openapi/v1/print/repair/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/v1/print/repair/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/v1/print/repair/a43b5c6d-7e8f-901a-234b-567c890d1e2f/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "a43b5c6d-7e8f-901a-234b-567c890d1e2f", "progress": 0, "status": "PENDING" } event: message data: { "id": "a43b5c6d-7e8f-901a-234b-567c890d1e2f", "type": "print-repair", "status": "SUCCEEDED", "progress": 100, "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000030000, "expires_at": 1715725401000, "task_error": null, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/a43b5c6d-7e8f-901a-234b-567c890d1e2f/output/model.glb?Expires=***", "fbx": "", "obj": "", "stl": "", "usdz": "", "3mf": "", "mtl": "" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/a43b5c6d-7e8f-901a-234b-567c890d1e2f/output/preview.png?Expires=***", "texture_urls": [], "consumed_credits": 10 } ``` --- ## The Repair Printability Task Object - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the repair-printability task. The value is `print-repair`. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result will expire from the system, in milliseconds. `0` if the task has not yet finished. - `task_error` · *object* Error information if the task has failed. This property is `null` if the task has not failed. See [Errors](/api/errors) for more details. - `message` · *string* Error message describing what went wrong. - `model_urls` · *object* Downloadable URLs to the repaired 3D model. **Only the field matching the input format is populated**; the other format fields are empty strings. - `glb` · *string* Downloadable URL to the repaired GLB. Populated when the input was a GLB or when `input_task_id` was used. - `fbx` · *string* Reserved for FBX output. Always an empty string for repair-printability tasks. - `obj` · *string* Downloadable URL to the repaired OBJ. Populated when the input was an OBJ upload. - `stl` · *string* Downloadable URL to the repaired STL. Populated when the input was an STL upload. - `usdz` · *string* Reserved for USDZ output. Always an empty string for repair-printability tasks. - `3mf` · *string* Reserved for 3MF output. Always an empty string for repair-printability tasks. - `mtl` · *string* Reserved for MTL output. Always an empty string for repair-printability tasks. - `thumbnail_url` · *string* URL of a preview image rendered from the repaired model. - `alpha_thumbnail_url` · *string* Downloadable URL to a transparent-background (RGBA) version of `thumbnail_url`. Only present when the task was created with `alpha_thumbnail: true` and the transparent preview was successfully rendered; otherwise this field is omitted. - `texture_urls` · *array* Always an empty array. Repair preserves the input geometry only and does not re-bake textures. - `consumed_credits` · *integer* The number of credits consumed by this task. `10` once the task has reached `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). **The Repair Printability Task Object** ```json { "id": "0193bfc5-ee4f-73f8-8525-44b398884ce9", "type": "print-repair", "status": "SUCCEEDED", "progress": 100, "preceding_tasks": 0, "created_at": 1699999999000, "started_at": 1700000000000, "finished_at": 1700000030000, "expires_at": 1715725401000, "task_error": null, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/model.glb?Expires=***", "fbx": "", "obj": "", "stl": "", "usdz": "", "3mf": "", "mtl": "" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/0193bfc5-ee4f-73f8-8525-44b398884ce9/output/preview.png?Expires=***", "texture_urls": [], "consumed_credits": 10 } ``` --- # Creative Lab — Keychain API Source: https://docs.meshy.ai/api/creative-lab-keychain # Creative Lab — Keychain API Turn a source photo into a 3D-printable keychain medallion — a badge-shaped colorized depth relief — in two stages: **prototype** generates a colorized concept image from your input photo, then **build** turns that concept image into a relief 3D model. The two stages are linked via `input_task_id`. - `POST /openapi/creative-lab/keychain/v1/prototype` - `POST /openapi/creative-lab/keychain/v1/build` --- ## POST /openapi/creative-lab/keychain/v1/prototype -- Create a Keychain Prototype Task Generate a single colorized concept image from the source photo. The returned task ID is what you pass as `input_task_id` to the build endpoint. Refer to [The Keychain Prototype Task Object](#the-keychain-prototype-task-object) for the response shape. ### Parameters - `image_url` · *string* · **required** Source photo for Meshy to colorize into a keychain-ready concept image. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created keychain prototype task. Poll the [Get a Task](#retrieve-a-keychain-task) endpoint or subscribe to the [stream](#stream-a-keychain-task) until the task reaches `SUCCEEDED`, then pass that ID to the [build endpoint](#create-a-keychain-build-task) as `input_task_id`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `image_url` is required. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW or intellectual property moderation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 1: generate a colorized keychain concept image curl https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1: generate a colorized keychain concept image const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1: generate a colorized keychain concept image payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## POST /openapi/creative-lab/keychain/v1/build -- Create a Keychain Build Task Generate the final 3D-printable keychain medallion from a succeeded prototype task. The build runs a depth-map relief pipeline on the prototype's colorized concept image and ships a single mesh artifact in the format you ask for. Refer to [The Keychain Build Task Object](#the-keychain-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created with the same API key, must have reached `SUCCEEDED`, and must have produced exactly one candidate image. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/keychain/v1/prototype` and refuses any other source with `404`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. #### `options` Optional tuning parameters for the relief geometry. Every field has a sensible default — send only the ones you want to override. - `badge_shape` · *string* · default: `circle` Outline silhouette of the keychain medallion. Available values: * `circle` (default) * `rounded-rect` * `hexagon` * `shield` * `star` - `size_mm` · *number* · default: `40` Bounding square edge length of the keychain, in millimeters. Range: `(0, 400]`. - `relief_height_mm` · *number* · default: `2.2` Maximum relief height above the base, in millimeters. Range: `[0, 20]`. - `relief_offset_mm` · *number* · default: `0` Vertical offset applied to the relief before extrusion, in millimeters. Range: `[0, 20]`. - `base_thickness_mm` · *number* · default: `0.1` Thickness of the flat base plate behind the relief, in millimeters. Range: `[0, 20]`. - `has_closed_back` · *boolean* · default: `true` Whether the back of the medallion is sealed as a closed surface. Set to `false` for an open shell. - `relief_curve` · *string* · default: `linear` Transfer curve mapping depth-map values to relief height. Available values: * `linear` (default) * `gamma` * `s-curve` - `curve_param` · *number* · default: `1.0` Shape parameter for the transfer curve (only meaningful when `relief_curve` is `gamma`). Range: `(0, 10]`. - `invert_depth` · *boolean* · default: `false` Invert the depth-map interpretation so darker regions become higher relief. - `smoothing` · *number* · default: `0.24` Smoothing strength applied to the depth map before relief extraction. Range: `[0, 10]`. - `relief_scale` · *number* · default: `1.0` Vertical scale multiplier applied on top of `relief_height_mm`. Range: `(0, 10]`. - `depth_threshold` · *number* · default: `0.1` Low-pass threshold for depth-map values; anything below this is clamped to zero. Range: `[0, 1]`. - `remove_background` · *boolean* · default: `true` Automatically remove the background of the prototype's concept image before reliefing. - `export_resolution` · *integer* · default: `512` Mesh resolution used for export. Range: `[64, 2048]`. #### `output` Optional wire-format selector. Defaults to `glb`. - `format` · *string* · default: `glb` Artifact bundle returned by the build. Available values: * `glb` (default) — returns a single `model.glb` under `model_urls.glb`. * `obj` — zips `model.obj` + `model.mtl` + `texture.png` and returns the bundle under `model_urls.obj`. * `zip` — zips every artifact the generator emits and returns the bundle under `model_urls.bundle_zip`. ### Returns The `result` property of the response contains the task `id` of the newly created keychain build task. Poll the [Get a Task](#retrieve-a-keychain-task) endpoint or subscribe to the [stream](#stream-a-keychain-task) until the task reaches `SUCCEEDED`, then download the artifact from the single entry in `model_urls`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` is required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidate**: The prototype task succeeded but produced no candidate image. * **Options out of range**: One of the `options` fields fell outside its allowed range or enum set. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 2: chain build off a succeeded prototype task curl https://api.meshy.ai/openapi/creative-lab/keychain/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "options": { "badge_shape": "circle", "size_mm": 40, "relief_height_mm": 2.5 }, "output": { "format": "glb" } }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: chain build off a succeeded prototype task const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", options: { badge_shape: "circle", size_mm: 40, relief_height_mm: 2.5, }, output: { format: "glb" }, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/keychain/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: chain build off a succeeded prototype task payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "options": { "badge_shape": "circle", "size_mm": 40, "relief_height_mm": 2.5, }, "output": {"format": "glb"}, } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/keychain/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" } ``` --- ## GET /openapi/creative-lab/keychain/v1/(prototype|build)/:id -- Retrieve a Keychain Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Keychain Prototype Task Object](#the-keychain-prototype-task-object) and [The Keychain Build Task Object](#the-keychain-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the keychain task to retrieve. ### Returns The response contains the keychain task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/keychain/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '019c320e-9a8f-7a1c-9c11-2a1876f8a9bb'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/keychain/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "018a210d-8ba4-705c-b111-1f1776f7f578" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/keychain/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-keychain-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` **Build Response** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-keychain-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 20, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***" } } ``` --- ## DELETE /openapi/creative-lab/keychain/v1/(prototype|build)/:id -- Delete a Keychain Task Cancel a keychain task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the keychain task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/keychain/v1/(prototype|build)/:id/stream -- Stream a Keychain Task Stream real-time updates for a keychain task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the keychain task to stream. ### Returns Returns a stream of [Keychain Prototype](#the-keychain-prototype-task-object) or [Keychain Build](#the-keychain-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/keychain/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/keychain/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/keychain/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "progress": 0, "status": "PENDING" } event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-keychain-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "task_error": null, "consumed_credits": 20, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***" } } ``` --- ## GET /openapi/creative-lab/keychain/v1/(prototype|build) -- List Keychain Tasks Retrieve a paginated list of your keychain tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the keychain prototype task object](#the-keychain-prototype-task-object) when listing `/prototype` or [the keychain build task object](#the-keychain-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/keychain/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/keychain/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-keychain-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ] ``` --- ## The Keychain Prototype Task Object The Keychain Prototype Task object is a work unit that Meshy keeps track of to generate a colorized **concept image** from a source photo. The output of this stage is chained into [the build stage](#create-a-keychain-build-task) via `input_task_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-keychain-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `image_urls` · *array of strings* Downloadable URLs for the concept image candidates generated by this prototype task. Currently the API always returns exactly one candidate; the field is an array so future revisions can surface multiple candidates without a breaking change. **Example Keychain Prototype Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-keychain-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` --- ## The Keychain Build Task Object The Keychain Build Task object is a work unit that Meshy keeps track of to generate the final 3D keychain mesh from a succeeded prototype task. The build runs a depth-map relief pipeline on the prototype's concept image and publishes a single mesh artifact in the format the caller requested. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-keychain-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `model_urls` · *object* Downloadable URLs for the generated artifact, keyed by artifact name. Always contains exactly one entry — the format requested via the build request's `output.format`. The key matches the requested format: - `glb` · *string* Downloadable URL to the GLB file. Present when `output.format` was `glb` (the default). - `obj` · *string* Downloadable URL to a zip bundle containing `model.obj`, `model.mtl`, and `texture.png`. Present when `output.format` was `obj`. - `bundle_zip` · *string* Downloadable URL to a zip bundle of every artifact the generator emits. Present when `output.format` was `zip`. **Example Keychain Build Task Object** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-keychain-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 20, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***" } } ``` --- # Creative Lab — Fridge Magnet API Source: https://docs.meshy.ai/api/creative-lab-fridge-magnet # Creative Lab — Fridge Magnet API Turn your photos into custom fridge magnets — a rounded-rectangle colorized depth relief with a flat magnetic back, sized for the fridge — in two stages: **prototype** generates a colorized concept image from your input photo, then **build** turns that concept image into a relief 3D model. The two stages are linked via `input_task_id`. - `POST /openapi/creative-lab/fridge-magnet/v1/prototype` - `POST /openapi/creative-lab/fridge-magnet/v1/build` --- ## POST /openapi/creative-lab/fridge-magnet/v1/prototype -- Create a Fridge Magnet Prototype Task Generate a single colorized concept image from the source photo. The returned task ID is what you pass as `input_task_id` to the build endpoint. Refer to [The Fridge Magnet Prototype Task Object](#the-fridge-magnet-prototype-task-object) for the response shape. ### Parameters - `image_url` · *string* · **required** Source photo for Meshy to colorize into a fridge-magnet-ready concept image. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created fridge magnet prototype task. Poll the [Get a Task](#retrieve-a-fridge-magnet-task) endpoint or subscribe to the [stream](#stream-a-fridge-magnet-task) until the task reaches `SUCCEEDED`, then pass that ID to the [build endpoint](#create-a-fridge-magnet-build-task) as `input_task_id`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `image_url` is required. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW or intellectual property moderation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 1: generate a colorized fridge magnet concept image curl https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1: generate a colorized fridge magnet concept image const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1: generate a colorized fridge magnet concept image payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9" } ``` --- ## POST /openapi/creative-lab/fridge-magnet/v1/build -- Create a Fridge Magnet Build Task Generate the final 3D-printable fridge magnet from a succeeded prototype task. The build runs a depth-map relief pipeline on the prototype's colorized concept image and ships a single mesh artifact in the format you ask for. Refer to [The Fridge Magnet Build Task Object](#the-fridge-magnet-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created with the same API key, must have reached `SUCCEEDED`, and must have produced exactly one candidate image. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/fridge-magnet/v1/prototype` and refuses any other source with `404`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. #### `options` Optional tuning parameters for the relief geometry. Every field has a sensible default — send only the ones you want to override. - `badge_shape` · *string* · default: `rounded-rect` Outline silhouette of the fridge magnet. Available values: * `circle` * `rounded-rect` (default) * `hexagon` * `shield` * `star` - `size_mm` · *number* · default: `60` Bounding square edge length of the fridge magnet, in millimeters. Range: `(0, 400]`. - `relief_height_mm` · *number* · default: `3.3` Maximum relief height above the base, in millimeters. Range: `[0, 20]`. - `relief_offset_mm` · *number* · default: `0` Vertical offset applied to the relief before extrusion, in millimeters. Range: `[0, 20]`. - `base_thickness_mm` · *number* · default: `2.0` Thickness of the flat base plate behind the relief, in millimeters. The fridge-magnet default is a chunkier 2 mm base — gives the magnet enough body to grip the fridge without the relief feeling fragile. Range: `[0, 20]`. - `has_closed_back` · *boolean* · default: `true` Whether the back of the fridge magnet is sealed as a closed surface (the side you glue the magnet to). Set to `false` for an open shell. - `relief_curve` · *string* · default: `linear` Transfer curve mapping depth-map values to relief height. Available values: * `linear` (default) * `gamma` * `s-curve` - `curve_param` · *number* · default: `1.0` Shape parameter for the transfer curve (only meaningful when `relief_curve` is `gamma`). Range: `(0, 10]`. - `invert_depth` · *boolean* · default: `false` Invert the depth-map interpretation so darker regions become higher relief. - `smoothing` · *number* · default: `0.24` Smoothing strength applied to the depth map before relief extraction. Range: `[0, 10]`. - `relief_scale` · *number* · default: `1.0` Vertical scale multiplier applied on top of `relief_height_mm`. Range: `(0, 10]`. - `depth_threshold` · *number* · default: `0.1` Low-pass threshold for depth-map values; anything below this is clamped to zero. Range: `[0, 1]`. - `remove_background` · *boolean* · default: `true` Automatically remove the background of the prototype's concept image before reliefing. - `export_resolution` · *integer* · default: `512` Mesh resolution used for export. Range: `[64, 2048]`. #### `output` Optional wire-format selector. Defaults to `glb`. - `format` · *string* · default: `glb` Artifact bundle returned by the build. Available values: * `glb` (default) — returns a single `model.glb` under `model_urls.glb`. * `obj` — zips `model.obj` + `model.mtl` + `texture.png` and returns the bundle under `model_urls.obj`. * `zip` — zips every artifact the generator emits and returns the bundle under `model_urls.bundle_zip`. ### Returns The `result` property of the response contains the task `id` of the newly created fridge magnet build task. Poll the [Get a Task](#retrieve-a-fridge-magnet-task) endpoint or subscribe to the [stream](#stream-a-fridge-magnet-task) until the task reaches `SUCCEEDED`, then download the artifact from the single entry in `model_urls`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` is required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidate**: The prototype task succeeded but produced no candidate image. * **Options out of range**: One of the `options` fields fell outside its allowed range or enum set. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 2: chain build off a succeeded prototype task curl https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9", "options": { "badge_shape": "rounded-rect", "size_mm": 60, "relief_height_mm": 3.3 }, "output": { "format": "glb" } }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: chain build off a succeeded prototype task const payload = { input_task_id: "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9", options: { badge_shape: "rounded-rect", size_mm: 60, relief_height_mm: 3.3, }, output: { format: "glb" }, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: chain build off a succeeded prototype task payload = { "input_task_id": "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9", "options": { "badge_shape": "rounded-rect", "size_mm": 60, "relief_height_mm": 3.3, }, "output": {"format": "glb"}, } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0" } ``` --- ## GET /openapi/creative-lab/fridge-magnet/v1/(prototype|build)/:id -- Retrieve a Fridge Magnet Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Fridge Magnet Prototype Task Object](#the-fridge-magnet-prototype-task-object) and [The Fridge Magnet Build Task Object](#the-fridge-magnet-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the fridge magnet task to retrieve. ### Returns The response contains the fridge magnet task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype/01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9", "type": "creative-lab-fridge-magnet-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729543210000, "started_at": 1729543215000, "finished_at": 1729543242000, "expires_at": 1729802442000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` **Build Response** ```json { "id": "01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0", "type": "creative-lab-fridge-magnet-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729543250000, "started_at": 1729543258000, "finished_at": 1729543285000, "expires_at": 1729802485000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 20, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0/output/model.glb?Expires=***" } } ``` --- ## DELETE /openapi/creative-lab/fridge-magnet/v1/(prototype|build)/:id -- Delete a Fridge Magnet Task Cancel a fridge magnet task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the fridge magnet task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype/01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/fridge-magnet/v1/(prototype|build)/:id/stream -- Stream a Fridge Magnet Task Stream real-time updates for a fridge magnet task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the fridge magnet task to stream. ### Returns Returns a stream of [Fridge Magnet Prototype](#the-fridge-magnet-prototype-task-object) or [Fridge Magnet Build](#the-fridge-magnet-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0", "progress": 0, "status": "PENDING" } event: message data: { "id": "01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0", "type": "creative-lab-fridge-magnet-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1729543250000, "started_at": 1729543258000, "finished_at": 1729543285000, "expires_at": 1729802485000, "task_error": null, "consumed_credits": 20, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0/output/model.glb?Expires=***" } } ``` --- ## GET /openapi/creative-lab/fridge-magnet/v1/(prototype|build) -- List Fridge Magnet Tasks Retrieve a paginated list of your fridge magnet tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the fridge magnet prototype task object](#the-fridge-magnet-prototype-task-object) when listing `/prototype` or [the fridge magnet build task object](#the-fridge-magnet-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/fridge-magnet/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9", "type": "creative-lab-fridge-magnet-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729543210000, "started_at": 1729543215000, "finished_at": 1729543242000, "expires_at": 1729802442000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ] ``` --- ## The Fridge Magnet Prototype Task Object The Fridge Magnet Prototype Task object is a work unit that Meshy keeps track of to generate a colorized **concept image** from a source photo. The output of this stage is chained into [the build stage](#create-a-fridge-magnet-build-task) via `input_task_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-fridge-magnet-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `image_urls` · *array of strings* Downloadable URLs for the concept image candidates generated by this prototype task. Currently the API always returns exactly one candidate; the field is an array so future revisions can surface multiple candidates without a breaking change. **Example Fridge Magnet Prototype Task Object** ```json { "id": "01a3d8f1-8c2e-7d04-b223-3f3776a1c8c9", "type": "creative-lab-fridge-magnet-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729543210000, "started_at": 1729543215000, "finished_at": 1729543242000, "expires_at": 1729802442000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` --- ## The Fridge Magnet Build Task Object The Fridge Magnet Build Task object is a work unit that Meshy keeps track of to generate the final 3D fridge magnet mesh from a succeeded prototype task. The build runs a depth-map relief pipeline on the prototype's concept image and publishes a single mesh artifact in the format the caller requested. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-fridge-magnet-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `model_urls` · *object* Downloadable URLs for the generated artifact, keyed by artifact name. Always contains exactly one entry — the format requested via the build request's `output.format`. The key matches the requested format: - `glb` · *string* Downloadable URL to the GLB file. Present when `output.format` was `glb` (the default). - `obj` · *string* Downloadable URL to a zip bundle containing `model.obj`, `model.mtl`, and `texture.png`. Present when `output.format` was `obj`. - `bundle_zip` · *string* Downloadable URL to a zip bundle of every artifact the generator emits. Present when `output.format` was `zip`. **Example Fridge Magnet Build Task Object** ```json { "id": "01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0", "type": "creative-lab-fridge-magnet-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729543250000, "started_at": 1729543258000, "finished_at": 1729543285000, "expires_at": 1729802485000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 20, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/01b4e9a2-9d3f-8e15-c334-4f4887b2d9d0/output/model.glb?Expires=***" } } ``` --- # Creative Lab — Figure API Source: https://docs.meshy.ai/api/creative-lab-figure # Creative Lab — Figure API Turn a source photo into a chibi-style collectible 3D figure in two stages: **prototype** generates a styled concept image from your input photo, then **build** turns that concept image into a textured 3D model. The two stages are linked via `input_task_id`. - `POST /openapi/creative-lab/figure/v1/prototype` - `POST /openapi/creative-lab/figure/v1/build` --- ## POST /openapi/creative-lab/figure/v1/prototype -- Create a Figure Prototype Task Generate a single chibi-style concept image from the source photo. The returned task ID is what you pass as `input_task_id` to the build endpoint. Refer to [The Figure Prototype Task Object](#the-figure-prototype-task-object) for the response shape. ### Parameters - `image_url` · *string* · **required** Source photo for Meshy to stylize as a chibi figure. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created figure prototype task. Poll the [Get a Task](#retrieve-a-figure-task) endpoint or subscribe to the [stream](#stream-a-figure-task) until the task reaches `SUCCEEDED`, then pass that ID to the [build endpoint](#create-a-figure-build-task) as `input_task_id`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `image_url` is required. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW or intellectual property moderation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 1: generate a chibi-style concept image curl https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1: generate a chibi-style concept image const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1: generate a chibi-style concept image payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## POST /openapi/creative-lab/figure/v1/build -- Create a Figure Build Task Generate the final textured 3D figure from a succeeded prototype task. The build runs the same image-to-3D pipeline as [Image to 3D](/api/image-to-3d), so the response object format and the list of output URLs match exactly. Refer to [The Figure Build Task Object](#the-figure-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created with the same API key, must have reached `SUCCEEDED`, and must have produced exactly one candidate image. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/figure/v1/prototype` and refuses any other source with `404`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created figure build task. Poll the [Get a Task](#retrieve-a-figure-task) endpoint or subscribe to the [stream](#stream-a-figure-task) until the task reaches `SUCCEEDED`, then download the textured GLB from `model_urls.glb` (or the OBJ + MTL pair from `model_urls.obj` and `model_urls.mtl` if your downstream pipeline prefers OBJ). ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` is required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidate**: The prototype task succeeded but produced no candidate image. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 2: chain build off a succeeded prototype task curl https://api.meshy.ai/openapi/creative-lab/figure/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: chain build off a succeeded prototype task const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/figure/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: chain build off a succeeded prototype task payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/figure/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" } ``` --- ## GET /openapi/creative-lab/figure/v1/(prototype|build)/:id -- Retrieve a Figure Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Figure Prototype Task Object](#the-figure-prototype-task-object) and [The Figure Build Task Object](#the-figure-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the figure task to retrieve. ### Returns The response contains the figure task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '019c320e-9a8f-7a1c-9c11-2a1876f8a9bb'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/figure/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "018a210d-8ba4-705c-b111-1f1776f7f578" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/figure/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` **Build Response** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-figure-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 20, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/texture_0.png?Expires=***" } ] } ``` --- ## DELETE /openapi/creative-lab/figure/v1/(prototype|build)/:id -- Delete a Figure Task Cancel a figure task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the figure task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/figure/v1/(prototype|build)/:id/stream -- Stream a Figure Task Stream real-time updates for a figure task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the figure task to stream. ### Returns Returns a stream of [Figure Prototype](#the-figure-prototype-task-object) or [Figure Build](#the-figure-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "progress": 0, "status": "PENDING" } event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-figure-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "task_error": null, "consumed_credits": 20, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/texture_0.png?Expires=***" } ] } ``` --- ## GET /openapi/creative-lab/figure/v1/(prototype|build) -- List Figure Tasks Retrieve a paginated list of your figure tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the figure prototype task object](#the-figure-prototype-task-object) when listing `/prototype` or [the figure build task object](#the-figure-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/figure/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/figure/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ] ``` --- ## The Figure Prototype Task Object The Figure Prototype Task object is a work unit that Meshy keeps track of to generate a chibi-style **concept image** from a source photo. The output of this stage is chained into [the build stage](#create-a-figure-build-task) via `input_task_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-figure-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `image_urls` · *array of strings* Downloadable URLs for the concept image candidates generated by this prototype task. Currently the API always returns exactly one candidate; the field is an array so future revisions can surface multiple candidates without a breaking change. **Example Figure Prototype Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` --- ## The Figure Build Task Object The Figure Build Task object is a work unit that Meshy keeps track of to generate a textured **3D figure** from a succeeded prototype task. It runs the same image-to-3D pipeline used by [Image to 3D](/api/image-to-3d), so the output fields mirror that endpoint's [task object](/api/image-to-3d#the-image-to-3d-task-object). ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-figure-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `prompt` · *string* Always empty for figure build. Present for cross-endpoint compatibility with the shared `V2ImageTo3DTaskResponse` shape used by [Image to 3D](/api/image-to-3d). - `negative_prompt` · *string* Always empty for figure build. Present for cross-endpoint compatibility. - `texture_prompt` · *string* Always empty for figure build. Present for cross-endpoint compatibility. - `texture_image_url` · *string* Always empty for figure build. Present for cross-endpoint compatibility. - `model_urls` · *object* Downloadable URLs for the generated 3D model. The figure build emits a textured GLB plus the OBJ + MTL pair for pipelines that prefer Wavefront OBJ. The field shape matches the [Image to 3D model_urls](/api/image-to-3d#the-image-to-3d-task-object) object so future format additions slot in without a breaking change. - `glb` · *string* Downloadable URL to the textured GLB file. - `obj` · *string* Downloadable URL to the Wavefront OBJ file (geometry + UV). - `mtl` · *string* Downloadable URL to the OBJ companion MTL material file. Pair with `obj` and the entry from `texture_urls[0].base_color`. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. - `texture_urls` · *array* An array of texture URL objects generated by this task. Currently contains a single object with the base color map. - `base_color` · *string* Downloadable URL to the base color map image. **Example Figure Build Task Object** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-figure-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 20, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/texture_0.png?Expires=***" } ] } ``` --- # Creative Lab — Vinyl Figure API Source: https://docs.meshy.ai/api/creative-lab-vinyl-figure # Creative Lab — Vinyl Figure API Turn a source photo into a big-head vinyl collectible 3D figure in two stages: **prototype** generates a styled concept image from your input photo, then **build** turns that concept image into a textured 3D model. The two stages are linked via `input_task_id`. - `POST /openapi/creative-lab/vinyl-figure/v1/prototype` - `POST /openapi/creative-lab/vinyl-figure/v1/build` --- ## POST /openapi/creative-lab/vinyl-figure/v1/prototype -- Create a Vinyl Figure Prototype Task Generate a single vinyl-figure-style concept image from the source photo. The returned task ID is what you pass as `input_task_id` to the build endpoint. Refer to [The Vinyl Figure Prototype Task Object](#the-vinyl-figure-prototype-task-object) for the response shape. ### Parameters - `image_url` · *string* · **required** Source photo for Meshy to stylize as a big-head vinyl figure. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created vinyl figure prototype task. Poll the [Get a Task](#retrieve-a-vinyl-figure-task) endpoint or subscribe to the [stream](#stream-a-vinyl-figure-task) until the task reaches `SUCCEEDED`, then pass that ID to the [build endpoint](#create-a-vinyl-figure-build-task) as `input_task_id`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `image_url` is required. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW or intellectual property moderation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 1: generate a vinyl-figure-style concept image curl https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1: generate a vinyl-figure-style concept image const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1: generate a vinyl-figure-style concept image payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de" } ``` --- ## POST /openapi/creative-lab/vinyl-figure/v1/build -- Create a Vinyl Figure Build Task Generate the final textured 3D vinyl figure from a succeeded prototype task. The build runs the same image-to-3D pipeline as [Image to 3D](/api/image-to-3d), so the response object format and the list of output URLs match exactly. Refer to [The Vinyl Figure Build Task Object](#the-vinyl-figure-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created with the same API key, must have reached `SUCCEEDED`, and must have produced exactly one candidate image. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/vinyl-figure/v1/prototype` and refuses any other source with `404`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created vinyl figure build task. Poll the [Get a Task](#retrieve-a-vinyl-figure-task) endpoint or subscribe to the [stream](#stream-a-vinyl-figure-task) until the task reaches `SUCCEEDED`, then download the textured GLB from `model_urls.glb` (or the OBJ + MTL pair from `model_urls.obj` and `model_urls.mtl` if your downstream pipeline prefers OBJ). ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` is required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidate**: The prototype task succeeded but produced no candidate image. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 2: chain build off a succeeded prototype task curl https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: chain build off a succeeded prototype task const payload = { input_task_id: "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: chain build off a succeeded prototype task payload = { "input_task_id": "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef" } ``` --- ## GET /openapi/creative-lab/vinyl-figure/v1/(prototype|build)/:id -- Retrieve a Vinyl Figure Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Vinyl Figure Prototype Task Object](#the-vinyl-figure-prototype-task-object) and [The Vinyl Figure Build Task Object](#the-vinyl-figure-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the vinyl figure task to retrieve. ### Returns The response contains the vinyl figure task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype/019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de", "type": "creative-lab-vinyl-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1752969600000, "started_at": 1752969604000, "finished_at": 1752969630000, "expires_at": 1753228830000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` **Build Response** ```json { "id": "019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef", "type": "creative-lab-vinyl-figure-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1752969700000, "started_at": 1752969710000, "finished_at": 1752969735000, "expires_at": 1753228935000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 30, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/texture_0.png?Expires=***" } ] } ``` --- ## DELETE /openapi/creative-lab/vinyl-figure/v1/(prototype|build)/:id -- Delete a Vinyl Figure Task Cancel a vinyl figure task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the vinyl figure task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype/019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/vinyl-figure/v1/(prototype|build)/:id/stream -- Stream a Vinyl Figure Task Stream real-time updates for a vinyl figure task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the vinyl figure task to stream. ### Returns Returns a stream of [Vinyl Figure Prototype](#the-vinyl-figure-prototype-task-object) or [Vinyl Figure Build](#the-vinyl-figure-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef", "progress": 0, "status": "PENDING" } event: message data: { "id": "019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef", "type": "creative-lab-vinyl-figure-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1752969700000, "started_at": 1752969710000, "finished_at": 1752969735000, "expires_at": 1753228935000, "task_error": null, "consumed_credits": 30, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/texture_0.png?Expires=***" } ] } ``` --- ## GET /openapi/creative-lab/vinyl-figure/v1/(prototype|build) -- List Vinyl Figure Tasks Retrieve a paginated list of your vinyl figure tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the vinyl figure prototype task object](#the-vinyl-figure-prototype-task-object) when listing `/prototype` or [the vinyl figure build task object](#the-vinyl-figure-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/vinyl-figure/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de", "type": "creative-lab-vinyl-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1752969600000, "started_at": 1752969604000, "finished_at": 1752969630000, "expires_at": 1753228830000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ] ``` --- ## The Vinyl Figure Prototype Task Object The Vinyl Figure Prototype Task object is a work unit that Meshy keeps track of to generate a vinyl-figure-style **concept image** from a source photo. The output of this stage is chained into [the build stage](#create-a-vinyl-figure-build-task) via `input_task_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-vinyl-figure-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `image_urls` · *array of strings* Downloadable URLs for the concept image candidates generated by this prototype task. Currently the API always returns exactly one candidate; the field is an array so future revisions can surface multiple candidates without a breaking change. **Example Vinyl Figure Prototype Task Object** ```json { "id": "019c8a2e-4b7d-7c3a-8d21-3f2987a1c4de", "type": "creative-lab-vinyl-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1752969600000, "started_at": 1752969604000, "finished_at": 1752969630000, "expires_at": 1753228830000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` --- ## The Vinyl Figure Build Task Object The Vinyl Figure Build Task object is a work unit that Meshy keeps track of to generate a textured **3D vinyl figure** from a succeeded prototype task. It runs the same image-to-3D pipeline used by [Image to 3D](/api/image-to-3d), so the output fields mirror that endpoint's [task object](/api/image-to-3d#the-image-to-3d-task-object). ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-vinyl-figure-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `prompt` · *string* Always empty for vinyl figure build. Present for cross-endpoint compatibility with the shared `V2ImageTo3DTaskResponse` shape used by [Image to 3D](/api/image-to-3d). - `negative_prompt` · *string* Always empty for vinyl figure build. Present for cross-endpoint compatibility. - `texture_prompt` · *string* Always empty for vinyl figure build. Present for cross-endpoint compatibility. - `texture_image_url` · *string* Always empty for vinyl figure build. Present for cross-endpoint compatibility. - `model_urls` · *object* Downloadable URLs for the generated 3D model. The vinyl figure build emits a textured GLB plus the OBJ + MTL pair for pipelines that prefer Wavefront OBJ. The field shape matches the [Image to 3D model_urls](/api/image-to-3d#the-image-to-3d-task-object) object so future format additions slot in without a breaking change. - `glb` · *string* Downloadable URL to the textured GLB file. - `obj` · *string* Downloadable URL to the Wavefront OBJ file (geometry + UV). - `mtl` · *string* Downloadable URL to the OBJ companion MTL material file. Pair with `obj` and the entry from `texture_urls[0].base_color`. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. - `texture_urls` · *array* An array of texture URL objects generated by this task. Currently contains a single object with the base color map. - `base_color` · *string* Downloadable URL to the base color map image. **Example Vinyl Figure Build Task Object** ```json { "id": "019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef", "type": "creative-lab-vinyl-figure-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1752969700000, "started_at": 1752969710000, "finished_at": 1752969735000, "expires_at": 1753228935000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 30, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c8a31-6e2f-7b4d-9a55-4c3098b2d5ef/output/texture_0.png?Expires=***" } ] } ``` --- # Creative Lab — Brick Figure API Source: https://docs.meshy.ai/api/creative-lab-brick-figure # Creative Lab — Brick Figure API Turn a source photo into a brick-style collectible 3D minifigure in two stages: **prototype** generates a styled concept image from your input photo, then **build** turns that concept image into a textured 3D model. The two stages are linked via `input_task_id`. - `POST /openapi/creative-lab/brick-figure/v1/prototype` - `POST /openapi/creative-lab/brick-figure/v1/build` --- ## POST /openapi/creative-lab/brick-figure/v1/prototype -- Create a Brick Figure Prototype Task Generate a single brick-style concept image from the source photo. The returned task ID is what you pass as `input_task_id` to the build endpoint. Refer to [The Brick Figure Prototype Task Object](#the-brick-figure-prototype-task-object) for the response shape. ### Parameters - `image_url` · *string* · **required** Source photo for Meshy to stylize as a brick minifigure. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created brick figure prototype task. Poll the [Get a Task](#retrieve-a-brick-figure-task) endpoint or subscribe to the [stream](#stream-a-brick-figure-task) until the task reaches `SUCCEEDED`, then pass that ID to the [build endpoint](#create-a-brick-figure-build-task) as `input_task_id`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `image_url` is required. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW moderation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `403 - Forbidden` The input image was flagged for intellectual property violation. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 1: generate a brick-style concept image curl https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1: generate a brick-style concept image const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1: generate a brick-style concept image payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## POST /openapi/creative-lab/brick-figure/v1/build -- Create a Brick Figure Build Task Generate the final textured 3D brick figure from a succeeded prototype task. The build runs the same image-to-3D pipeline as [Image to 3D](/api/image-to-3d), so the response object format and the list of output URLs match exactly. Refer to [The Brick Figure Build Task Object](#the-brick-figure-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created with the same API key, must have reached `SUCCEEDED`, and must have produced exactly one candidate image. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/brick-figure/v1/prototype` and refuses any other source with `404`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created brick figure build task. Poll the [Get a Task](#retrieve-a-brick-figure-task) endpoint or subscribe to the [stream](#stream-a-brick-figure-task) until the task reaches `SUCCEEDED`, then download the textured GLB from `model_urls.glb` (or the OBJ + MTL pair from `model_urls.obj` and `model_urls.mtl` if your downstream pipeline prefers OBJ). ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` is required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidate**: The prototype task succeeded but produced no candidate image. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 2: chain build off a succeeded prototype task curl https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: chain build off a succeeded prototype task const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: chain build off a succeeded prototype task payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" } ``` --- ## GET /openapi/creative-lab/brick-figure/v1/(prototype|build)/:id -- Retrieve a Brick Figure Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Brick Figure Prototype Task Object](#the-brick-figure-prototype-task-object) and [The Brick Figure Build Task Object](#the-brick-figure-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the brick figure task to retrieve. ### Returns The response contains the brick figure task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '019c320e-9a8f-7a1c-9c11-2a1876f8a9bb'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "018a210d-8ba4-705c-b111-1f1776f7f578" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-brick-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` **Build Response** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-brick-figure-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 30, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/texture_0.png?Expires=***" } ] } ``` --- ## DELETE /openapi/creative-lab/brick-figure/v1/(prototype|build)/:id -- Delete a Brick Figure Task Cancel a brick figure task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the brick figure task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/brick-figure/v1/(prototype|build)/:id/stream -- Stream a Brick Figure Task Stream real-time updates for a brick figure task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the brick figure task to stream. ### Returns Returns a stream of [Brick Figure Prototype](#the-brick-figure-prototype-task-object) or [Brick Figure Build](#the-brick-figure-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "progress": 0, "status": "PENDING" } event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-brick-figure-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "task_error": null, "consumed_credits": 30, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/texture_0.png?Expires=***" } ] } ``` --- ## GET /openapi/creative-lab/brick-figure/v1/(prototype|build) -- List Brick Figure Tasks Retrieve a paginated list of your brick figure tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `100` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the brick figure prototype task object](#the-brick-figure-prototype-task-object) when listing `/prototype` or [the brick figure build task object](#the-brick-figure-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/brick-figure/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-brick-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ] ``` --- ## The Brick Figure Prototype Task Object The Brick Figure Prototype Task object is a work unit that Meshy keeps track of to generate a brick-style **concept image** from a source photo. The output of this stage is chained into [the build stage](#create-a-brick-figure-build-task) via `input_task_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-brick-figure-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `null`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `null`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `image_urls` · *array of strings* Downloadable URLs for the concept image candidates generated by this prototype task. Currently the API always returns exactly one candidate; the field is an array so future revisions can surface multiple candidates without a breaking change. **Example Brick Figure Prototype Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-brick-figure-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` --- ## The Brick Figure Build Task Object The Brick Figure Build Task object is a work unit that Meshy keeps track of to generate a textured **3D brick figure** from a succeeded prototype task. It runs the same image-to-3D pipeline used by [Image to 3D](/api/image-to-3d), so the output fields mirror that endpoint's [task object](/api/image-to-3d#the-image-to-3d-task-object). ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-brick-figure-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `prompt` · *string* Always empty for brick figure build. Present for cross-endpoint compatibility with the shared `V2ImageTo3DTaskResponse` shape used by [Image to 3D](/api/image-to-3d). - `negative_prompt` · *string* Always empty for brick figure build. Present for cross-endpoint compatibility. - `texture_prompt` · *string* Always empty for brick figure build. Present for cross-endpoint compatibility. - `texture_image_url` · *string* Always empty for brick figure build. Present for cross-endpoint compatibility. - `model_urls` · *object* Downloadable URLs for the generated 3D model. The brick figure build emits a textured GLB plus the OBJ + MTL pair for pipelines that prefer Wavefront OBJ. The field shape matches the [Image to 3D model_urls](/api/image-to-3d#the-image-to-3d-task-object) object so future format additions slot in without a breaking change. - `glb` · *string* Downloadable URL to the textured GLB file. - `obj` · *string* Downloadable URL to the Wavefront OBJ file (geometry + UV). - `mtl` · *string* Downloadable URL to the OBJ companion MTL material file. Pair with `obj` and the entry from `texture_urls[0].base_color`. - `thumbnail_url` · *string* Downloadable URL to the thumbnail image of the model file. - `texture_urls` · *array* An array of texture URL objects generated by this task. Currently contains a single object with the base color map. - `base_color` · *string* Downloadable URL to the base color map image. **Example Brick Figure Build Task Object** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-brick-figure-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 30, "prompt": "", "negative_prompt": "", "texture_prompt": "", "texture_image_url": "", "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.glb?Expires=***", "obj": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.obj?Expires=***", "mtl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/model.mtl?Expires=***" }, "thumbnail_url": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/preview.png?Expires=***", "texture_urls": [ { "base_color": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/texture_0.png?Expires=***" } ] } ``` --- # Creative Lab — Lamp API Source: https://docs.meshy.ai/api/creative-lab-lamp # Creative Lab — Lamp API Turn a text prompt or a source photo into a 3D-printable lampshade in two stages: **prototype** generates a stylized matte-white concept image, then **build** turns that concept image into a hollow STL lampshade (optionally paired with a base disk for a light-source fixture). The two stages are linked via `input_task_id`. - `POST /openapi/creative-lab/lamp/v1/prototype` - `POST /openapi/creative-lab/lamp/v1/build` --- ## POST /openapi/creative-lab/lamp/v1/prototype -- Create a Lamp Prototype Task Generate a single matte-white concept image for the lampshade — either from a text prompt (text-to-3D) or from a reference photo (image-to-3D). The returned task ID is what you pass as `input_task_id` to the build endpoint. Refer to [The Lamp Prototype Task Object](#the-lamp-prototype-task-object) for the response shape. ### Parameters > **Note:** Exactly one of `text` or `image_url` is **required**. Passing both, or neither, returns `400`. - `text` · *string* · **required** Text prompt describing the desired lampshade subject. Required when `image_url` is omitted. Maximum 800 characters. - `image_url` · *string* · **required** Source photo Meshy uses as the visual reference for the lampshade. Required when `text` is omitted. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `image_subject` · *string* · default: `character` Subject category hint for the image-to-3D path. Available values: * `character` (default) — single character / object subject (figurine, animal, mascot, etc.). * `landscape` — outdoor scene / panorama subject (mountain, cityscape, forest, etc.). Ignored on the text-to-3D path. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created lamp prototype task. Poll the [Get a Task](#retrieve-a-lamp-task) endpoint or subscribe to the [stream](#stream-a-lamp-task) until the task reaches `SUCCEEDED`, then pass that ID to the [build endpoint](#create-a-lamp-build-task) as `input_task_id`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: Exactly one of `text` or `image_url` is required. * **Both provided**: Passing both `text` and `image_url` is rejected — they are mutually exclusive. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW or intellectual property moderation. * **Text too long**: `text` exceeds 800 characters. * **Invalid `image_subject`**: Not one of `character` / `landscape`. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 1 (image-to-3D): generate a matte-white lampshade concept image curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "", "image_subject": "character" }' # Stage 1 (text-to-3D): generate from a text prompt curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "text": "a stylized owl perched on a tree branch under moonlight" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1 (image-to-3D): generate a matte-white lampshade concept image const payload = { image_url: "", image_subject: "character", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1 (image-to-3D): generate a matte-white lampshade concept image payload = { "image_url": "", "image_subject": "character", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "018a210d-8ba4-705c-b111-1f1776f7f578" } ``` --- ## POST /openapi/creative-lab/lamp/v1/build -- Create a Lamp Build Task Generate the final 3D-printable lampshade from a succeeded prototype task. The build runs an image-to-3D pipeline on the prototype's concept image, then post-processes the mesh through the lamp processor to hollow it, flatten the top, optionally cut a base, and (when a fixture preset is chosen) emit a separate base disk for the light source. Refer to [The Lamp Build Task Object](#the-lamp-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created with the same API key, must have reached `SUCCEEDED`, and must have produced exactly one candidate image. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/lamp/v1/prototype` and refuses any other source with `404`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. #### `options` Optional tuning parameters for the lampshade geometry. Every field has a sensible default — send only the ones you want to override. - `diameter_mm` · *number* · default: `80` Target maximum dimension of the lampshade bounding box, in millimeters. The mesh is uniformly scaled to fit. Range: `[50, 400]`. - `thickness_mm` · *number* · default: `1.5` Wall thickness of the hollow lampshade, in millimeters. Range: `(0, 10]`. - `cut_amount_percent` · *number* · default: `35` Percentage of the lampshade height to flatten at the top so the print can sit on the bed. Range: `[1, 100]`. - `light_source_preset` · *string* · default: `bambu_mh001_60mm` Light-source fixture preset that determines whether (and what) base disk to emit alongside the lampshade. Available values: * `bambu_mh001_60mm` (default) — emit a 60 mm base disk sized for a compatible light-source fixture. Result includes `model_urls.base_stl`. * `none` — no fixture, no base disk. `model_urls.base_stl` is omitted. - `fixture_offset_x_mm` · *number* · default: `0` Horizontal X-axis offset of the fixture cutout relative to the lampshade center, in millimeters. Only meaningful when `light_source_preset` ≠ `none`. Range: `[-80, 80]`. - `fixture_offset_z_mm` · *number* · default: `0` Vertical Z-axis offset of the fixture cutout relative to the lampshade bottom, in millimeters. Range: `[-80, 80]`. - `rotate_x_deg` · *number* · default: `0` Rotation around the X axis applied to the imported mesh before processing, in degrees. Range: `[-360, 360]`. - `rotate_y_deg` · *number* · default: `0` Rotation around the Y axis applied to the imported mesh before processing, in degrees. Range: `[-360, 360]`. - `rotate_z_deg` · *number* · default: `0` Rotation around the Z axis applied to the imported mesh before processing, in degrees. Range: `[-360, 360]`. - `include_result_json` · *boolean* · default: `false` When `true` and `output.format` is `zip`, includes the lamp processor's `result.json` (containing measured mesh metrics + the resolved option set) inside the bundle. Ignored when `output.format` is `stl`. #### `output` Optional wire-format selector. Defaults to `stl`. - `format` · *string* · default: `stl` Artifact bundle returned by the build. Available values: * `stl` (default) — returns the lampshade as `model_urls.lamp_stl`, plus `model_urls.base_stl` when `light_source_preset` ≠ `none`. * `zip` — packages every artifact the processor emits (`lamp.stl`, optional `base.stl`, optional `result.json`) into a single zip and returns it under `model_urls.bundle_zip`. ### Returns The `result` property of the response contains the task `id` of the newly created lamp build task. Poll the [Get a Task](#retrieve-a-lamp-task) endpoint or subscribe to the [stream](#stream-a-lamp-task) until the task reaches `SUCCEEDED`, then download the artifacts from `model_urls`. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` is required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidate**: The prototype task succeeded but produced no candidate image. * **Options out of range**: One of the `options` fields fell outside its allowed range or enum set. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` Insufficient credits to perform this task. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. **cURL** ```bash # Stage 2: chain build off a succeeded prototype task curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "options": { "diameter_mm": 120, "thickness_mm": 2, "light_source_preset": "bambu_mh001_60mm", "cut_amount_percent": 30 }, "output": { "format": "stl" } }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: chain build off a succeeded prototype task const payload = { input_task_id: "018a210d-8ba4-705c-b111-1f1776f7f578", options: { diameter_mm: 120, thickness_mm: 2, light_source_preset: "bambu_mh001_60mm", cut_amount_percent: 30, }, output: { format: "stl" }, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/lamp/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: chain build off a succeeded prototype task payload = { "input_task_id": "018a210d-8ba4-705c-b111-1f1776f7f578", "options": { "diameter_mm": 120, "thickness_mm": 2, "light_source_preset": "bambu_mh001_60mm", "cut_amount_percent": 30, }, "output": {"format": "stl"}, } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/lamp/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" } ``` --- ## GET /openapi/creative-lab/lamp/v1/(prototype|build)/:id -- Retrieve a Lamp Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Lamp Prototype Task Object](#the-lamp-prototype-task-object) and [The Lamp Build Task Object](#the-lamp-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the lamp task to retrieve. ### Returns The response contains the lamp task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '018a210d-8ba4-705c-b111-1f1776f7f578'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '019c320e-9a8f-7a1c-9c11-2a1876f8a9bb'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/lamp/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "018a210d-8ba4-705c-b111-1f1776f7f578" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/lamp/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-lamp-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` **Build Response** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-lamp-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 30, "model_urls": { "lamp_stl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/lamp.stl?Expires=***", "base_stl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/base.stl?Expires=***" } } ``` --- ## DELETE /openapi/creative-lab/lamp/v1/(prototype|build)/:id -- Delete a Lamp Task Cancel a lamp task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the lamp task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype/018a210d-8ba4-705c-b111-1f1776f7f578 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '018a210d-8ba4-705c-b111-1f1776f7f578' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "018a210d-8ba4-705c-b111-1f1776f7f578" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/lamp/v1/(prototype|build)/:id/stream -- Stream a Lamp Task Stream real-time updates for a lamp task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the lamp task to stream. ### Returns Returns a stream of [Lamp Prototype](#the-lamp-prototype-task-object) or [Lamp Build](#the-lamp-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/lamp/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/lamp/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/lamp/v1/build/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "progress": 0, "status": "PENDING" } event: message data: { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-lamp-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "task_error": null, "consumed_credits": 30, "model_urls": { "lamp_stl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/lamp.stl?Expires=***", "base_stl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/base.stl?Expires=***" } } ``` --- ## GET /openapi/creative-lab/lamp/v1/(prototype|build) -- List Lamp Tasks Retrieve a paginated list of your lamp tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `50` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the lamp prototype task object](#the-lamp-prototype-task-object) when listing `/prototype` or [the lamp build task object](#the-lamp-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/lamp/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/lamp/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-lamp-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ] ``` --- ## The Lamp Prototype Task Object The Lamp Prototype Task object is a work unit that Meshy keeps track of to generate a stylized matte-white **concept image** from either a text prompt or a source photo. The output of this stage is chained into [the build stage](#create-a-lamp-build-task) via `input_task_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-lamp-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Present when the task status is `PENDING`, `IN_PROGRESS`, or `SUCCEEDED`. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `image_urls` · *array of strings* Downloadable URLs for the concept image candidates generated by this prototype task. Currently the API always returns exactly one candidate; the field is an array so future revisions can surface multiple candidates without a breaking change. **Example Lamp Prototype Task Object** ```json { "id": "018a210d-8ba4-705c-b111-1f1776f7f578", "type": "creative-lab-lamp-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123456000, "started_at": 1729123460000, "finished_at": 1729123486000, "expires_at": 1729382686000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 6, "image_urls": [ "https://assets.meshy.ai/***/concept.png?Expires=***" ] } ``` --- ## The Lamp Build Task Object The Lamp Build Task object is a work unit that Meshy keeps track of to generate the final 3D-printable lampshade from a succeeded prototype task. The build runs an image-to-3D draft + texture pipeline on the prototype's concept image, then post-processes the mesh through the lamp processor to hollow, flatten, and (optionally) cut a fixture base. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-lamp-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. Returns `0` for `FAILED` tasks (credits are refunded on failure). - `model_urls` · *object* Downloadable URLs for the generated artifacts, keyed by artifact name. The set of keys depends on `output.format` and `options.light_source_preset`: - `lamp_stl` · *string* Downloadable URL to the lampshade `lamp.stl`. Present when `output.format` was `stl` (the default). - `base_stl` · *string* Downloadable URL to the fixture-base `base.stl`. Present when `output.format` was `stl` **and** `options.light_source_preset` was not `none`. Omitted when the fixture preset was `none`. - `bundle_zip` · *string* Downloadable URL to a zip bundle of every artifact the processor emits (`lamp.stl`, optional `base.stl`, and — when `options.include_result_json` is `true` — `result.json`). Present when `output.format` was `zip`. When `bundle_zip` is present, `lamp_stl` / `base_stl` are omitted. **Example Lamp Build Task Object** ```json { "id": "019c320e-9a8f-7a1c-9c11-2a1876f8a9bb", "type": "creative-lab-lamp-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1729123500000, "started_at": 1729123510000, "finished_at": 1729123535000, "expires_at": 1729382735000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 30, "model_urls": { "lamp_stl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/lamp.stl?Expires=***", "base_stl": "https://assets.meshy.ai/***/tasks/019c320e-9a8f-7a1c-9c11-2a1876f8a9bb/output/base.stl?Expires=***" } } ``` --- # Creative Lab — Keycap API Source: https://docs.meshy.ai/api/creative-lab-keycap # Creative Lab — Keycap API Turn a source photo into a full-color custom mechanical keyboard keycap in two stages: **prototype** generates a "finished keycap" design render from your input photo. Once you have confirmed that render, **build** turns it into a textured 3D keycap model in a single run — white-model generation, automatic seating and cutting on a calibrated default pose, full-model coloring, and final assembly all happen inside one build task. The two stages are linked via `input_task_id` plus `candidate_id`. - `POST /openapi/creative-lab/keycap/v1/prototype` - `POST /openapi/creative-lab/keycap/v1/build` > **Note:** Both `POST` endpoints require a paid subscription plan. Requests from > free-plan accounts are rejected with `402 Payment Required`. --- ## POST /openapi/creative-lab/keycap/v1/prototype -- Create a Keycap Prototype Task Generate a finished-keycap design render from the source photo. The task result carries an `image_urls` array (the display render of the finished keycap) and a parallel `candidate_ids` array; both hold a single entry. Call this endpoint again for another render if the result is not what you want — each call is billed separately. Pass the `candidate_id` together with the prototype task ID to the [build endpoint](#create-a-keycap-build-task). Refer to [The Keycap Prototype Task Object](#the-keycap-prototype-task-object) for the response shape. ### Parameters - `image_url` · *string* · **required** Source photo for Meshy to turn into keycap design images. We currently support `.jpg`, `.jpeg`, `.png`, and `.webp` formats. The format is detected by decoding the image data, **not** from the URL's file extension — a URL with no extension, or one that redirects, works as long as the bytes decode to a supported format. HTTP redirects are followed. EXIF orientation is normalized, so a rotated phone photo is used the way it looks. Limits: at least `32` pixels on each side, at most `178,956,970` pixels in total, and at most `20,000,000` bytes once downloaded. For a data URI the limit applies to the **decoded** bytes, so the source file itself may be up to that size — it is the base64 text that is about a third larger, which matters for your request body, not for this limit. A data URI must declare an `image/*` content type and `;base64`. There are two ways to provide the image: - **Publicly accessible URL**: A URL that is accessible from the public internet. - **Data URI**: A base64-encoded data URI of the image. Example of a data URI: `data:image/jpeg;base64,`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. ### Returns The `result` property of the response contains the task `id` of the newly created keycap prototype task. Poll the [Get a Task](#retrieve-a-keycap-task) endpoint or subscribe to the [stream](#stream-a-keycap-task) until the task reaches `SUCCEEDED`, then take the entry from `candidate_ids` and pass it, together with the task ID, to the [build endpoint](#create-a-keycap-build-task). ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `image_url` is required. * **Invalid image format**: The provided `image_url` is not a supported format (`.jpg`, `.jpeg`, `.png`, `.webp`). * **Image dimensions out of range**: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count. * **Unreachable URL**: The `image_url` could not be downloaded (404 or timeout). * **Invalid Data URI**: The base64 string is malformed. * **Content flagged**: The input image was flagged by NSFW moderation. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` The account is on the free plan (a paid plan is required to create tasks) or has insufficient credits. - `403 - Forbidden` The input image was flagged by intellectual property moderation. - `429 - Too Many Requests` You have exceeded your rate limit. - `500 - Internal Server Error` An unexpected server-side error occurred — for example the content-moderation service was unavailable, staging the input image failed, or the task could not be created. No task is created in this case, so retrying is safe. **cURL** ```bash # Stage 1: generate a finished-keycap design render curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "image_url": "" }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 1: generate a finished-keycap design render const payload = { image_url: "", }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 1: generate a finished-keycap design render payload = { "image_url": "", } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef" } ``` --- ## POST /openapi/creative-lab/keycap/v1/build -- Create a Keycap Build Task Generate the final textured 3D keycap model from a succeeded prototype task and one of its candidates. A single build task runs the whole pipeline end to end — white-model generation from the chosen design, automatic seating and cutting onto the keycap base using a calibrated default pose (no interactive adjustment needed), full-model coloring, and final assembly and export. A build typically takes **3–7 minutes**, toward the upper end when several builds run concurrently. Refer to [The Keycap Build Task Object](#the-keycap-build-task-object) for the response shape. ### Parameters - `input_task_id` · *string* · **required** The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created by the same Meshy account, must have reached `SUCCEEDED`, and must have produced at least one candidate. Prototype tasks created through the webapp are **not** accepted — the build endpoint accepts only prototype tasks produced by `POST /openapi/creative-lab/keycap/v1/prototype` and refuses any other source with `404`. - `candidate_id` · *string* · **required** The candidate to build, taken from the `candidate_ids` array of the succeeded prototype task. Must belong to that task; any other value is rejected with `400`. - `name` · *string* Optional task name for display purposes. Maximum 100 characters. #### `options` Optional geometry tuning. Every field has a calibrated default — send only the ones you want to override. - `base_model` · *string* · default: `cherry-mx-1x1-r1` The keycap base to build on. Currently the only available value is `cherry-mx-1x1-r1` — a standard Cherry MX profile 1u keycap. 3–5 additional mainstream standard sizes are planned; custom sizes are not supported. - `head_size_mm` · *number* · default: `23` Target size of the sculpted head, in millimeters: its longest dimension is scaled to this value. Range: `[10, 40]`. Values above roughly `32.9` may be reduced so the head still fits the base's protective footprint limit, so the delivered longest dimension can be smaller than requested. The applied value is not echoed back on the task object today — if you need to confirm the size you actually received, measure the bounding box of the `keycap-head` mesh in the downloaded model. - `vertical_offset_mm` · *number* · default: `0` Vertical offset applied to the head before it is seated on the base, in millimeters. Range: `[-5, 5]`. ### Returns The `result` property of the response contains the task `id` of the newly created keycap build task. Poll the [Get a Task](#retrieve-a-keycap-task) endpoint or subscribe to the [stream](#stream-a-keycap-task) until the task reaches `SUCCEEDED`, then download the artifacts from `model_urls.glb` and `model_urls.obj_zip`. > **Note:** Both the GLB and the OBJ bundle are exported at **real-world > millimeter scale**, with a **Y-up** coordinate system and the front of > the keycap facing **+Z**. ### Failure Modes - `400 - Bad Request` The request was unacceptable. Common causes: * **Missing parameter**: `input_task_id` and `candidate_id` are required. * **Invalid UUID**: The `input_task_id` is not a valid UUID. * **Parent not succeeded**: The referenced prototype task has not reached `SUCCEEDED` yet. * **No candidates**: The prototype task succeeded but produced no candidates. * **Unknown candidate**: `candidate_id` is not one of the input task's candidates. * **Options out of range**: One of the `options` fields fell outside its allowed range or enum set. - `401 - Unauthorized` Authentication failed. Please check your API key. - `402 - Payment Required` The account is on the free plan (a paid plan is required to create tasks) or has insufficient credits. - `404 - Not Found` The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build). - `429 - Too Many Requests` You have exceeded your rate limit. - `500 - Internal Server Error` An unexpected server-side error occurred — for example the content-moderation service was unavailable, staging the input image failed, or the task could not be created. No task is created in this case, so retrying is safe. **cURL** ```bash # Stage 2: build the chosen candidate into a 3D keycap curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build \ -X POST \ -H "Authorization: Bearer ${YOUR_API_KEY}" \ -H 'Content-Type: application/json' \ -d '{ "input_task_id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", "candidate_id": "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b", "options": { "base_model": "cherry-mx-1x1-r1", "head_size_mm": 23, "vertical_offset_mm": 0 } }' ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Stage 2: build the chosen candidate into a 3D keycap const payload = { input_task_id: "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", candidate_id: "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b", options: { base_model: "cherry-mx-1x1-r1", head_size_mm: 23, vertical_offset_mm: 0, }, }; try { const response = await axios.post( 'https://api.meshy.ai/openapi/creative-lab/keycap/v1/build', payload, { headers } ); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Stage 2: build the chosen candidate into a 3D keycap payload = { "input_task_id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", "candidate_id": "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b", "options": { "base_model": "cherry-mx-1x1-r1", "head_size_mm": 23, "vertical_offset_mm": 0, }, } response = requests.post( "https://api.meshy.ai/openapi/creative-lab/keycap/v1/build", headers=headers, json=payload, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "result": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af" } ``` --- ## GET /openapi/creative-lab/keycap/v1/(prototype|build)/:id -- Retrieve a Keycap Task Retrieve a prototype or build task given a valid task `id`. The URL path must match the task's stage — a build task fetched through `/prototype/:id` returns `404`, and vice versa. Refer to [The Keycap Prototype Task Object](#the-keycap-prototype-task-object) and [The Keycap Build Task Object](#the-keycap-build-task-object) for response shapes. ### Parameters - `id` · *path* Unique identifier for the keycap task to retrieve. ### Returns The response contains the keycap task object. The shape depends on which stage was requested. **cURL** ```bash # Prototype curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \ -H "Authorization: Bearer ${YOUR_API_KEY}" # Build curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` }; // Prototype const prototypeId = '019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef'; const proto = await axios.get( `https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/${prototypeId}`, { headers } ); console.log(proto.data); // Build const buildId = '019c9a52-7d18-7e2b-9f01-6e3b98c4d2af'; const build = await axios.get( `https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/${buildId}`, { headers } ); console.log(build.data); ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } # Prototype prototype_id = "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef" proto = requests.get( f"https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/{prototype_id}", headers=headers, ) proto.raise_for_status() print(proto.json()) # Build build_id = "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af" build = requests.get( f"https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/{build_id}", headers=headers, ) build.raise_for_status() print(build.json()) ``` **Prototype Response** ```json { "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", "type": "creative-lab-keycap-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1753142456000, "started_at": 1753142460000, "finished_at": 1753142516000, "expires_at": 1753401716000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 12, "image_urls": [ "https://assets.meshy.ai/***/design-1.png?Expires=***" ], "candidate_ids": [ "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b" ] } ``` **Build Response** ```json { "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af", "type": "creative-lab-keycap-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1753142600000, "started_at": 1753142610000, "finished_at": 1753143050000, "expires_at": 1753402250000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 50, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***", "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***" }, "process_image_urls": { "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***", "composite": "https://assets.meshy.ai/***/composite.png?Expires=***", "base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***" } } ``` --- ## DELETE /openapi/creative-lab/keycap/v1/(prototype|build)/:id -- Delete a Keycap Task Cancel a keycap task. If the task is still `PENDING`, the credits consumed at create-time are refunded. Tasks that are already `IN_PROGRESS` are cancelled without a refund (the worker may already be burning resources). Tasks that have already reached a terminal state (`SUCCEEDED`, `FAILED`, `CANCELED`) cannot be cancelled. The URL path must match the task's stage — `DELETE` on `/prototype/:buildId` returns `404`. ### Path Parameters - `id` · *path* Unique identifier for the keycap task to cancel. ### Returns Returns `204 No Content` on success with an empty body. ### Failure Modes - `400 - Bad Request` The task is already in a terminal state and cannot be cancelled. - `404 - Not Found` The task does not exist, belongs to a different user, or its stage does not match the URL path. - `500 - Internal Server Error` An unexpected server-side error occurred while cancelling. The task may or may not have been cancelled — re-read it to confirm before retrying. **cURL** ```bash curl --request DELETE \ --url https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const taskId = '019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { await axios.delete( `https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/${taskId}`, { headers } ) } catch (error) { console.error(error) } ``` ```python import requests task_id = "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef" headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.delete( f"https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/{task_id}", headers=headers, ) response.raise_for_status() ``` **Response** ```json // Returns 204 No Content on success (empty body). ``` --- ## GET /openapi/creative-lab/keycap/v1/(prototype|build)/:id/stream -- Stream a Keycap Task Stream real-time updates for a keycap task via Server-Sent Events (SSE). The URL path must match the task's stage — opening a stream at `/prototype/:buildId/stream` emits a single `event: error` payload with `status_code: 404` and closes the stream. ### Parameters - `id` · *path* Unique identifier for the keycap task to stream. ### Returns Returns a stream of [Keycap Prototype](#the-keycap-prototype-task-object) or [Keycap Build](#the-keycap-build-task-object) task objects as Server-Sent Events. For `PENDING` or `IN_PROGRESS` tasks, the response stream will only include the necessary `progress` and `status` fields. **cURL** ```bash curl -N https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript const response = await fetch( 'https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream', { headers: { Authorization: `Bearer ${YOUR_API_KEY}` } } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (line.startsWith('data:')) { const data = JSON.parse(line.slice(5)); console.log(data); if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(data.status)) { reader.cancel(); } } } } ``` ```python import requests import json headers = { "Authorization": f"Bearer {YOUR_API_KEY}", "Accept": "text/event-stream" } response = requests.get( 'https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream', headers=headers, stream=True ) for line in response.iter_lines(): if line: if line.startswith(b'data:'): data = json.loads(line.decode('utf-8')[5:]) print(data) if data['status'] in ['SUCCEEDED', 'FAILED', 'CANCELED']: break response.close() ``` **Response Stream** ```javascript // Error event example (wrong stage or task not found) event: error data: { "status_code": 404, "message": "Task not found" } // Message event examples illustrate task progress. // For PENDING or IN_PROGRESS tasks, the response stream will not include all fields. event: message data: { "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af", "progress": 0, "status": "PENDING" } event: message data: { "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af", "type": "creative-lab-keycap-build", "status": "SUCCEEDED", "progress": 100, "created_at": 1753142600000, "started_at": 1753142610000, "finished_at": 1753143050000, "expires_at": 1753402250000, "task_error": null, "consumed_credits": 50, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***", "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***" }, "process_image_urls": { "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***" } } ``` --- ## GET /openapi/creative-lab/keycap/v1/(prototype|build) -- List Keycap Tasks Retrieve a paginated list of your keycap tasks for a single stage. The URL path selects the stage — `/prototype` returns prototype tasks; `/build` returns build tasks. Tasks from the other stage are not included in either response. ### Path Parameters - `stage` · *path* · **required** Either `prototype` or `build`. The collection returns only tasks whose stage matches the URL — fetching `/prototype` never returns build tasks and vice versa. ### Query Parameters - `page_num` · *integer* · default: `1` Page number for pagination. - `page_size` · *integer* · default: `10` Page size limit. Maximum allowed is `100` items. - `sort_by` · *string* · default: `-created_at` Field to sort by. Available values: * `+created_at`: Sort by creation time in ascending order. * `-created_at`: Sort by creation time in descending order. ### Returns Returns a paginated list of the per-stage task object — either [the keycap prototype task object](#the-keycap-prototype-task-object) when listing `/prototype` or [the keycap build task object](#the-keycap-build-task-object) when listing `/build`. **cURL** ```bash # List prototype tasks curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" # List build tasks curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build?page_size=10 \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios' const headers = { Authorization: `Bearer ${YOUR_API_KEY}` } try { const { data } = await axios.get( 'https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype', { headers, params: { page_size: 10 } } ) console.log(data) } catch (error) { console.error(error) } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype", headers=headers, params={"page_size": 10}, ) response.raise_for_status() print(response.json()) ``` **Response (List Prototype Tasks)** ```json [ { "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", "type": "creative-lab-keycap-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1753142456000, "started_at": 1753142460000, "finished_at": 1753142516000, "expires_at": 1753401716000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 12, "image_urls": [ "https://assets.meshy.ai/***/design-1.png?Expires=***" ], "candidate_ids": [ "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b" ] } ] ``` --- ## The Keycap Prototype Task Object The Keycap Prototype Task object is a work unit that Meshy keeps track of to generate one **finished-keycap design image** from a source photo. The output of this stage is chained into [the build stage](#create-a-keycap-build-task) via `input_task_id` plus `candidate_id`. ### Properties - `id` · *string* Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should **not** make any assumptions about the format of the id. - `type` · *string* Type of the task. The value is `creative-lab-keycap-prototype`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. > **Note:** A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following > the [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) standard. > For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as `1693569600000`. This applies > to **all** timestamps in Meshy API. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be `0`. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be `0`. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. > **Note:** The value of this field is meaningful only if the task status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. A task that reaches `SUCCEEDED` is charged the full amount for its stage. A task that never gets created (a `4xx` at request time, including a moderation rejection) is not charged at all. A task that reaches `FAILED` returns `0` — the charge is refunded, including an asynchronous moderation block. Cancelling via `DELETE` refunds only while the task is still `PENDING`; a task already `IN_PROGRESS` stays charged, because the work has been spent. - `image_urls` · *array of strings* Downloadable URL of the finished-keycap design render — what the candidate looks like as a finished keycap. Holds a single entry; `image_urls[i]` corresponds to `candidate_ids[i]`. Empty until the task reaches `SUCCEEDED`. The URL is for display only; the build endpoint consumes `candidate_ids`, not these URLs. Same URL lifecycle as `model_urls`: signed, no `Authorization` header, valid until `expires_at`, and stable when the task is re-read. - `candidate_ids` · *array of strings* Opaque candidate identifiers, parallel to `image_urls`. Pass the entry matching your chosen design as the build request's `candidate_id`. Do **not** make any assumptions about the format of these ids. **Example Keycap Prototype Task Object** ```json { "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", "type": "creative-lab-keycap-prototype", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1753142456000, "started_at": 1753142460000, "finished_at": 1753142516000, "expires_at": 1753401716000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 12, "image_urls": [ "https://assets.meshy.ai/***/design-1.png?Expires=***" ], "candidate_ids": [ "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b" ] } ``` --- ## The Keycap Build Task Object The Keycap Build Task object is a work unit that Meshy keeps track of to generate the final textured 3D keycap from a succeeded prototype task and a chosen candidate. A single build runs the full pipeline — white-model generation, automatic seating and cutting, coloring, assembly, and export. ### Properties - `id` · *string* Unique identifier for the task. - `type` · *string* Type of the task. The value is `creative-lab-keycap-build`. - `name` · *string* The task name supplied when the task was created. Empty string if no name was provided. - `status` · *string* Status of the task. Possible values are one of `PENDING`, `IN_PROGRESS`, `SUCCEEDED`, `FAILED`, `CANCELED`. - `progress` · *integer* Progress of the task. If the task is not started yet, this property will be `0`. Once the task has succeeded, this will become `100`. - `created_at` · *timestamp* Timestamp of when the task was created, in milliseconds. - `started_at` · *timestamp* Timestamp of when the task was started, in milliseconds. - `finished_at` · *timestamp* Timestamp of when the task was finished, in milliseconds. - `expires_at` · *timestamp* Timestamp of when the task result expires, in milliseconds. - `preceding_tasks` · *integer* The count of preceding tasks. Meaningful only when status is `PENDING`. - `task_error` · *object* Error details for failed tasks. See [Errors](/api/errors#task-errors) for the full `task_error` object reference. - `consumed_credits` · *integer* The number of credits consumed by this task. A task that reaches `SUCCEEDED` is charged the full amount for its stage. A task that never gets created (a `4xx` at request time, including a moderation rejection) is not charged at all. A task that reaches `FAILED` returns `0` — the charge is refunded, including an asynchronous moderation block. Cancelling via `DELETE` refunds only while the task is still `PENDING`; a task already `IN_PROGRESS` stays charged, because the work has been spent. - `model_urls` · *object* Downloadable URLs for the generated model artifacts. Both the GLB and the OBJ bundle are exported at **real-world millimeter scale**, **Y-up**, with the front of the keycap facing **+Z**. Meshes are named `keycap-head` and `keycap-base`; when the base falls back to a pattern fill, a third mesh `keycap-base-interior` is also present for the stem cavity. Do not assume exactly two meshes. These are signed URLs: fetch them **without** an `Authorization` header. They stay valid until `expires_at`, which is 3 days after `finished_at`, and re-reading the task inside that window returns the identical URL rather than a freshly signed one. Download and store the files yourself before then — there is no way to refresh an expired link. - `glb` · *string* Downloadable URL to the final textured `model.glb`. - `obj_zip` · *string* Downloadable URL to a zip bundle containing `model.obj`, `model.mtl`, and the texture PNGs its MTL actually references. A solid-color base ships only `keycap-head.png`; a patterned base also ships `keycap-base.png`. - `process_image_urls` · *object* Downloadable URLs for intermediate process images, keyed by kind. Same URL lifecycle as `model_urls`: signed, no `Authorization` header, valid until `expires_at`, and stable when the task is re-read. Currently emitted kinds: * `head_design` — the chosen candidate's design image the build consumed (always present). * `composite` — the finished-keycap display render of the chosen candidate (present when available). * `base_canvas` — the painted keycap-base canvas (present when available). Treat the key set as open-ended; new kinds may be added without a breaking change. **Example Keycap Build Task Object** ```json { "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af", "type": "creative-lab-keycap-build", "name": "", "status": "SUCCEEDED", "progress": 100, "created_at": 1753142600000, "started_at": 1753142610000, "finished_at": 1753143050000, "expires_at": 1753402250000, "preceding_tasks": 0, "task_error": null, "consumed_credits": 50, "model_urls": { "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***", "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***" }, "process_image_urls": { "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***", "composite": "https://assets.meshy.ai/***/composite.png?Expires=***", "base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***" } } ``` --- ## End-to-End Example The complete flow: create a prototype from a photo, poll it to `SUCCEEDED`, pick a candidate from `candidate_ids`, create a build with that candidate, poll the build to `SUCCEEDED`, then download the GLB and the OBJ bundle from `model_urls`. The example picks the **first** candidate programmatically. In a real integration you would display the `image_urls` entry to the end user and let them choose; the chosen index maps 1:1 onto `candidate_ids`. **cURL** ```bash #!/usr/bin/env bash set -euo pipefail # Requires curl and jq. Point IMAGE_PATH at a local photo, or IMAGE_URL at a public one: # export MESHY_API_KEY=msy_... # export IMAGE_PATH=./portrait.jpg # or: export IMAGE_URL=https://... : "${MESHY_API_KEY:?export MESHY_API_KEY first}" if [[ -z "${IMAGE_PATH:-}" && -z "${IMAGE_URL:-}" ]]; then echo "export IMAGE_PATH (local file) or IMAGE_URL (public url) first" >&2 exit 1 fi BASE="https://api.meshy.ai/openapi/creative-lab/keycap/v1" AUTH="Authorization: Bearer $MESHY_API_KEY" # api METHOD URL [curl args...] -> prints the response body, non-zero on failure. # Note we do not use -f/--fail: it discards the body, and the body is the only # place the reason appears. api() { local method=$1 url=$2 out http_code body shift 2 out=$(curl --silent --show-error --max-time 60 --write-out $'\n%{http_code}' \ -X "$method" "$url" -H "$AUTH" "$@") || return 1 http_code=${out##*$'\n'} body=${out%$'\n'*} if ((http_code >= 400)); then echo "HTTP $http_code for $url: $body" >&2 return 1 fi printf '%s' "$body" } # Each task gets its own 40-minute budget. poll() { local kind=$1 id=$2 delay=5 task_status deadline deadline=$(($(date +%s) + 2400)) while :; do if (($(date +%s) >= deadline)); then echo "gave up waiting for $kind $id" >&2 return 1 fi task_status=$(api GET "$BASE/$kind/$id" | jq -r '.status') echo "$kind: $task_status" case "$task_status" in SUCCEEDED) return 0 ;; FAILED | CANCELED) return 1 ;; esac sleep "$delay" delay=$((delay * 2 > 30 ? 30 : delay * 2)) done } # Build the request body in a file. A base64 data URI must never go on the # command line or into an exported variable - a photo of any real size will # exceed the OS argument limit. BODY=$(mktemp) trap 'rm -f "$BODY"' EXIT if [[ -n "${IMAGE_PATH:-}" ]]; then # Declare the real type: the API accepts JPEG, PNG and WebP. case "$(printf '%s' "${IMAGE_PATH##*.}" | tr 'A-Z' 'a-z')" in png) MIME=image/png ;; webp) MIME=image/webp ;; *) MIME=image/jpeg ;; esac { printf '{"image_url":"data:%s;base64,' "$MIME" base64 <"$IMAGE_PATH" | tr -d '\n' printf '"}' } >"$BODY" else printf '{"image_url":"%s"}' "$IMAGE_URL" >"$BODY" fi # 1. Create the prototype task PROTO_ID=$(api POST "$BASE/prototype" \ -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result') # 2. Wait for the design render poll prototype "$PROTO_ID" # 3. Pick a candidate (first one here; show image_urls to a user in production) CANDIDATE_ID=$(api GET "$BASE/prototype/$PROTO_ID" | jq -r '.candidate_ids[0]') # 4. Create the build task jq -n --arg p "$PROTO_ID" --arg c "$CANDIDATE_ID" \ '{input_task_id: $p, candidate_id: $c}' >"$BODY" BUILD_ID=$(api POST "$BASE/build" \ -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result') # 5. Wait for the model (a build usually takes 3-7 minutes) poll build "$BUILD_ID" # 6. Download the artifacts. These are signed URLs: no Authorization header, # and they stay valid for 3 days after the task finishes. TASK=$(api GET "$BASE/build/$BUILD_ID") curl --silent --show-error --fail --max-time 900 \ -o keycap.glb "$(jq -r '.model_urls.glb' <<<"$TASK")" curl --silent --show-error --fail --max-time 900 \ -o keycap-obj.zip "$(jq -r '.model_urls.obj_zip' <<<"$TASK")" echo "Done: keycap.glb + keycap-obj.zip" ``` ```python # Requires the requests package: pip install requests import base64 import os import time import requests BASE = "https://api.meshy.ai/openapi/creative-lab/keycap/v1" REQUEST_TIMEOUT = 60 # per HTTP call TASK_DEADLINE = 2400 # give up on a single task after 40 minutes def env(name: str) -> str: value = os.environ.get(name) if not value: raise SystemExit(f"set {name} before running") return value # Point IMAGE_PATH at a local photo, or IMAGE_URL at a public one: # export MESHY_API_KEY=msy_... # export IMAGE_PATH=./portrait.jpg # or: export IMAGE_URL=https://... HEADERS = {"Authorization": f"Bearer {env('MESHY_API_KEY')}"} def source_image() -> str: path = os.environ.get("IMAGE_PATH") if path: # Encode here, in the process. A base64 data URI passed on a command # line or through an exported variable will exceed the OS argument # limit for a photo of any real size. # Declare the real type: the API accepts JPEG, PNG and WebP. mime = {"png": "image/png", "webp": "image/webp"}.get( os.path.splitext(path)[1].lower().lstrip("."), "image/jpeg") with open(path, "rb") as f: return f"data:{mime};base64," + base64.b64encode(f.read()).decode() if not os.environ.get("IMAGE_URL"): raise SystemExit("set IMAGE_PATH (local file) or IMAGE_URL (public url) first") return os.environ["IMAGE_URL"] def check(resp: requests.Response) -> dict: # raise_for_status()'s message omits the response body, and the body is # where the reason is. if not resp.ok: raise RuntimeError(f"HTTP {resp.status_code} for {resp.url}: {resp.text[:500]}") return resp.json() def poll(stage: str, task_id: str) -> dict: deadline = time.monotonic() + TASK_DEADLINE delay = 5 while True: if time.monotonic() > deadline: raise TimeoutError(f"gave up waiting for {stage} {task_id}") data = check(requests.get(f"{BASE}/{stage}/{task_id}", headers=HEADERS, timeout=REQUEST_TIMEOUT)) print(f"{stage}: {data['status']} ({data['progress']}%)") if data["status"] == "SUCCEEDED": return data if data["status"] in ("FAILED", "CANCELED"): raise RuntimeError( f"{stage} task {task_id} ended as {data['status']}: {data['task_error']}") time.sleep(delay) delay = min(delay * 2, 30) # 1. Create the prototype task prototype_id = check(requests.post( f"{BASE}/prototype", headers=HEADERS, json={"image_url": source_image()}, timeout=REQUEST_TIMEOUT, ))["result"] # 2. Wait for the design render prototype = poll("prototype", prototype_id) # 3. Pick a candidate (first one here; show image_urls to a user in production) candidate_id = prototype["candidate_ids"][0] # 4. Create the build task build_id = check(requests.post( f"{BASE}/build", headers=HEADERS, json={"input_task_id": prototype_id, "candidate_id": candidate_id}, timeout=REQUEST_TIMEOUT, ))["result"] # 5. Wait for the model (a build usually takes 3-7 minutes) build = poll("build", build_id) # 6. Download the artifacts. These are signed URLs: no Authorization header, # and they stay valid for 3 days after the task finishes. for key, filename in (("glb", "keycap.glb"), ("obj_zip", "keycap-obj.zip")): with requests.get(build["model_urls"][key], stream=True, timeout=(60, 900)) as dl: if not dl.ok: raise RuntimeError(f"download {key} failed: HTTP {dl.status_code}") with open(filename, "wb") as f: for chunk in dl.iter_content(chunk_size=1 << 20): f.write(chunk) print(f"Saved {filename}") ``` --- # Balance API Source: https://docs.meshy.ai/api/balance # Balance API The Balance API allows you to retrieve the current credit balance for your account. This endpoint provides a simple way to check your available credits, which are used for various Meshy services. --- ## GET /openapi/v1/balance -- Get Balance This endpoint retrieves the current credit balance for the authenticated user. ### Returns Returns an object containing the current balance of credits. **cURL** ```bash curl https://api.meshy.ai/openapi/v1/balance \ -H "Authorization: Bearer ${YOUR_API_KEY}" ``` ```javascript import axios from 'axios'; const headers = {Authorization: `Bearer ${YOUR_API_KEY}`}; try { const response = await axios.get('https://api.meshy.ai/openapi/v1/balance', {headers}); console.log(response.data); } catch (error) { console.error(error); } ``` ```python import requests headers = { "Authorization": f"Bearer {YOUR_API_KEY}" } response = requests.get( "https://api.meshy.ai/openapi/v1/balance", headers=headers, ) response.raise_for_status() print(response.json()) ``` **Response** ```json { "balance": 1000 } ``` --- # Animation Library Source: https://docs.meshy.ai/api/animation-library # Animation Library Reference This page provides a comprehensive reference of all available animations in Meshy's [Animation API](/api/animation). Each animation is identified by a unique `action_id` that can be used when creating animation tasks. ## Available Animations Below is a complete list of animations available for use with the [Animation API](/api/animation). Use the `action_id` value when creating an animation task with the [`POST /openapi/v1/animations`](/api/animation#create-an-animation-task) endpoint. > The full list of available animations (with `action_id`, name, category, preview URL) is served as JSON at https://api.meshy.ai/web/public/animations/resources — fetch it directly to retrieve the current catalog. ## Usage Example To apply an animation to your rigged character, use the action_id in your API request: ```javascript const payload = { rig_task_id: "YOUR_RIGGING_TASK_ID", action_id: 92, // Double Combo Attack animation }; // Send this payload to the POST /openapi/v1/animations endpoint ``` For more details on how to create animation tasks, see the [Animation API documentation](/api/animation#create-an-animation-task). --- --- # Webapp & Platform Documentation # Meshy Documentation Source: https://docs.meshy.ai # Meshy Documentation Welcome to the official Meshy documentation. Learn how to create production-ready 3D assets from text, images, and conversations — in the web app, inside your 3D tools and printing software, or programmatically with the API. --- ## What is Meshy? Meshy is an AI-powered 3D modeling platform that transforms text descriptions, 2D images, and conversational prompts into production-ready 3D assets. Whether you're a game developer prototyping characters, a 3D artist exploring concepts, a maker creating custom gifts, or a hobbyist building models for 3D printing, Meshy provides an end-to-end workflow from generation to post-processing to export. The platform is built around our latest web-based workspace, which organizes all tools into six modules: Image, 3D Model, 3D Printing, Animate, Scene, and Video. In addition, Meshy 3D Agent introduces a conversational workflow that lets you brainstorm, explore, and create 3D models through a single chat. Through the [API](/api), every generation capability is available as a REST endpoint for developers wanting to build at scale — with an [API Playground](/api/playground) for testing and an [MCP server](/api/ai) for connecting AI agents directly. --- ## Choose Your Path You can use Meshy in four ways, all backed by the same generation models and your Meshy account — each has its own section in these docs. Generate and export 3D assets in your browser in seconds — no setup required. Build 3D generation at scale into your own products and pipeline. Use Meshy directly inside Unity, Blender, Maya and more. Go from 3D generated model to print-ready file in seconds. --- ## Platform Overview **Generation Models** | Model | Release | Best For | Speed | Quality | | ------- | ------- | ----------------------------------- | ------- | ------- | | Smart Topology | 2026 | Optimized for game development and real-time rendering | ~10 sec | ★★★★★ | | Meshy 6 | 2025 | Final assets, production quality | ~2 min | ★★★★★ | | Meshy 5 | 2024 | Fast iteration, concept exploration | ~45 sec | ★★★★☆ | **Supported Export Formats** | Format | Use Case | Includes Textures | | ------ | --------------------------- | ----------------- | | GLB | Web, AR, universal exchange | ✅ Embedded | | FBX | Unity, Unreal, DCC tools | ✅ Separate files | | OBJ | Legacy workflows, DCC tools | ✅ MTL + textures | | STL | 3D printing | ❌ Geometry only | | USDZ | Apple AR Quick Look | ✅ Embedded | | 3MF | 3D printing (color) | ✅ Embedded | --- ## FAQ ### What is Meshy used for? Meshy is an AI 3D model generator that turns text, images, and chat prompts into production-ready 3D assets for games, AR/VR, 3D printing, and design. ### Is Meshy free to use? Yes. Meshy offers a free plan with 100 credits per month — no credit card required — so you can generate models before upgrading. ### Do I need 3D modeling experience to use Meshy? No. Meshy automates mesh, texture, and rigging generation, and the 3D Agent guides beginners from idea to finished model through chat. ### Does Meshy offer an API? Yes. The Meshy API provides REST endpoints for Text to 3D, Image to 3D, texturing, remeshing, and animation, along with an API Playground for no-code testing and an MCP server for AI-agent integration. ### What can I create with Meshy? Characters, props, environment objects, vehicles, figurines, and product models — from game assets to 3D-printable miniatures. ### What file formats can I export from Meshy? Meshy exports GLB, FBX, OBJ, STL, USDZ, and 3MF, covering game engines, 3D printing, AR, and DCC tools. --- # 3D Agent Source: https://docs.meshy.ai/webapp/3d-agent # 3D Agent Meshy 3D Agent is the world's first AI agent built for 3D creation — a chat-to-3D workflow that takes you from idea to downloadable 3D model through conversation. Start with a photo, sketch, description, story, or creative direction. The agent guides you through brainstorming, batch visual concept generation, and 3D creation — all within a single conversation. --- ## TL;DR - Meshy 3D Agent is the world's first AI agent built for 3D creation — a chat-to-3D workflow. - Start with a photo, sketch, description, story, or creative direction; the agent guides you from idea to downloadable 3D model. - Four core capabilities: brainstorming, batch visual concept generation, chat-to-3D creation, and built-in 3D creation knowledge. - Unlike traditional text-to-3D tools that produce one output from one prompt, 3D Agent supports a multi-step creative process within a single conversation. - Currently in Beta — deeper DCC/slicer integration is on the roadmap. --- ## When to Use - You have a vague idea and want help exploring creative directions before generating. - You want to generate multiple visual concepts in one session and select the best to convert to 3D. - You're a maker with a custom idea (pet photo, child's drawing, gift concept) and want guided 3D creation. - You're an indie game developer who needs a batch of style-consistent assets for a cohesive world. - You have 3D creation or 3D printing questions and want answers within the creation workflow. --- ## When NOT to Use - You have a clear reference image and need precise single-image-to-3D conversion → Use [Image to 3D](/webapp/image-to-3d) - You have a well-defined prompt and want a quick single generation → Use [Text to 3D](/webapp/text-to-3d) - You need API-level programmatic batch generation → Use API - You need to edit an existing 3D model → 3D Agent Beta does not currently support direct 3D editing --- ## How 3D Agent Works The 3D Agent introduces a conversational workflow that keeps more of the creative process inside one chat: ``` Idea / Input → Brainstorm → Visual Concepts (batch) → Refine → 3D Generation → Download ``` **Step 1: Start a conversation** Open [3D Agent](/webapp/3d-agent) and describe what you want to create. You can start with: - A text description: "I want to create a set of fantasy potion bottles for my RPG game" - A photo: Upload a pet photo, product image, or sketch - A story or scenario: "My daughter drew a dragon — I want to turn it into a 3D printed figurine" - A creative direction: "Cyberpunk props with neon accents and weathered metal" **Step 2: Brainstorm and explore** The agent suggests creative directions, asks clarifying questions, and helps you refine your concept. Unlike a single-prompt tool, you can: - Compare different artistic approaches - Ask practical questions about 3D creation or printing - Refine your direction through back-and-forth conversation **Step 3: Generate batch visual concepts** The agent generates multiple visual concepts in one session. You can: - Request specific quantities: "Show me 6 variations" - Guide style consistency: "Keep the same art direction as the first batch" - Mix and match: "I like the shape from concept 2 and the colors from concept 5" **Step 4: Select and convert to 3D** Choose your favorite concepts and the agent converts them into downloadable 3D models. Selected models can then enter the standard Meshy post-processing pipeline (Remesh, AI Texturing, Rigging, etc.). **Step 5: Download and use** Export the 3D model in your desired format for use in games, 3D printing, e-commerce, or other creative workflows. --- ## Key Capabilities **Brainstorming for 3D Creation** The agent can suggest creative directions before you generate anything. This is particularly valuable when you know what category of object you need (e.g., "game props") but haven't decided on specific designs. **Batch Visual Concept Generation** Instead of generating one output per prompt, explore multiple concepts in a single conversation. The agent can maintain style consistency across batches, which is critical for creating asset sets that belong to the same world. **Chat-to-3D Creation** Selected visual concepts are turned into downloadable 3D models for use in creative, printing, or production workflows — all within the same conversation. **Built-in 3D Creation Knowledge** Ask questions about 3D creation and 3D printing directly in the chat. The agent can advise on topics like wall thickness for printing, polygon budgets for different platforms, or how to prepare models for specific slicers. **In-chat Rigging and Animation** For the generated 3D models, the agent can direct users to Rigging section, and automatically suggest different animations like walking, running, or custom motions. --- ## Use Case: Custom 3D Printing Gift A common gap for 3D printing makers: they know how to print, but don't know how to model a custom object from scratch. 1. Start with a pet photo, a child's drawing, a name, a story, or a gift idea. 2. The agent explores custom 3D concepts through conversation. 3. Select a concept and generate a 3D model. 4. Download STL/3MF and proceed to slicer → print. > **Note:** Users should still review geometry, scale, wall thickness, and slicer settings before printing. --- ## Use Case: Style-Consistent Game Asset Batches A common challenge for indie developers: creating not just one asset, but a consistent set that feels like it belongs to the same world. 1. Describe a visual direction: "Low-poly medieval fantasy, warm color palette, hand-painted look." 2. The agent generates batches of props, characters, or environment concepts. 3. Select favorites, request variations, ensure consistency. 4. Convert to 3D and export for your engine. --- ## Settings & Tradeoffs | Factor | 3D Agent | Text to 3D | Image to 3D | | --- | --- | --- | --- | | Input flexibility | Text, images, sketches, stories | Text only | Images only | | Multi-step process | ✅ Continuous conversation | ❌ Single prompt | ❌ Single upload | | Batch concept exploration | ✅ Multiple concepts | ❌ One at a time | ❌ One at a time (or Batch) | | Style consistency | ✅ Maintained in conversation | Manual prompt consistency | Depends on input images | | Speed (single model) | Slower (includes brainstorming) | Faster | Faster | | Precision | Good for concepts | Good for known prompts | Best for visual matching | | Built-in Q&A | ✅ Ask 3D questions in chat | ❌ | ❌ | --- ## Roadmap Future updates are expected to: - Bring deeper connections to DCC and slicing tools. - Make references and inspiration easier to access without leaving the conversation. - Further improve style consistency and batch generation quality. --- ## Troubleshooting | Symptom | Cause | Fix | | --- | --- | --- | | Agent doesn't understand my request | Description too vague | Be more specific about what you want to create, the style, and the intended use | | Batch concepts lack consistency | Style direction not clear enough | Provide a clear art direction upfront; reference specific styles or moods | | Generated 3D model differs from selected concept | Normal variation in 2D-to-3D conversion | Use Image to 3D with the concept image for closer matching | | Agent can't edit my uploaded model | Editing not supported in Beta | Use standard post-processing tools (Remesh, AI Texturing) instead | --- ## FAQ ### What is Meshy 3D Agent? Meshy 3D Agent is an AI agent for 3D creation that helps users brainstorm ideas, generate visual concepts in batches, ask 3D creation questions, and turn selected concepts into 3D models through a conversational workflow. ### How is Meshy 3D Agent different from a text-to-3D tool? Traditional text-to-3D tools typically generate one output from one prompt. Meshy 3D Agent supports a multi-step, chat-based workflow where users can explore directions, refine ideas, generate multiple concepts, and move selected results toward 3D output in one conversation. ### Is Meshy 3D Agent the same as ChatGPT for 3D? Meshy 3D Agent brings a conversational AI experience to 3D creation, but it is not a general chat interface. It is built specifically for 3D workflows — brainstorming, visual concept generation, 3D creation Q&A, and converting ideas into 3D models. ### Who is Meshy 3D Agent built for? 3D printing makers, indie game developers, 3D artists, designers, and creators who want a faster way to move from idea to 3D creation. ### Can Meshy 3D Agent be used for 3D printing? Yes. 3D Agent can help users create custom 3D concepts that can move into a 3D printing workflow. Users should still review geometry, scale, wall thickness, and slicer settings before printing. ### Can Meshy 3D Agent generate 3D assets for games? Yes. 3D Agent can help indie developers and creators explore batches of 3D asset concepts with a consistent creative direction. Depending on the final use case, users may need to optimize, polish, or adapt outputs before using them in production game projects. ### Can Meshy 3D Agent edit existing 3D models? Not in the current Beta. 3D Agent is designed to help users brainstorm, generate, refine through chat, and create 3D outputs from ideas, images, or descriptions. For editing existing models, use the standard post-processing tools (Remesh, AI Texturing, Rigging, Stylize). --- # Changelog Source: https://docs.meshy.ai/webapp/changelog # Changelog See all of the latest features and updates to the Meshy webapp. --- ## June 2026 ### 3D Agent Released [Meshy 3D Agent](/webapp/3d-agent) (Beta), the world's first AI agent for 3D creation. The Beta covers: - End-to-end creation in one conversation: brainstorming, batch visual concept generation, model generation with 4K textures, and export to DCC tools or slicers. - Web search for reference images, with results directly usable in generation. - A built-in knowledge base that answers your 3D creation questions. - Read-only conversation sharing via link, no login required. ### Creative Lab - Added two new categories: Twist Egg and Golden Boot Keychain. - Creations are now automatically saved to the asset panel and can be resumed for further editing. ### DCC Integrations - Added a [ZBrush plugin](/webapp/plugins/zbrush/introduction) that sends models from the Meshy workspace to ZBrush in one click as clean OBJ geometry. --- # Core Concepts Source: https://docs.meshy.ai/webapp/concepts # Core Concepts The foundational 3D concepts behind Meshy — mesh, textures, topology, UV mapping, and rigging — and how they connect in one workflow. --- ## TL;DR - A mesh is the skeleton of a 3D model, composed of vertices, edges, and faces. Polygon count directly affects performance and quality. - Textures add color and surface detail. PBR textures include Albedo, Normal, Roughness, and Metallic maps. - Topology describes how faces are arranged. Good topology = animatable + deformable + efficient rendering. - UV Mapping is the process of unwrapping a 3D surface into 2D space, determining how textures are applied to the model. - Rigging binds a bone/skeleton system to a model, enabling animation. ![Meshy workspace showing a generated 3D model with its topology details — triangle mesh, face and vertex counts — alongside printability check and generation settings](https://cdn.meshy.ai/webapp-assets/doc/core-concepts-p1-1.webp) --- ## Glossary Quick Reference | Term | Definition | | --- | --- | | Mesh | 3D geometry composed of vertices, edges, and faces | | Polygon Count | Number of faces in a model. Game assets typically < 50K; film can reach millions | | PBR Textures | Physically Based Rendering maps: Albedo, Normal, Roughness, Metallic | | Topology | Arrangement and flow of faces. "Clean topology" = even quads following structure | | UV Mapping | Unwrapping a 3D surface to 2D space so textures map correctly | | Rigging | Binding a bone/skeleton system to a model for animation | | Normal Map | RGB texture simulating surface bumps without adding geometry | | LOD | Level of Detail — different resolution models for different viewing distances | | Watertight Mesh | A closed mesh with no holes — required for 3D printing | | GLB/GLTF | Open 3D file formats, the standard for web and real-time rendering | | FBX | Autodesk format, the primary exchange format for game engines (Unity/Unreal) | | STL | Geometry-only format, the standard input for 3D printing | | USDZ | Apple's AR format for Quick Look and Reality Composer | --- ## How These Concepts Connect in Meshy The Meshy workflow moves through these concepts in sequence: 1. **Generation** (Text/Image/Chat → Mesh + Texture): AI creates a mesh and applies initial textures. 2. **AI Texturing** (Mesh → PBR Textures): Optionally re-generate or enhance textures with PBR maps. 3. **Remesh** (Mesh → Optimized Mesh): Reduce or optimize polygon count while preserving shape. 4. **Unwrap UV** (Mesh → UV Layout): Generate clean UV maps for custom texture workflows. 5. **Rigging** (Mesh → Skeleton + Mesh): Bind a bone structure for animation. 6. **Export** (All → Target Format): Package mesh + textures + rig into your chosen format. --- ## FAQ ### What is a mesh in 3D modeling? A mesh is the geometric structure of a 3D model, made of vertices, edges, and faces. Polygon count affects both quality and performance. ### What are PBR textures? PBR (Physically Based Rendering) textures simulate real-world light using Albedo, Normal, Roughness, and Metallic maps for realistic surfaces. ### What is topology and why does it matter? Topology is how faces are arranged on a mesh. Clean topology is essential for smooth animation, deformation, and efficient rendering. ### What is UV mapping? UV mapping unwraps a 3D surface into 2D space so textures apply correctly without seams or stretching. ### What is rigging in 3D? Rigging adds a bone/skeleton system to a model so it can be posed and animated. Meshy auto-rigs humanoid and quadruped models. --- ## Related Links - [Glossary](/webapp/glossary) — Complete A–Z terminology reference - [Quick Start](/webapp/getting-started) — Put these concepts into practice - [AI Texturing](/webapp/guides/3d-model/ai-texturing) — Deep dive into PBR texture generation --- # Meshy Webapp Documentation Source: https://docs.meshy.ai/webapp/getting-started # Meshy Webapp Documentation Generate your first 3D model in minutes — using an image or a text prompt — then export it for any creative workflow. --- ## TL;DR - Sign up and get free credits immediately — no credit card required. - The fastest path: upload an image to [Image to 3D](/webapp/image-to-3d) — get a 3D model in under 2 minutes. - [Text to 3D](/webapp/text-to-3d) works best when you don't have a reference image — describe in natural language. - [3D Agent](/webapp/3d-agent) lets you brainstorm and create through a chat conversation. - Post-processing pipeline: AI Texturing → Remesh → Rigging → Export. - All generated results are saved in My Models for download and further editing. --- ## When to Use This Guide - You just signed up for Meshy and want to experience the core features quickly. - You want to learn the shortest path from "input" to "usable 3D asset." > **Note:** **When NOT to use this guide:** If you need API integration, see the API Quick Start. If you prefer a conversational workflow, go to [3D Agent](/webapp/3d-agent). --- ## Step-by-Step: Your First 3D Model 1. **Create your account** — Visit [meshy.ai](https://www.meshy.ai/) and sign up with Google or email. You'll receive free credits upon registration. 2. **Choose your generation method** - **Image to 3D** (recommended for beginners): Click "Image to 3D" in the left sidebar. Upload a clear photo or concept art of your subject. Select Meshy 6 as the model. - **Batch Images to 3D**: Click "Batch Images to 3D" in the left sidebar. Upload a group of images and turn them all to 3D at once. - **Text to 3D**: Click "Text to 3D" in the left sidebar. Describe your object in detail (e.g., "a medieval wooden treasure chest with iron bands and a rusty padlock"). 3. **Configure and generate** — Select output quality (Standard or Smart Topology), enable Image Enhancement if your input image quality is low, and click "Generate." Generation takes approximately 1–2 minutes with Meshy 6. 4. **Review your result** — The 3D viewer lets you rotate, zoom, and inspect your model from all angles. Check mesh quality, texture detail, and overall accuracy. 5. **Post-process (optional)** - **AI Texturing**: Re-texture your model with different styles or generate PBR maps. - **Remesh**: Optimize polygon count for your target platform (game engine, 3D printing, etc.). - **Rigging**: Auto-rig humanoid or quadruped models for animation. 6. **Export** — Click "Download" and select your desired format: GLB for web/AR, FBX for game engines, STL for 3D printing, OBJ for DCC tools. --- ## Examples **Success Example**: A clear front-facing photo of a ceramic mug → Meshy 6, Standard quality → Clean mesh with accurate handle, smooth surface, PBR textures applied. **Common Pitfall**: A blurry, low-contrast photo with complex background → Generated model captures background noise, distorted geometry. **Fix**: Use AI Background Removal first, or provide a cleaner input image. --- ## Troubleshooting | Symptom | Cause | Fix | | --- | --- | --- | | Generation stuck at 0% | Server queue full | Wait 1–2 minutes and retry; check [status.meshy.ai](https://status.meshy.ai) | | Model has holes/missing parts | Input image shows only partial view | Use multi-view images or provide additional angles | | Textures look blurry | Low-res input image | Enable Image Enhancement or provide a higher-res image | | Export file is empty | Generation did not complete | Re-generate and wait for "Complete" status before export | --- ## FAQ ### How do I create my first 3D model in Meshy? Sign up at meshy.ai, open Image to 3D or Text to 3D, upload an image or enter a prompt, select Meshy 6, and click Generate. ### How long does it take to generate a 3D model? About 1–2 minutes with Meshy 6 and around 45 seconds with Meshy 5. ### Should I start with Text to 3D or Image to 3D? Use Image to 3D if you have a reference photo (most accurate for beginners); use Text to 3D when you only have an idea in mind. ### Do I need a credit card to start? No. You get free credits as soon as you sign up with Google or email. ### Where are my generated models saved? Every result is saved automatically in My Models, where you can preview, post-process, and download it anytime. --- # Glossary Source: https://docs.meshy.ai/webapp/glossary # Glossary Complete 3D terminology reference, sorted alphabetically. Each term includes a definition and its specific connection to Meshy. --- ## A **Albedo Map**: The base color texture of a 3D model, without lighting or shadow information. In Meshy, Albedo maps are generated as part of the PBR texture set via AI Texturing. --- ## F **FBX**: A proprietary Autodesk file format widely used for 3D asset exchange between game engines (Unity, Unreal) and DCC tools. Meshy exports FBX with embedded textures and optional rig data. --- ## G **GLB / GLTF**: Open standard 3D file formats. GLB is the binary version (single file, embedded textures). GLTF is the JSON version (multiple files). GLB is Meshy's recommended format for web and AR use. --- ## L **Low Poly**: A 3D modeling style using minimal polygons, popular in games and stylized art. Meshy's Smart Topology mode in Text to 3D and Image to 3D generates optimized low-poly meshes. --- ## M **Mesh**: The geometric structure of a 3D model, composed of vertices, edges, and faces. Meshy generates meshes automatically from text, image, or conversation input. **Metallic Map**: A PBR texture map that defines which parts of a surface are metallic (white) vs non-metallic (black). Generated by AI Texturing with "Generate PBR Textures" enabled. --- ## N **Normal Map**: A texture that simulates surface detail without adding geometry. Uses RGB values to encode surface direction. Meshy generates normal maps as part of the PBR texture set. --- ## P **PBR (Physically Based Rendering)**: A rendering approach that simulates real-world light interaction. Uses Albedo + Normal + Roughness + Metallic maps. Meshy's AI Texturing generates complete PBR texture sets. **Polygon Count**: The number of faces in a mesh. Lower counts = better performance. Meshy's Remesh tool lets you target specific polygon counts. --- ## R **Remesh**: The process of regenerating a model's mesh topology. In Meshy, Remesh optimizes polygon count and ensures watertight geometry. **Rigging**: The process of adding a bone/skeleton system to a mesh for animation. Meshy supports automatic rigging for humanoid and quadruped models. **Roughness Map**: A PBR texture defining surface smoothness. Black = smooth/glossy, white = rough/matte. Generated by AI Texturing. --- ## S **Smart Topology**: A generation mode that outputs clean, game-ready geometry with native part segmentation and poly-count control (100–15,000 polygons). Available in Text to 3D and Image to 3D. **STL**: A file format that stores only geometry (no color/texture). The standard format for 3D printing. Meshy exports STL for FDM/SLA printing. --- ## T **Topology**: The arrangement and flow of polygons on a mesh surface. Clean topology (even quads following surface contours) is essential for animation and deformation. --- ## U **USD / USDZ**: Universal Scene Description format by Pixar. USDZ is the compressed version used by Apple for AR Quick Look. Meshy exports USDZ for Apple AR compatibility. **UV Mapping**: The process of projecting a 3D surface onto a 2D plane for texture application. Meshy's Unwrap UV tool generates automatic UV layouts. --- ## W **Watertight Mesh**: A closed mesh with no holes or open edges. Required for 3D printing. Meshy's Remesh tool can produce watertight output. --- ## Related Links - [Export & File Formats](/webapp/guides/platform/export-formats) - [AI Texturing](/webapp/guides/3d-model/ai-texturing) - [Remesh](/webapp/guides/3d-model/remesh) - [Unwrap UV](/webapp/guides/3d-model/unwrap-uv) - [Rigging](/webapp/guides/3d-model/rigging) --- # Image to 3D Source: https://docs.meshy.ai/webapp/image-to-3d # Image to 3D Upload an image and Meshy's AI generates a textured 3D model that matches your visual reference — more precise than text prompts alone. --- ## TL;DR - Upload an image, and AI generates a corresponding 3D model with textures. - Two model types: Standard for maximum detail and Smart Topology for optimized, game-ready meshes. - Rich control parameters: Image Enhancement, Multi-view Images to 3D, Pose control. - More precise than [Text to 3D](/webapp/text-to-3d) — a visual reference gives AI a clear generation target. - License options: CC BY 4.0 (Free plan) or Private (Pro and above). --- ## When to Use - You have concept art, photos, or hand-drawn sketches to convert to 3D. - You need to precisely match a specific visual design. - You want optimized, game-ready assets for real-time or web 3D. --- ## When NOT to Use - You have no reference image → Use [Text to 3D](/webapp/text-to-3d) or generate a reference with AI Image Generation. - You want to brainstorm what to create first → Use [3D Agent](/webapp/3d-agent). - You have multi-angle photos for high-fidelity reconstruction → Use Multi-view Images to 3D. --- ## Step-by-Step 1. Navigate to **3D Model** module → **Image to 3D**. 2. **Upload your image**: - Supports JPG, PNG formats. - Recommended: clear subject, simple background, resolution ≥ 512×512. - For complex backgrounds, use AI Background Removal first. 3. **Select Output Quality**: Standard (high detail) or Smart Topology (optimized for games and real-time). 4. **Configure parameters**: - **Multi-view**: Generate a more complete 3D model from multiple images at different angles. - **Pose Control**: Specify the pose for the generated model (humanoid models). - **Image Enhancement**: Enable to let AI improve input image quality. 5. Click **Generate** and wait (~1 minute). 6. Rotate and review the result in the 3D previewer from all angles. 7. Proceed to post-processing or download. ![Meshy Image to 3D workspace: an uploaded character concept image converted into a full 3D model, with Image Enhancement and pose controls](https://cdn.meshy.ai/webapp-assets/doc/image-to-3d-p0-1.webp) --- ## Smart Topology Smart Topology is a generation mode built for real production pipelines: game development, real-time rendering, and web-based 3D. Instead of a dense, uniform mesh, it outputs clean, organized geometry that's ready to work with right away. What you get: - **Native part segmentation**: the model comes split into clean, accurate parts, so you can select, re-texture, or animate each piece on its own instead of wrestling with one fused mesh. - **Fast iteration**: about 10 seconds from image to mesh, quick enough to try several versions in one sitting. - **Full poly-count control**: set a target anywhere from 100 to 15,000 polygons, from lightweight web and mobile assets to more detailed real-time models. Why it matters: - Cleaner topology deforms more predictably, so rigging and animation behave better. - A controllable, low poly count keeps assets light enough to drop straight into your engine without a performance hit. - Segmented parts make downstream edits, like swapping a material or adjusting one component, far easier. Choose Standard instead when you want maximum surface detail for renders or showcases and topology isn't a constraint. --- ## Multi-view Images to 3D Upload multiple images from different angles, and AI combines all viewpoints to generate a more complete 3D model. - **Recommended angle combinations**: Front + Side + Back + 3/4 view - **Consistency requirement**: All images should be of the same object, with similar lighting conditions - **Advantage**: Back and side details are more accurate, reducing AI "guesswork" --- ## Custom Pose Take full control of your 3D character's pose during generation. Instead of relying on the default pose from the input image, you can define the exact stance your character will be created in. How it works: 1. Upload a character image. 2. Select Pose → Custom Pose. 3. Choose from 6 preset poses as a starting point, or manually adjust every joint (drag, rotate, refine) for total control. 4. Click Generate — the character will be created in the exact pose you set. ![Customize Pose editor in Meshy with preset poses and joint-level controls for setting a character's exact stance](https://cdn.meshy.ai/webapp-assets/doc/image-to-3d-p0-2.webp) When to use Custom Pose: - You need a specific pose for your project (action stance, sitting, T-pose for rigging) but your reference image shows a different pose. - You want to generate the same character in multiple poses without re-uploading different reference images. - You need a T-pose or A-pose output for downstream rigging in Animate, but your concept art shows a dynamic pose. Tips: - For best results with Animate (auto-rig + animation presets), set the pose to T-pose or A-pose. - Custom Pose applies to humanoid characters. Non-humanoid subjects use the pose as shown in the input image. --- ## Settings & Tradeoffs | Setting | Options | Tradeoff | | --- | --- | --- | | Model Version | Meshy 6 / Meshy 5 | Same as Text to 3D | | Output Quality | Standard / Smart Topology | Standard has more detail; Smart Topology is better for real-time rendering | | Image Enhancement | On / Off | On: AI pre-processes to improve image quality; Off: preserves original, best for high-quality inputs | | Multi-view | Single / Multiple (2–8) | Multiple is more accurate but requires prepared materials | | Pose Control | Default / Custom | Custom pose is ideal for character-type models | | License | CC BY 4.0 / Private | CC BY 4.0: Free plan. Private: Pro+, full commercial use | --- ## Examples **Success Example**: - Input: Clear front-view photo of a sneaker on white background, Meshy 6, Standard. - Result: Accurate 3D sneaker with correct proportions, detailed sole pattern, clean textures. **Failure Example**: - Input: Full scene photo with multiple objects, cluttered background. - Result: AI merges multiple objects into one distorted mesh. - Fix: Crop to a single object, remove background, use a clean reference. --- ## Troubleshooting | Symptom | Cause | Fix | | --- | --- | --- | | Back details missing or incorrect | Single image provides no back info | Use Multi-view Images to 3D with back-angle references | | Model proportions distorted | Severe perspective distortion in photo | Use photos with near-orthographic projection or telephoto lens | | Generation ignores image details | Image resolution too low | Enable Image Enhancement or provide a higher-resolution input | | Black patches on model surface | Input image has shadows or dark areas | Use evenly-lit photos, or correct lighting in a 2D editor first | --- ## FAQ ### How do I convert a photo into a 3D model? Open 3D Model → Image to 3D, upload a clear image, select Meshy 6, configure options, and generate in about 1–2 minutes. ### What image works best for Image to 3D? A clear single subject on a simple background at 512×512 or higher; remove busy backgrounds first for the best accuracy. ### Is Image to 3D more accurate than Text to 3D? Yes. A visual reference gives the AI a clear target, so Image to 3D matches your design more precisely. ### Can I generate a model in a specific pose? Yes. Use Custom Pose to pick from 6 presets or adjust joints manually — set a T-pose or A-pose for downstream rigging. ### Can I use multiple photos of the same object? Yes. Multi-view Images to 3D combines front, side, back, and 3/4 views for a more complete, accurate model. --- # Pricing & Credits Source: https://docs.meshy.ai/webapp/pricing # Pricing & Credits Meshy offers Free, Pro, Studio, and Enterprise plans. Each plan includes a set of credits you can spend across all generation tools. --- ## TL;DR - Meshy offers Free, Pro, Studio and Enterprise plans. - Free plan includes a set of complimentary credits, suitable for trial and lightweight use. - Credit consumption varies by operation type and model version: Meshy 6 costs more credits but delivers higher quality. - All paid plans support commercial use. - Enterprise plan offers custom credit volume and dedicated support. ![Meshy plan upgrade screen comparing Free, Pro, Premium, and Ultra tiers with monthly credits, concurrent tasks, and queue priority](https://cdn.meshy.ai/webapp-assets/doc/pricing-credits-p1-1.webp) --- ## Credit Usage Reference | Operation | Meshy 6 | Meshy 5 | Notes | | ------------ | ------- | ------- | ------------------ | | Text to 3D | 20 | 10 | Per generation | | Image to 3D | 20 | 10 | Per generation | | AI Texturing | 10 | 10 | Per model | | Remesh | 0 | 0 | Per model | | Rigging | 0 | 0 | Per model | | Animate | 0 | 0 | Per animation clip | > **Note:** For the latest credit amounts, visit [meshy.ai](https://www.meshy.ai/). --- ## Licensing | Plan | License Type | Commercial Use | Output Ownership | | ---------- | ------------ | ------------------- | ---------------- | | Free | CC BY 4.0 | ✅ With attribution | User owns output | | Pro | Private | ✅ Full commercial | User owns output | | Enterprise | Custom | ✅ Full commercial | User owns output | --- ## FAQ ### Is Meshy free? Yes. The Free plan includes 100 credits per month with no credit card required; paid plans (Pro, Studio, Enterprise) add more credits and features. ### How many credits does a 3D model cost? A full Text to 3D or Image to 3D generation costs 20 credits, covering both the mesh and texture stages. ### When do my Meshy credits reset? Monthly credits reset at 00:00 UTC on the first day of each month; permanent and purchased credits do not expire. ### Will I be charged credits if a generation fails? No. Credits are not deducted for failed generations, and canceled tasks are refunded. ### Can I use Meshy models commercially? Yes. All paid plans (Pro and above) include commercial-use rights; Free-plan outputs are licensed under CC BY 4.0. --- # Text to 3D Source: https://docs.meshy.ai/webapp/text-to-3d # Text to 3D Describe an object in natural language and Meshy's AI generates a textured 3D model directly — no reference image needed. --- ## TL;DR - Describe in natural language, and AI generates a textured 3D model directly. - Supports both Meshy 5 (fast) and Meshy 6 (high quality). - Best for: concept exploration, rapid prototyping, scenarios without reference images. - Quality depends on prompt specificity. Detailed descriptions of materials, style, and proportions produce the best results. - Output includes mesh + base textures; can be further enhanced with AI Texturing. --- ## When to Use - You have an idea but no reference image. - You need to quickly explore multiple design directions. - You want to batch-generate concept variants. --- ## When NOT to Use - You have a clear reference image → Use [Image to 3D](/webapp/image-to-3d) (more precise) - You need to precisely match a specific IP character → [Image to 3D](/webapp/image-to-3d) + multi-view references is more reliable - You need CAD-precision engineering models → Meshy is oriented toward art/game assets - You want a guided creative process with brainstorming → Use [3D Agent](/webapp/3d-agent) --- ## Step-by-Step 1. Navigate to the **3D Model** module in the left sidebar. 2. Select **Text to 3D**. 3. **Choose model version**: - Meshy 6: Highest quality, recommended for final assets. - Meshy 5: Faster, ideal for rapid iteration and concept exploration. 4. **Write your prompt**: - Describe the subject: "a medieval castle tower" - Add material/texture: "stone walls with moss" - Specify art style: "low-poly game art style" - Declare scale: "roughly 3 meters tall" 5. Select output quality: Standard or Smart Topology. 6. Click **Generate** and wait (Meshy 6 ~2 min, Meshy 5 ~45 sec). 7. Inspect the result in the 3D previewer. 8. Proceed to post-processing or export directly. ![Meshy Text to 3D workspace: a text prompt for a medieval castle tower generates a low-poly 3D model, shown with topology stats and printability check](https://cdn.meshy.ai/webapp-assets/doc/text-to-3d-p0-1.webp) --- ## Settings & Tradeoffs | Setting | Options | Tradeoff | | --- | --- | --- | | Model Version | Meshy 6 / Meshy 5 | Meshy 6: higher quality, better topology, but slower and costs more credits. Meshy 5: fast iteration. | | Output Quality | Standard / Smart Topology | Standard: more detail and faces. Smart Topology: fewer faces, faster, better for games. | | Art Style | Specified in prompt | "realistic" produces high detail. "stylized/cartoon" yields cleaner topology. | --- ## Examples **Success Example**: - Prompt: "a detailed steampunk pocket watch with gears visible through glass, brass and copper materials, realistic style" - Result: Clean mesh with accurate gear details, PBR metallic textures, ~25K faces. **Failure Example**: - Prompt: "watch" - Result: Ambiguous — generates a wristwatch with minimal detail, flat textures. - Fix: Be specific about type, materials, style, and visible features. --- ## Troubleshooting | Symptom | Cause | Fix | | --- | --- | --- | | Model doesn't match description | Prompt too vague | Add detail: materials, style, viewpoint, colors | | Model has floating fragments | Prompt describes multiple separate objects | Focus on a single subject; use Scene Compose for complex scenes | | Poor topology (excess triangles) | Normal AI generation behavior | Use Remesh to optimize topology | | Visible texture seams | UV layout issues | Use AI Texturing to regenerate textures | --- ## FAQ ### How does Text to 3D work in Meshy? Describe an object in natural language and Meshy's AI generates a textured 3D model directly — no reference image needed. ### How do I write a good text-to-3D prompt? Combine subject, material/texture, art style, and technical specs, e.g. "a medieval castle tower, stone walls with moss, low-poly game art." ### How many credits does Text to 3D cost? A full Text to 3D generation costs 20 credits, including the mesh and texture stages. ### Should I use Meshy 5 or Meshy 6 for Text to 3D? Use Meshy 6 for the highest-quality final assets and Meshy 5 for faster iteration and concept exploration. ### Can I use a negative prompt in Text to 3D? Yes — add exclusions like "no background elements" or "no text or labels" to remove unwanted features. --- # AI Texturing Source: https://docs.meshy.ai/webapp/guides/3d-model/ai-texturing # AI Texturing Generate or regenerate high-quality PBR textures for any 3D model — control style by prompt and output HD Albedo, Normal, Roughness, and Metallic maps. --- ## TL;DR - Generate or regenerate high-quality PBR textures (Albedo, Normal, Roughness, Metallic) for existing 3D models. - Supports uploading your own mesh for texturing — not limited to Meshy-generated models. - Control parameters: Remove Lighting (remove baked lighting), Generate PBR Textures (full PBR suite), HD Texture (high-resolution output). - Style can be controlled via text prompt (e.g., "weathered wood", "futuristic metallic"). --- ## When to Use - The initial textures from generation aren't good enough and need to be regenerated. - You have an untextured mesh (white model) that needs AI auto-texturing. - You want to change the model's material style (e.g., from realistic to cartoon). - You need a complete PBR texture set for a PBR rendering pipeline. --- ## When NOT to Use - You want to manually paint textures → Export UV and work in Substance Painter - You only need color/brightness adjustments → Fine-tune in DCC tools --- ## Step-by-Step 1. Select the target model in My Models, or upload an external mesh (OBJ, FBX, GLB). 2. Enter the **AI Texturing** tool. 3. **Configure parameters**: - **Text Prompt**: Describe the desired material style (e.g., "rusted iron with scratches"). - **Image Prompt**: Upload an image of the desired material style. - **Remove Lighting**: Enable to remove baked lighting for more accurate PBR rendering. - **Generate PBR Textures**: Enable to generate the full Albedo + Normal + Roughness + Metallic set. - **HD Texture**: Enable to output high-resolution textures (2K/4K). 4. Click **Generate Texture**. 5. Preview the result under different lighting environments to check PBR quality. 6. Download the texture files or export the complete textured model. ![Meshy AI Texturing panel: texture a model from a text or image prompt, with Remove Lighting, PBR maps, and HD Texture options](https://cdn.meshy.ai/webapp-assets/doc/ai-texturing-p0-1.webp) --- ## Settings & Tradeoffs | Setting | Options | Tradeoff | | --- | --- | --- | | Remove Lighting | On / Off | On: removes baked shadows, ideal for PBR pipelines. Off: preserves original lighting info. | | Generate PBR Textures | On / Off | On: outputs 4 maps, complete PBR pipeline. Off: Albedo only. | | HD Texture | On / Off | On: 2K–4K textures, sharper, costs more credits. Off: 1K standard. | | Style Prompt | Free text | More specific = better results. Stack style keywords for best effect. | --- ## Examples **Success Example**: - Input: Low-poly sword mesh (no textures), prompt "ancient elvish blade, silver with blue rune engravings, fantasy style" - Settings: PBR On, HD On, Remove Lighting On. - Result: Complete PBR texture set with detailed engravings, proper metallic response. **Failure Example**: - Input: Dense mesh with overlapping UVs, prompt "wood" - Result: Texture seams and distortion visible. - Fix: Run Unwrap UV first to generate a clean UV layout, then re-apply AI Texturing. --- ## Troubleshooting | Symptom | Cause | Fix | | --- | --- | --- | | Visible texture seams | Poor UV layout | Run Unwrap UV first, then re-texture | | PBR maps look "flat" | Remove Lighting not enabled | Enable Remove Lighting to remove baked shadows | | Texture style doesn't match prompt | Prompt too short | Add more descriptors: material, era, wear level, colors | | HD textures load slowly | 4K texture files are large | Normal behavior; disable HD Texture if ultra-high-res isn't needed | --- ## FAQ ### How do I add textures to a 3D model in Meshy? Select a model or upload your own mesh, open AI Texturing, enter a material prompt, and generate PBR textures. ### Can I texture a model I made elsewhere? Yes. You can upload external meshes (OBJ, FBX, GLB, up to 50MB) for AI texturing — not just Meshy-generated models. ### What does "Remove Lighting" (delight) do? It strips baked-in lighting and shadows from the texture so PBR rendering looks correct under any lighting environment. ### What PBR maps does Meshy generate? With Generate PBR Textures enabled, Meshy outputs Albedo, Normal, Roughness, and Metallic maps, plus optional 2K/4K HD resolution. ### Why do my textures have seams or distortion? This usually means poor UVs. Run Unwrap UV first to generate a clean UV layout, then re-apply AI Texturing. --- ## Related Links - [Unwrap UV](/webapp/guides/3d-model/unwrap-uv) — Generate clean UVs before texturing - [Remesh](/webapp/guides/3d-model/remesh) — Optimize mesh before texturing for best results - [Text to 3D](/webapp/text-to-3d) — Generation includes initial textures --- # Auto Split Source: https://docs.meshy.ai/webapp/guides/3d-model/auto-split # Auto Split Turn an oversized or multi-color 3D model into printable, watertight parts in seconds — with smart cuts, a fast preview, and a build-plate-ready layout for easy assembly. --- ## TL;DR - **Fast Preview:** Get a complete split preview in about 40 seconds, so you can review the result and re-split as needed before finalizing. - **Smart Cuts:** Cuts follow the model's natural structure, with clean boundaries and accurate separation, sized to fit your build plate. - **Built to Assemble:** Every cut is auto-capped watertight, parts are auto-arranged on the build plate, and they are ready to fit back together. One click sends them to Bambu Studio, OrcaSlicer, Elegoo Slicer etc. - **Target Use:** Built for multi-color prints, oversized models and figures, currently available for untextured models generated by Meshy 6. --- ## When to Use - You need to split an oversized model into printable, plate-sized parts. - You want to print a multi-color model with less purge waste and fewer filament changes. - You want split parts automatically arranged on the build plate for easier printing. - You want to preserve fine details and surface quality by reducing overhangs, supports, and the risk of damage during support removal. - You want to split, cap, and align model parts without switching between multiple tools. --- ## When NOT to Use - You can already print the model cleanly as one piece within your printer's build volume. - You need precise cut placement or custom joints, which are better handled manually in Blender or Meshmixer. --- ## Step-by-Step 1. Select a model from your model library, or generate a new one. 2. Click **Print** in the left sidebar to open the 3D Printing workspace, open Meshy Auto Split from either of these entry points: - The Meshy Auto Split card at the top of the **Post-Processing** panel. - The Meshy Auto Split button in the **toolbar** below the model viewer. 3. Click **Meshy Auto Split** and wait about 40 seconds. When the split is complete, the model will reappear with each part shown in a different color. 4. Drag the **slider** below the model to gradually pull the parts apart. Slide it back to bring the parts together and check how they fit. 5. Switch between the two view modes: - **Assembled**: Shows the parts fitted together so you can check their alignment. - **On Plate**: Shows the parts arranged flat on the print plate as they will be printed. 6. Click the list icon on the right side of the toolbar to view all parts, their colors, and the total part count. 7. Click the **Download** button at the bottom-right of the toolbar. Choose one of the following export layouts: - **Assembled**: Exports all parts together in their fitted positions. - **On Plate**: Exports the parts arranged on the print plate, ready to import into your slicer without repositioning. - STL is the recommended file format. 8. Click **Re-split** in the toolbar to generate a different split result if needed. Each re-split starts a new split job and uses credits. It is different from the free Retry option available during model generation. --- ## Example