Skip to content
Select language:English
Select theme

Projects API

List, create, update, delete, and search engineering projects with nested jobs and operations.

Updated

Base path: /v1/organizations/:organization_id/projects

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
{
"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" }
]
}
]
}

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 }
]
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.

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)
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
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)
# Search projects by name
curl "https://api.toolingmetrics.com/v1/organizations/12/projects/search?q=Cylinder" \
-H "Authorization: Bearer YOUR_TOKEN"
# Get a project with full job and operation detail
curl "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']}")
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