Connected Workers Work Orders
A work order is planned work: a job with a status, a schedule, a place, and someone who owns it. It is the doing half of Connected Workers — the complement of the work request, which is how a problem gets reported in the first place.
- Anchored by business key — like every other public CW endpoint, you send your codes (a functional-location code, an asset's primary-key value, a department name), never Treedis row ids.
- Two kinds of row — native work orders are planned through this API or in the app. Mirror rows are synced read-only from an external CMMS (HxGN EAM, SAP, IBM Maximo). A mirror row cannot be edited here.
- Promote a request into a job — one call turns a work request into a work order, carrying its context over.
Base URL & auth
https://api.treedis.com/v2/api/workspaces/{workspaceId}/workOrders
/work-ordersworks too. Both spellings mount the same router, matching the work request aliases. The examples below useworkOrders.
All endpoints require authentication (OAuth2 Bearer token or API key), and the caller must have access to the workspace. workspaceId is always a numeric ID. An API key is bound to a single workspace and can only address its own.
Reads need workspace membership. Every write additionally needs the ManageProjectAccess workspace permission — the same gate the in-app planning board uses.
Endpoints
| Method | Path (under /v2/api/workspaces/{workspaceId}/workOrders) |
Purpose |
|---|---|---|
GET |
`` (collection) | List work orders + the status vocabulary |
POST |
`` (collection) | Plan a work order |
GET |
/{workOrderId} |
Full detail (checklists, time, messages) |
PATCH |
/{workOrderId} |
Update a native work order |
DELETE |
/{workOrderId} |
Delete a native work order |
PATCH |
/schedule |
Batch schedule — place many at once |
POST |
/from-work-request/{workRequestId} |
Promote a work request |
GET |
/export |
Export every work order as portable JSON |
POST |
/import |
Import portable JSON into this workspace |
This is the integration surface: plan, read, schedule, promote, and move work between workspaces. The per-job interaction surface — ticking checklist items, logging time, posting messages, the worker's own "my work" view — stays inside the app, where it belongs to a signed-in person doing the job.
Listing work orders
curl "https://api.treedis.com/v2/api/workspaces/7/workOrders" \
-H "Authorization: Bearer your-access-token"
{
"success": true,
"code": 200,
"message": "Success",
"data": {
"workOrders": [
{
"id": 4101,
"number": 118,
"provider": "native",
"externalId": null,
"title": "Replace pump seal",
"status": null,
"statusId": "inProgress",
"priority": "high",
"assignee": null,
"assigneeUserId": 512,
"teamId": 8,
"departmentId": 33,
"cwLocationId": 9001,
"cwAssetId": 4402,
"scheduledDate": "2026-06-24T00:00:00.000Z",
"startDate": "2026-06-24T08:00:00.000Z",
"dueDate": "2026-06-25T17:00:00.000Z",
"estimatedDurationMinutes": 180,
"tagId": 7781,
"tourSlug": "north-plant"
}
],
"statuses": [
{ "id": "open", "label": "Open", "color": "#667085", "order": 0, "schedulingBehavior": "pending", "isDefault": true },
{ "id": "inProgress", "label": "In progress", "color": "#2055FF", "order": 1, "schedulingBehavior": "active" },
{ "id": "onHold", "label": "On hold", "color": "#F79009", "order": 2, "schedulingBehavior": "pending" },
{ "id": "complete", "label": "Complete", "color": "#12B76A", "order": 3, "schedulingBehavior": "completed" }
]
}
}
statuses is the workspace's own status vocabulary — read statusId against it. A workspace can rename, recolour and reorder these, so resolve labels from this list rather than hardcoding them. schedulingBehavior (pending · active · completed) is the stable part: it is what "open work" and "done" mean, whatever a workspace calls its statuses.
tagId and tourSlug are resolved for you from the linked asset — they are what a client needs to jump to the job in the 3D tour.
Planning a work order
title is the only required field. Anchors are optional and, like everywhere else in the public API, are your keys:
| Field | What it is |
|---|---|
location |
The location row's primary-key value (e.g. its functional-location code). |
assetKey |
The asset table slug the asset value lives in (e.g. assets). Required when asset is sent. |
asset |
The asset row's primary-key value — the thing being worked on. |
department |
The department's title (its human name). |
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/workOrders" \
-H "Authorization: Bearer your-access-token" \
-H "Content-Type: application/json" \
-d '{
"title": "Replace pump seal",
"description": "Seal is weeping; replace and monitor for 24h.",
"priority": "high",
"statusId": "inProgress",
"location": "R400-20-FL-1001",
"assetKey": "assets",
"asset": "R400-20-FL-1001-EQ",
"department": "Maintenance",
"startDate": "2026-06-24T08:00:00Z",
"dueDate": "2026-06-25T17:00:00Z",
"estimatedDurationMinutes": 180
}'
Returns 201 with { "workOrder": { … } }.
Content fields
| Field | Type | Notes |
|---|---|---|
title |
string | Required. |
description |
string | Job details. |
priority |
string | e.g. high. |
statusId |
string | A status id from the workspace vocabulary. Unknown or omitted → the workspace default. |
startDate / dueDate |
date-time | ISO 8601. dueDate earlier than startDate is rejected with 400. |
scheduledDate |
date-time | Board placement — the day the job is due to run. |
estimatedDurationMinutes |
number | Planned duration. |
assignee |
string | Free-text assignee label (an external system's name for the owner). |
assigneeUserId |
number | A Treedis user id, when you have one. Sets the person who owns the job. |
teamId |
number | The team row the job sits on. |
reporter |
string | Who raised it. |
closeoutNotes |
string | What was actually done. |
customFieldValues |
object | Form answers, keyed by the work order form template's field ids. |
parentWorkOrderId |
number | Makes this row a sub-work-order — one department's step of a cross-department job. |
Two invariants worth knowing before you plan in bulk:
- Department follows the team. Send
teamIdwithoutdepartmentIdand the department is derived from it (a team belongs to exactly one department). With no team but anassigneeUserId, the person's department is used instead. - The sub-work-order tree is one level deep. A work order that already has children cannot itself become a child, and a child cannot be a parent.
Updating and deleting
PATCH sends only the fields you want to change. An anchor you do not mention is left alone; send it as null to clear it.
curl -X PATCH "https://api.treedis.com/v2/api/workspaces/7/workOrders/4101" \
-H "Authorization: Bearer your-access-token" \
-H "Content-Type: application/json" \
-d '{ "statusId": "complete", "closeoutNotes": "Seal replaced, no further weeping." }'
Mirror rows are read-only. A work order synced from an external CMMS carries provider other than native, and PATCH / DELETE on it return 400 — "This work order is mirrored from an external system and cannot be edited". Change it in the source system and let the sync carry it over. See the HxGN EAM, SAP and IBM Maximo sync pages.
Batch scheduling
One call places many work orders on the board — the bulk operation a planner or a scheduling integration actually needs.
curl -X PATCH "https://api.treedis.com/v2/api/workspaces/7/workOrders/schedule" \
-H "Authorization: Bearer your-access-token" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "workOrderId": 4101, "scheduledDate": "2026-06-24", "teamId": 8, "estimatedDurationMinutes": 180 },
{ "workOrderId": 4102, "scheduledDate": "2026-06-25", "assignee": "Dana Levi" }
]
}'
Each item takes workOrderId plus any of scheduledDate, teamId, assignee and estimatedDurationMinutes. Returns the updated rows as { "workOrders": [ … ] }. A work order in a status whose schedulingBehavior is completed is not re-scheduled — finished work does not go back on the board.
Promoting a work request
The reporting-to-doing handoff, in one call. Pass the work request id; the work order inherits its title, description, priority, due date, location, asset and reporter.
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/workOrders/from-work-request/9001" \
-H "Authorization: Bearer your-access-token"
Idempotent. One work order per work request is enforced by a unique index on the source id, so a repeated call returns the work order that already exists rather than creating a duplicate — safe to retry.
Export & import
Both endpoints move work orders between workspaces as portable JSON. Anchors travel as business keys, not ids — a location by its name, an asset by table key + primary-key value — so the same payload re-resolves in the destination.
curl "https://api.treedis.com/v2/api/workspaces/7/workOrders/export" \
-H "Authorization: Bearer your-access-token"
{
"success": true,
"code": 200,
"message": "Success",
"data": {
"kind": "cw-work-orders",
"version": 1,
"workOrders": [
{
"provider": "native",
"externalId": "WO-118",
"title": "Replace pump seal",
"status": "inProgress",
"priority": "high",
"assignee": null,
"reporter": null,
"department": "Maintenance",
"scheduledDate": "2026-06-24T00:00:00.000Z",
"dueDate": "2026-06-25T17:00:00.000Z",
"location": "R400-20-FL-1001",
"assetKey": "assets",
"asset": "R400-20-FL-1001-EQ",
"customFieldValues": null
}
]
}
}
Post the same payload back to import it; the response is { "imported": n, "skipped": n }. Ids, workspace and timestamps are dropped on export — what travels is the work, not the row. A work order whose location or asset cannot be resolved in the destination is skipped, not guessed at.
Import the target tables before the work orders: push Locations, Assets and Departments first, or every anchor will fail to resolve.
How work orders get into Treedis
There are three ways, and they coexist in one board:
- This API — plan them directly, or import them.
- Promoted from a work request — someone in the field reported it, a planner turned it into a job.
- Synced from an external CMMS — HxGN EAM, SAP or IBM Maximo. Those rows are mirrors: read-only here, owned by the source system.
Errors
| Status | When |
|---|---|
400 |
title missing, dueDate before startDate, an invalid sub-work-order parent, a mirror row edited, an unresolvable anchor, or asset without assetKey |
401 |
Missing or invalid credentials |
403 |
No workspace access, an API key addressing another workspace, or a write without ManageProjectAccess |
404 |
The work order (or work request) is not in this workspace, or no location / asset row matches the given value |
See the Connected Workers Work Orders tag in the API Reference for the full request and response schemas.

