# Parts API

List, create, update, delete, and search workpiece parts.

Source: https://support.toolingmetrics.com/en/api/reference/parts/
Updated: 2026-10-29

Base path: `/v1/organizations/:organization_id/parts`

## Endpoints

| Method | Path | Description |
|---|---|---|
| `GET` | `/parts` | List all parts |
| `GET` | `/parts/:id` | Get a part |
| `POST` | `/parts` | Create a part |
| `PATCH` | `/parts/:id` | Update a part |
| `DELETE` | `/parts/:id` | Delete a part |
| `GET` | `/parts/search` | Search by number and/or description |

## Part object

```json
{
  "id": 5,
  "number": "P-0042",
  "description": "Cylinder Block",
  "customer_number": "CB-100",
  "created_at": "2025-03-01T08:00:00Z",
  "updated_at": "2025-06-01T10:00:00Z",
  "material": {
    "id": 2,
    "name": "42CrMo4",
    "iso_code": "P20",
    "vdi_code": "1.7225"
  },
  "created_by": { "id": 7, "email": "user@example.com" }
}
```

## Parameters

### Create / update

| Parameter | Type | Description |
|---|---|---|
| `number` | string | Part number. If blank on create, auto-generated from the organization's parts sequence. |
| `description` | string | Part description |
| `customer_number` | string | Customer's own reference number |
| `material_id` | integer | ID of the material from the Materials Library: the organization's own or a shared one. Another organization's material answers `422` |
| `organization_id` | integer | **Required in the request body on create**, not just in the URL. The `:organization_id` path segment authorizes the request but does not by itself associate the new part with that organization — pass it again in the body. |
| `user_id` | integer | Associates the record with a specific user for role-based scoping (see [Authentication](https://support.toolingmetrics.com/en/api/authentication/)). Leave unset unless you know you need it. |
| `picture` | string | Part photo as a Base64-encoded PNG |
| `drawing` | string | 2D drawing as a Base64-encoded DXF |
| `model` | string | 3D model as a Base64-encoded STEP file |

### Search

| Parameter | Type | Description |
|---|---|---|
| `number` | string | Exact match on part number |
| `description` | string | Case-insensitive exact match on description |

Both parameters may be combined to narrow results.

## File attachments

Pictures, drawings, and STEP models are uploaded as Base64-encoded strings in the JSON request body. Files are stored in object storage and associated with the part record after save.

```json
{
  "number": "P-0042",
  "description": "Cylinder Block",
  "model": "<base64-encoded-step-content>"
}
```

## Examples

```bash
# Search by part number
curl "https://api.toolingmetrics.com/v1/organizations/12/parts/search?number=P-0042" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Create a part — organization_id is required in the body, not just the URL
curl -X POST "https://api.toolingmetrics.com/v1/organizations/12/parts" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"number": "P-0042", "description": "Cylinder Block", "material_id": 2, "organization_id": 12}'
```

```python
import requests
import base64

BASE = "https://api.toolingmetrics.com/v1"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}

# Create a part with a STEP model attached
with open("cylinder_block.stp", "rb") as f:
    model_b64 = base64.b64encode(f.read()).decode()

response = requests.post(
    f"{BASE}/organizations/12/parts",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={
        "number": "P-0042",
        "description": "Cylinder Block",
        "material_id": 2,
        "organization_id": 12,
        "model": model_b64,
    },
)
response.raise_for_status()
part = response.json()
print(f"Created part #{part['id']}: {part['number']}")
```
