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

---
# Text to Motion API

Generate character motion clips from natural-language descriptions. Describe an action — "a character waving", "a zombie shambling forward" — and receive a raw motion clip you can retarget onto rigged characters in your own pipeline or DCC tools.

The output is a standalone motion clip: it does not require, and is not attached to, a character model. To rig a character first, see the [Rigging API](/api/rigging). To apply a generated clip onto your rigged character, pass the task `id` as `motion_task_id` to the [Animation API](/api/animation#create-an-animation-task) — apply it within the 3-day asset retention window.

---

## POST /openapi/v1/text-to-motion -- Create a Text to Motion Task

This endpoint creates a new task to generate a motion clip from a text prompt.

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

A task with `mode` `prime` costs 10 credits and generates with our highest-quality motion model. A task with `mode` `swift` costs 3 credits and generates faster with our economical motion model.

### Parameters

  - `prompt` · *string* · **required**

  A natural-language description of the motion to generate. Maximum 400 characters.

  - `mode` · *string* · default: `prime`

  The motion generation mode. Available values: `prime`, `swift`. `prime` produces the highest quality and outputs FBX; `swift` is faster and cheaper and outputs BVH.

  - `duration` · *number* · **required**

  The target duration of the motion clip in seconds. Between `2` and `10`, in steps of `0.5` (for example `2`, `2.5`, `3`, … `10`).

### Returns
The `result` property of the response contains the task `id` of the newly created Text to Motion task.

### Failure Modes

  - `400 - Bad Request`

  The request was unacceptable. Common causes:
  * **Missing or empty prompt**: `prompt` is missing, blank, or longer than 400 characters.
  * **Invalid mode**: `mode` is not `prime` or `swift`.
  * **Invalid duration**: `duration` is missing, outside `2`–`10`, or not on a `0.5` second step.

  - `401 - Unauthorized`

  Authentication failed. Please check your API key.

  - `402 - Payment Required`

  Insufficient credits to perform this task.

  - `403 - Forbidden`

  The prompt was flagged by content moderation.

  - `429 - Too Many Requests`

  You have exceeded your rate limit.

**cURL**

```bash
# Generate a motion clip with required params only
curl https://api.meshy.ai/openapi/v1/text-to-motion \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "prompt": "a character waving",
    "duration": 3
  }'

# Generate a fast, economical clip with Swift mode
curl https://api.meshy.ai/openapi/v1/text-to-motion \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "prompt": "a character waving",
    "mode": "swift",
    "duration": 4.5
  }'
```

```javascript
import axios from 'axios'

const headers = { Authorization: `Bearer ${YOUR_API_KEY}` };

// Generate a motion clip with required params only
const payload = {
  prompt: "a character waving",
  duration: 3
};

try {
  const response = await axios.post(
    'https://api.meshy.ai/openapi/v1/text-to-motion',
    payload,
    { headers }
  );
  console.log(response.data);
} catch (error) {
  console.error(error);
}

// Generate a fast, economical clip with Swift mode
const swiftPayload = {
  prompt: "a character waving",
  mode: "swift",
  duration: 4.5
};

try {
  const response = await axios.post(
    'https://api.meshy.ai/openapi/v1/text-to-motion',
    swiftPayload,
    { headers }
  );
  console.log(response.data);
} catch (error) {
  console.error(error);
}
```

```python
import requests

headers = {
    "Authorization": f"Bearer {YOUR_API_KEY}"
}

# Generate a motion clip with required params only
payload = {
    "prompt": "a character waving",
    "duration": 3
}

response = requests.post(
    "https://api.meshy.ai/openapi/v1/text-to-motion",
    headers=headers,
    json=payload,
)
response.raise_for_status()
print(response.json())

# Generate a fast, economical clip with Swift mode
swift_payload = {
    "prompt": "a character waving",
    "mode": "swift",
    "duration": 4.5
}

response = requests.post(
    "https://api.meshy.ai/openapi/v1/text-to-motion",
    headers=headers,
    json=swift_payload,
)
response.raise_for_status()
print(response.json())
```

**Response**

```json
{
  "result": "018c425b-b2c6-727e-d333-3c1887i9h791"
}
```

---

## GET /openapi/v1/text-to-motion/:id -- Retrieve a Text to Motion Task

This endpoint allows you to retrieve a Text to Motion task given a valid task `id`. Refer to [The Text to Motion Task Object](#the-text-to-motion-task-object) to see which properties are included.

### Parameters

  - `id` · *path*

  Unique identifier for the Text to Motion task to retrieve.

### Returns
The response contains the Text to Motion Task object. Check [The Text to Motion Task Object](#the-text-to-motion-task-object) section for details.

**cURL**

```bash
curl https://api.meshy.ai/openapi/v1/text-to-motion/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/text-to-motion/${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/text-to-motion/{task_id}",
    headers=headers,
)
response.raise_for_status()
print(response.json())
```

**Response**

```json
{
  "id": "018c425b-b2c6-727e-d333-3c1887i9h791",
  "type": "text-to-motion",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1787314497437,
  "started_at": 1787314498012,
  "finished_at": 1787314505881,
  "expires_at": 1787573705881,
  "task_error": null,
  "result": {
    "motion_url": "https://assets.meshy.ai/0630d47c-84b8-4d37-bc02-69e45d9272c1/tasks/018c425b-b2c6-727e-d333-3c1887i9h791/output/clip.fbx?Expires=...",
    "motion_format": "fbx",
    "duration_ms": 3000,
    "mode": "prime"
  },
  "consumed_credits": 10
}
```

---

## GET /openapi/v1/text-to-motion -- List Text to Motion Tasks

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

The response is an array of [Text to Motion Task objects](#the-text-to-motion-task-object).

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/text-to-motion?page_num=1&page_size=20" \
  -H "Authorization: Bearer ${YOUR_API_KEY}"
  ```

**Response**

```json
[
  {
    "id": "018c425b-b2c6-727e-d333-3c1887i9h791",
    "type": "text-to-motion",
    "status": "SUCCEEDED",
    "...": "..."
  }
]
```

---

## GET /openapi/v1/text-to-motion/:id/stream -- Stream a Text to Motion Task

This endpoint streams real-time updates for a Text to Motion task using Server-Sent Events (SSE).

### Parameters

  - `id` · *path*

  Unique identifier for the Text to Motion task to stream.

### Returns

Returns a stream of [The Text to Motion Task Objects](#the-text-to-motion-task-object) as Server-Sent Events.

Every `message` event carries the full task object. While the task is `PENDING` or `IN_PROGRESS`, the `result` fields are still empty (`""` / `0`) and `finished_at` / `expires_at` are `0`; watch `status` and `progress`.

  **cURL**

  ```bash
  curl -N https://api.meshy.ai/openapi/v1/text-to-motion/018c425b-b2c6-727e-d333-3c1887i9h791/stream \
  -H "Authorization: Bearer ${YOUR_API_KEY}"
  ```

  ```javascript
  const response = await fetch(
    'https://api.meshy.ai/openapi/v1/text-to-motion/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/text-to-motion/{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 events carry the full task object at every stage; the result
  // fields stay empty until the task succeeds.
  event: message
  data: {
    "id": "018c425b-b2c6-727e-d333-3c1887i9h791",
    "type": "text-to-motion",
    "status": "IN_PROGRESS",
    "progress": 50,
    "created_at": 1787314497437,
    "started_at": 1787314498012,
    "finished_at": 0,
    "expires_at": 0,
    "task_error": null,
    "result": {
      "motion_url": "",
      "motion_format": "",
      "duration_ms": 0,
      "mode": ""
    },
    "consumed_credits": 10
  }

  event: message
  data: { // Example of a SUCCEEDED task stream item, mirroring The Text to Motion Task Object structure
    "id": "018c425b-b2c6-727e-d333-3c1887i9h791",
    "type": "text-to-motion",
    "status": "SUCCEEDED",
    "progress": 100,
    "created_at": 1787314497437,
    "started_at": 1787314498012,
    "finished_at": 1787314505881,
    "expires_at": 1787573705881,
    "task_error": null,
    "result": {
      "motion_url": "https://assets.meshy.ai/.../output/clip.fbx?Expires=...",
      "motion_format": "fbx",
      "duration_ms": 3000,
      "mode": "prime"
    },
    "consumed_credits": 10
  }
```

---

## DELETE /openapi/v1/text-to-motion/:id -- Delete a Text to Motion Task

This endpoint permanently deletes a Text to Motion task, including the generated motion clip. This action is irreversible.

### Path Parameters

  - `id` · *path*

  The ID of the Text to Motion task to delete.

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

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

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

### Returns
Returns `200 OK` on success, or `409 Conflict` when the task is
`IN_PROGRESS`.

  **cURL**

  ```bash
  curl --request DELETE \
    --url https://api.meshy.ai/openapi/v1/text-to-motion/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 {
    await axios.delete(
      `https://api.meshy.ai/openapi/v1/text-to-motion/${taskId}`,
      { headers }
    )
  } catch (error) {
    console.error(error)
  }
  ```

  ```python
  import requests

  task_id = "018c425b-b2c6-727e-d333-3c1887i9h791"
  headers = {
      "Authorization": f"Bearer {YOUR_API_KEY}"
  }

  response = requests.delete(
      f"https://api.meshy.ai/openapi/v1/text-to-motion/{task_id}",
      headers=headers,
  )
  response.raise_for_status()
  ```

**Response**

```json
// 200 OK on success, with an empty body.
//
// 409 Conflict when the task is IN_PROGRESS — the task is left running:
{
  "message": "Task is IN_PROGRESS and cannot be deleted. Credits for a task the worker has already started are not refundable; wait for it to reach SUCCEEDED, FAILED or CANCELED, then delete it."
}
```

---

## The Text to Motion Task Object
The Text to Motion Task object represents the work unit for generating a motion clip from a text prompt.

### Properties

  - `id` · *string*

  Unique identifier for the task.

  - `type` · *string*

  Type of the task. The value is `text-to-motion`.

  - `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. `0` until the task finishes. The generated clip is retained for 3 days after the task finishes; download it before it expires.

  - `preceding_tasks` · *integer*

  The count of preceding tasks in the queue. Meaningful only if status is `PENDING`; omitted when zero.

  - `consumed_credits` · *integer*

  The number of credits consumed by this task. `10` for `prime` mode, `3` for `swift` mode. Returns `0` for `FAILED` tasks (credits are refunded on failure).

  - `task_error` · *object*

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

  - `result` · *object*

  Contains the generated motion clip once the task `SUCCEEDED`; until then the fields are present but empty (`""` / `0`).

- `motion_url` · *string*

  Downloadable URL for the generated motion clip. The URL is re-signed on every read and expires with the task's retention window.

- `motion_format` · *string*

  File format of the clip: `fbx` for `prime` mode, `bvh` for `swift` mode.

- `duration_ms` · *integer*

  Duration of the generated clip in milliseconds.

- `mode` · *string*

  The mode the clip was generated with: `prime` or `swift`.

  <span id="example-text-to-motion-task-object" />

  **Example Text to Motion Task Object**

  ```json
  {
    "id": "018c425b-b2c6-727e-d333-3c1887i9h791",
    "type": "text-to-motion",
    "status": "SUCCEEDED",
    "progress": 100,
    "created_at": 1787314497437,
    "started_at": 1787314498012,
    "finished_at": 1787314505881,
    "expires_at": 1787573705881,
    "task_error": null,
    "result": {
      "motion_url": "https://assets.meshy.ai/.../output/clip.fbx?Expires=...",
      "motion_format": "fbx",
      "duration_ms": 3000,
      "mode": "prime"
    },
    "consumed_credits": 10
  }
  ```
