# Machines API

List, create, update, delete, and search machines. Retrieve the live tool crib for a machine.

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

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

## Endpoints

| Method | Path | Description |
|---|---|---|
| `GET` | `/machines` | List all machines |
| `GET` | `/machines/:id` | Get a machine |
| `POST` | `/machines` | Create a machine |
| `PATCH` | `/machines/:id` | Update a machine |
| `DELETE` | `/machines/:id` | Delete a machine |
| `GET` | `/machines/search` | Search by designation |
| `GET` | `/machines/:id/tool_crib` | Get tools currently at a machine |

## Machine object

```json
{
  "id": 1,
  "name": "DMG 5-axis",
  "designation": "DMG-001",
  "builder": "DMG Mori",
  "model": "DMU 50",
  "serial_number": "SN123456",
  "hour_rate": 120.0,
  "target_oee": 85,
  "created_at": "2025-01-15T08:00:00Z",
  "updated_at": "2025-06-01T10:00:00Z",
  "warehouse_access_point": { "id": 3, "name": "CNC Area" },
  "created_by": { "id": 7, "email": "user@example.com" },
  "components": [
    {
      "id": 44,
      "component_type": "spindle",
      "name": "Main Spindle",
      "interfaces": [{ "code": "HSK01C0630****" }],
      "data": {},
      "tool_crib": false
    }
  ]
}
```

## Parameters

### Create / update

| Parameter | Type | Description |
|---|---|---|
| `name` | string | Display name |
| `designation` | string | Machine code. **Always pass this explicitly.** |
| `builder` | string | Manufacturer name |
| `model` | string | Machine model |
| `serial_number` | string | Serial number |
| `hour_rate` | decimal | Cost per operating hour |
| `target_oee` | decimal | Target OEE (0–100) |
| `warehouse_access_point_id` | integer | WAP the machine belongs to. If omitted, defaults to the first WAP in the organization. |
| `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 machine 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. |

Like [Parts](https://support.toolingmetrics.com/en/api/reference/parts/), Machines auto-generate `designation` from an organization sequence when left blank — `number` is an alias for `designation` on the Machine model, so the same blank-`designation` handling that works for Parts works here too.

### Search

| Parameter | Type | Description |
|---|---|---|
| `designation` | string | Exact match on machine designation |

## Examples

```bash
# List all machines
curl "https://api.toolingmetrics.com/v1/organizations/12/machines" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Find a machine by designation
curl "https://api.toolingmetrics.com/v1/organizations/12/machines/search?designation=DMG-001" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Get the live tool crib for a machine
curl "https://api.toolingmetrics.com/v1/organizations/12/machines/1/tool_crib" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Create a machine — organization_id is required in the body, not just the URL
curl -X POST "https://api.toolingmetrics.com/v1/organizations/12/machines" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Mazak 3-axis", "designation": "MAZ-002", "builder": "Mazak", "model": "VCN-430A", "organization_id": 12}'
```

```python
import requests

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

# Check which tools are loaded at a machine before a setup
crib = requests.get(
    f"{BASE}/organizations/12/machines/1/tool_crib",
    headers=HEADERS,
).json()

for assembly_id, tools in crib.items():
    for tool in tools:
        remaining = [edge["remain_life_percentage"] for edge in tool["cutting_edges"] if edge["remain_life_percentage"] is not None]
        print(f"  T{tool['number']} — {tool['name']} — remaining {min(remaining) if remaining else 0}%")
```

## Tool crib

`GET /machines/:id/tool_crib` returns tools currently stored at the machine, grouped by tool assembly ID. Each entry is filtered down to a fixed set of fields — note that **`id` is not one of them**:

```json
{
  "42": [
    {
      "number": "T-001",
      "name": "Face Mill Ø80",
      "status": "active",
      "completed": true,
      "updated_at": "2025-06-01T08:00:00Z",
      "weight": 1.8,
      "usage_at": "2026-05-30T14:00:00Z",
      "cutting_edges": [
        {
          "id": 12,
          "item_id": 84,
          "condition": "used",
          "usage_life": 4.5,
          "life_limit": 20.0,
          "remain_life_percentage": 77.5,
          "completed": true
        }
      ],
      "component_id": 44,
      "slot_number": 3
    }
  ]
}
```

Keys are tool assembly IDs (integers as strings). Each value is an array of tool records sorted by the limiting cutting edge's `remain_life_percentage` descending. Tools without a cutting edge life limit are listed last.

| Field | Description |
|---|---|
| `number` | Tool number assigned at assembly station |
| `name` | Tool name |
| `status` | Current status |
| `completed` | Whether all assembly components are present |
| `weight` | Tool weight |
| `usage_at` | Timestamp of last usage record |
| `cutting_edges` | All cutting edges and their current index, condition, usage, life limit, life unit, remaining-life percentage, completion, quantity, and CRP data |
| `component_id` | Which machine component (head/turret/gang, from `components` in the machine object) the tool is loaded into. **Only present if the tool has been assigned a crib slot** — a tool physically at the machine but not yet slotted into a component omits this and `slot_number` entirely |
| `slot_number` | Pocket/position number within that component (lathe turret position, or magazine slot) |

**`slot_number` is not validated against the component's own pocket definitions.** A machine component separately defines its physical pockets as Machine Tool Location records (each with its own `slot_number`, unique per component — that's what the `components` array in the Machine Object above represents). The `slot_number` returned here comes from a second, independent occupancy map (`tool_crib`) that is only kept in sync with those pocket definitions by convention — matching integers, not a foreign key. Don't assume a `tool_crib` entry's `slot_number` necessarily corresponds to an existing, currently-defined pocket on that component; treat it as "the number recorded when this tool was last slotted," not a validated reference.
