---
title: "3D → SimReady"
description: "Upload any 3D file and get back a physics-enabled USD asset. 1 credit per conversion."
---

import { Tabs, TabItem, Aside } from '@astrojs/starlight/components';

Upload a 3D model and Rigyd returns a SimReady USD asset — physics properties, collision meshes, and materials filled in automatically.

| | |
|---|---|
| **Method** | `POST` |
| **Path**   | `/api/conversions` |
| **Content-type** | `multipart/form-data` |
| **Job type** | `glb_to_simready` |
| **Credits** | 1 |

## Accepted formats

`.glb`, `.gltf`, `.fbx`, `.obj`, `.stl`, `.ply`, `.usd`, `.usda`, `.usdc`, `.usdz`, and `.zip` (for multi-file inputs).

`.glb` skips the preprocessing stage and is the fastest path. Anything else goes through Blender-based cleanup first — see [Supported formats](/reference/supported-formats) for the rules around ZIP archives, OBJ + MTL, GLTF + bin, and USD with references.

## Request fields

| Field                    | Type           | Required | Notes                                                                |
| ------------------------ | -------------- | -------- | -------------------------------------------------------------------- |
| `file`                   | file (upload)  | yes      | The 3D model. See accepted formats above.                            |
| `target_triangle_count`  | int            | no       | Decimate to this triangle count during preprocessing. `1000`–`1000000`. Useful for high-poly inputs. |
| `threshold`              | float          | no       | CoACD collision-decomposition concavity threshold (advanced).        |
| `llm_provider`           | string         | no       | Override the LLM used for material identification (advanced).        |
| `skip_validation`        | boolean        | no       | Skip USD schema validation. Default `false`.                         |

## Examples

<Tabs syncKey="lang">
  <TabItem label="curl">
  ```bash
  curl -X POST https://api.rigyd.com/api/conversions \
    -H "Authorization: Bearer rgyd_live_..." \
    -F "file=@./toolbox.glb" \
    -F "target_triangle_count=50000"
  ```
  </TabItem>
  <TabItem label="JavaScript">
  ```js
  import fs from 'node:fs';

  const form = new FormData();
  form.append('file', new Blob([fs.readFileSync('./toolbox.glb')]), 'toolbox.glb');
  form.append('target_triangle_count', '50000');

  const res = await fetch('https://api.rigyd.com/api/conversions', {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.RIGYD_API_KEY}` },
    body: form,
  });
  const { data } = await res.json();
  ```
  </TabItem>
  <TabItem label="Python">
  ```python
  import os, requests

  with open("toolbox.glb", "rb") as f:
      res = requests.post(
          "https://api.rigyd.com/api/conversions",
          headers={"Authorization": f"Bearer {os.environ['RIGYD_API_KEY']}"},
          files={"file": ("toolbox.glb", f, "model/gltf-binary")},
          data={"target_triangle_count": 50000},
      )
  job = res.json()["data"]
  ```
  </TabItem>
</Tabs>

## Response — `202 Accepted`

```json
{
  "data": {
    "id": "abc123...",
    "physiq_job_id": "phy_...",
    "status": "queued",
    "filename": "toolbox.glb",
    "progress": 0,
    "job_type": "glb_to_simready",
    "credits_charged": 1,
    "createdAt": "2026-05-06T12:00:00.000Z"
  }
}
```

For non-GLB inputs, `status` starts at `preprocessing` while the model is converted to a clean GLB, then transitions to `queued` → `running` → `completed`.

<Aside type="tip">
  The credit is reserved atomically when the request is accepted and refunded automatically if the job ends in `failed`. You will not be double-charged on retries.
</Aside>

## Next: [poll the job](/jobs/retrieve) → [download the USD](/jobs/download).