Projects API
List, create, update, delete, and search engineering projects with nested jobs and operations.
Base path: /v1/organizations/:organization_id/projects
Endpoints
Section titled “Endpoints”| Method | Path | Description |
|---|---|---|
GET |
/projects |
List all projects (summary) |
GET |
/projects/:id |
Get a project with jobs and operations |
POST |
/projects |
Create a project |
PATCH |
/projects/:id |
Update a project |
DELETE |
/projects/:id |
Delete a project |
GET |
/projects/search |
Search projects by name |
Project object (detail)
Section titled “Project object (detail)”{ "id": 8, "name": "Cylinder Block Rev2", "description": "...", "status": "released", "multiple_setup": false, "created_at": "2025-04-01T08:00:00Z", "updated_at": "2025-06-01T10:00:00Z", "created_by": { "id": 7, "email": "user@example.com" }, "jobs": [ { "id": 12, "name": "Op 10 — Facing", "order": 1, "status": "draft", "locked": false, "machine": { "id": 1, "designation": "DMG-001", "name": "DMG 5-axis" }, "part": { "id": 5, "number": "P-0042", "description": "Cylinder Block" }, "operations": [ { "id": 20, "name": "Face milling" } ] } ]}List response
Section titled “List response”The GET /projects index returns a compact summary — not the full nested structure:
[ { "id": 8, "name": "Cylinder Block Rev2", "status": "released", "locked": false }, { "id": 9, "name": "Shaft Housing", "status": "draft", "locked": false }]Parameters
Section titled “Parameters”Create / update
Section titled “Create / update”| Parameter | Type | Description |
|---|---|---|
name |
string | Project name |
description |
string | Project description |
status |
string | One of draft, released, approved, active, archived. Approving a released project copies the products of its tool assemblies into items, created as the project’s creator, so it also needs the key’s user to be allowed to create such items and to update the existing ones; otherwise 401 |
multiple_setup |
boolean | Whether the project uses multiple machine setups |
picture |
string | Project image as a Base64-encoded PNG |
jobs_attributes |
array | Nested jobs (see below) |
Unlike Parts and Machines, Projects auto-assign their organization from the :organization_id path segment — you do not need to (and cannot, organization_id isn’t an accepted param) pass it again in the body. The same applies to each job in jobs_attributes.
Jobs attributes
Section titled “Jobs attributes”| Parameter | Type | Description |
|---|---|---|
id |
integer | Required when updating an existing job |
name |
string | Job name |
order |
integer | Display order |
machine_id |
integer | Assigned machine |
part_id |
integer | Workpiece part |
status |
string | Job status |
_destroy |
boolean | Pass true to delete the job |
operations_attributes |
array | Nested operations (see below) |
Operations attributes
Section titled “Operations attributes”| Parameter | Type | Description |
|---|---|---|
id |
integer | Required when updating an existing operation |
name |
string | Operation name |
order |
integer | Display order within the job |
cycle_time |
integer | Estimated cycle time. Must be a whole number — numericality: only_integer: true rejects decimals with a 422 |
tool_number |
integer | T-number in the NC program |
tool_assembly_id |
integer | Assigned tool assembly model |
_destroy |
boolean | Pass true to delete the operation |
List / search filters
Section titled “List / search filters”| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status (list endpoint). Also implicitly filters to locked: false — passing status excludes locked projects even though you didn’t ask for that filter. Omit status if you need locked projects included. |
q |
string | Case-insensitive substring match on project name (search endpoint) |
Examples
Section titled “Examples”# Search projects by namecurl "https://api.toolingmetrics.com/v1/organizations/12/projects/search?q=Cylinder" \ -H "Authorization: Bearer YOUR_TOKEN"
# Get a project with full job and operation detailcurl "https://api.toolingmetrics.com/v1/organizations/12/projects/8" \ -H "Authorization: Bearer YOUR_TOKEN"import requests
BASE = "https://api.toolingmetrics.com/v1"HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}
# Create a project with one job and one operation (CAM post-processor integration)payload = { "name": "Cylinder Block Rev2", "status": "draft", "jobs_attributes": [ { "name": "Op 10 — Facing", "order": 1, "machine_id": 1, "part_id": 5, "operations_attributes": [ { "name": "Face milling", "order": 1, "cycle_time": 750, "tool_number": 1, "tool_assembly_id": 42, } ], } ],}
response = requests.post( f"{BASE}/organizations/12/projects", headers={**HEADERS, "Content-Type": "application/json"}, json=payload,)response.raise_for_status()project = response.json()print(f"Created project #{project['id']}: {project['name']}")Common errors
Section titled “Common errors”| Status | Cause |
|---|---|
401 |
The key’s user may not make the change: for example approving a released project without the right to change the items its approval creates or updates |
404 |
Project, machine, or part ID not found |
422 |
Required fields missing or invalid status value |