lowpoly retires Oct 30, 2026. Please switch models before these dates to avoid request errors. See all deprecations

Quickstart

Start by creating your API key

Every request in this guide needs one. Creating a key takes seconds.

Create your API key

Make your first 3D model with the Meshy REST API in four steps, from creating an API key to downloading the model.


1Get your API key

Create an API key on the API Keys page of the Developer Platform. You can't view the key again after you leave that screen, so store it somewhere safe. Send it in every request as a Bearer token in the Authorization header. See Authentication.

You need a paid plan to create and manage API keys. On the Free plan, you can't create keys of your own, and the Playground uses a built-in key for testing.

Open the API Keys page in the Developer Platform, then create your key


2Create an Image to 3D task

Send an image to Image to 3D. To start from a text prompt or several photos instead, use Text to 3D or Multi-Image to 3D.

First, store your key in an environment variable:

Export your key

export MESHY_API_KEY="<your-api-key>"

The following examples all use this photo. To try another image, change image_url.

Sample fantasy character illustration used as the Image to 3D input in this guide
Sample input

Request

POST
/openapi/v1/image-to-3d
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"
  }'

3Check task status

The task runs in the background and usually takes a few minutes. Get the task from the same endpoint until status is SUCCEEDED, FAILED, or CANCELED. In the following request, replace <task_id> with the ID that step 2 returned. Between requests, wait the number of seconds in the Retry-After header.

For typical processing times, and how long to wait before you give up, see Task lifecycle.

Request

GET
/openapi/v1/image-to-3d/:id
curl https://api.meshy.ai/openapi/v1/image-to-3d/<task_id> \
  -H "Authorization: Bearer ${MESHY_API_KEY}"

Response: SUCCEEDED

{
  "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": null
}

If the task fails, status is FAILED, and task_error says why. Fix the input or create another task. See Errors.


4Download your model

The files are in model_urls of the preceding response. Each format (GLB, FBX, OBJ, USDZ, and STL) has a signed URL that works for a limited time. You can also paste the URL into your browser to download the file.

Download

model_urls.glb
curl -L "<model_urls.glb from the response above>" -o model.glb
The resulting 3D model generated from the sample fantasy character photo
Your result

Put it all together

This script creates the task, waits for it to finish, and downloads the model.

Full script

import axios from 'axios';
import fs from 'fs';

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, timeout: 60_000 },
);
const taskId = created.result;

// 2. Poll until it finishes, for up to 60 minutes
const deadline = Date.now() + 60 * 60 * 1000;
let task;
while (true) {
  const { data, headers: resHeaders } = await axios.get(
    `https://api.meshy.ai/openapi/v1/image-to-3d/${taskId}`,
    { headers, timeout: 30_000 },
  );
  task = data;
  if (['SUCCEEDED', 'FAILED', 'CANCELED'].includes(task.status)) break;
  if (Date.now() > deadline) {
    // The task is still running. Check it again later with the same task ID instead of creating a new one.
    throw new Error(`Task ${taskId} is still ${task.status}; check it again later`);
  }
  const waitSeconds = Number(resHeaders['retry-after']) || 5;
  await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
}

// 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');

Explore common workflows


Next steps