Connected Workers Locations

The Connected Workers Locations API lets you build the structured, table‑like location data sets your workers navigate — typically a functional‑location hierarchy. A location table models any set of places as rows, with your own columns.

  • Location table — a table. Has a name, a key, and rows. Can be nested into a hierarchy.
  • Column — a field definition on the table (name, key, data type, ordering, display behavior).
  • Item — a row: an object mapping each column's key to its value ({ "tplnr": "FL-1001", "name": "Pump Station A" }). Rows belong to the table.
Workspace 7
└── Location table 15 "Functional Locations"  (key: functional-locations)
    ├── Columns:  TPLNR (key: tplnr, text, title) · Name (key: name, text)
    └── Items (rows):
          { "id": 1001, "tplnr": "FL-1001", "name": "Pump Station A" }
          { "id": 1002, "tplnr": "FL-1002", "name": "Pump Station B" }

Locations are the entity worker features attach to — work requests, forms, checklists, and flows are filed against a location row. Assets can link to a location, and tours/spaces can be tagged to one. See the Assets guide and the Lists guide for the other two CW table entities.

Base URL & auth

Every endpoint is scoped to a workspace and served under:

https://api.treedis.com/v2/api/workspaces/{workspaceId}/cw/locations

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.

Authentication How to obtain and send an OAuth2 access token.

Keys — address tables and columns by id or slug

Tables and columns each have a key — a URL‑safe slug (lowercase, no spaces), generated automatically from the name on create (or passed). Keys are unique within their scope and never all‑numeric.

  • Anywhere a path takes {columnId}, pass either the numeric id or the key (e.g. …/cw/locations/columns/tplnr). A purely numeric value is an id; anything else is a key. The Locations table itself is not addressed by id — it is the single per-workspace table reached directly under …/cw/locations.
  • Rows reference columns by key — the property names in a row object are column keys.
  • Items (rows) have no key — address them by their numeric id.

Endpoints

Locations is a single per-workspace table. Unlike assets and lists (where you manage many tables), every workspace has exactly one Locations table — it is record-native. There is no table-id segment: GET on the collection returns that one table with its columns and items nested, and every sub-resource hangs directly off …/cw/locations (no {tableId}). There is no GET/PUT/DELETE /{tableId} and no /{tableId}/bulk; create and upsert records through the collection POST and POST /bulk.

Method Path (under /v2/api/workspaces/{workspaceId}/cw/locations) Purpose
GET `` (collection) Get the Locations table (columns + items)
POST `` (collection) Create / upsert the table
POST /bulk Batch insert columns + rows
GET / POST /columns List columns / create a column
GET / PUT / DELETE /columns/{columnId} Get / update / delete a column
GET / POST /items List rows / insert a row
GET / PUT / DELETE /items/{itemId} Get / update / delete a row
POST /items/truncate Truncate items (delete all rows)

GET on the collection returns the table with its columns and items nested. The /columns and /items sub-resources return those slices on their own.

Location tables

Create takes no table id — the id and key are assigned and returned.

  • GET / POST /v2/api/workspaces/{workspaceId}/cw/locations
Field Type Notes
name string Required. Table name.
key string URL‑safe slug. Auto‑generated from name if omitted; unique within the workspace; never all‑numeric.
status active | inactive Required.
parentId number | string | null Parent table — id or key. Tables themselves can be nested into a hierarchy.
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations" \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Functional Locations", "status": "active" }'

GET on the collection returns the single Locations table with its columns and items nested:

{
  "success": true,
  "code": 200,
  "message": "Success",
  "data": {
    "id": 15,
    "key": "functional-locations",
    "name": "Functional Locations",
    "status": "active",
    "parentId": null,
    "itemsCount": 2,
    "columns": [
      {
        "id": 8,
        "key": "tplnr",
        "name": "TPLNR",
        "type": "text",
        "isTitle": true
      },
      { "id": 9, "key": "name", "name": "Name", "type": "text" }
    ],
    "items": [
      { "id": 1001, "tplnr": "FL-1001", "name": "Pump Station A" },
      { "id": 1002, "tplnr": "FL-1002", "name": "Pump Station B" }
    ]
  }
}

Columns

Define the fields of the table. Create takes no column id; the key is derived from the name (or pass your own, unique within the table).

  • GET / POST /v2/api/workspaces/{workspaceId}/cw/locations/columns
  • GET / PUT / DELETE …/columns/{columnId}
Field Type Notes
name string Required. Column name — unique within the table.
key string URL‑safe slug; auto‑generated from name if omitted. Used as the property name in rows.
type enum Required. See the column types below.
order number Display order.
isRequired boolean Whether a value is required.
settings object Type‑specific settings (e.g. maxLength, pattern).
status active | inactive Column status.
isTitle boolean Marks the column shown as the row's display title in the worker view (e.g. the human-readable name). Display only.
isPrimaryKey boolean Marks the table's primary key — the column whose value uniquely identifies a row across the workspace (e.g. a plant-prefixed TPLNR like R400-20-FL-1001). Used to address a row when filing a work request by business key.
isVisible boolean Whether the column shows in the UI.

Column types (type): text · number · date · checkbox · hierarchyParent (links a row to a parent row — used to build the location tree) · reference (links to another table/entity) · locationTag (ties the value to a tour location/tag) · space (a space/environment) · tagStatus (a status tag).

curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations/columns" \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{ "name": "TPLNR", "type": "text", "isRequired": true, "status": "active", "isVisible": true }'

Hierarchy

Build a parent/child tree of location rows with a hierarchyParent column — its value on a row points at the parent row (by the parent's primary‑key value). Treedis rejects a parent assignment that would create a circular reference (400).

Items (rows)

An item is a row — an object mapping each column's key to its value. Responses add the row id. Rows belong to the table.

  • GET / POST /v2/api/workspaces/{workspaceId}/cw/locations/items
  • GET / PUT / DELETE …/items/{itemId}
# insert a row
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations/items" \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{ "tplnr": "FL-1001", "name": "Pump Station A" }'
{
  "success": true,
  "code": 200,
  "message": "Item created successfully",
  "data": { "id": 1001, "tplnr": "FL-1001", "name": "Pump Station A" }
}

A PUT on …/items/{itemId} updates the row's values; send only the columns you want to change. List rows with ?filter[swerk]=R400-20, ?page / ?limit, and ?sortBy / ?sortOrder.

Batch insert

Columns are matched by name/key within the table — an existing column is reused, only a new name creates a new column. A key is optional on the table and columns (omit to auto‑generate from the name).

Batch insert (columns + rows)

POST /v2/api/workspaces/{workspaceId}/cw/locations/bulk — define columns and insert rows into the Locations table in one call, under the locations envelope. This is the call an integrator uses to push a whole functional‑location export in one request.

curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations/bulk" \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [
      {
        "name": "Functional Locations", "key": "functional-locations", "status": "active",
        "columns": [ { "name": "TPLNR", "key": "tplnr", "type": "text", "isPrimaryKey": true }, { "name": "Name", "type": "text" } ],
        "items": [
          { "tplnr": "FL-1001", "name": "Pump Station A" },
          { "tplnr": "FL-1002", "name": "Pump Station B" }
        ]
      }
    ]
  }'

Each surface uses its own batch envelope key — locations here, assets for the Assets surface, lists for the Lists surface.

For data sets above a few thousand rows, upload a CSV and import it asynchronously instead of sending one large /bulk payload.

CSV Import Async CSV import for large data sets — presign, upload to S3, start, and poll.

Batch insert by type

One endpoint for every surface: if a single integration pushes to more than one surface, you can send everything in one call instead of fanning out across paths. POST /v2/api/workspaces/{workspaceId}/cw/bulk takes a tables array where each table carries its own typelocation, asset, list, department, or user — alongside its columns and rows. One request can mix all of them. It is equivalent to posting each table to its surface's own /bulk.

curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/bulk" \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{
    "tables": [
      {
        "type": "location",
        "name": "Functional Locations", "key": "functional-locations", "status": "active",
        "columns": [ { "name": "TPLNR", "key": "tplnr", "type": "text", "isPrimaryKey": true }, { "name": "Name", "type": "text" } ],
        "items": [
          { "tplnr": "FL-1001", "name": "Pump Station A" },
          { "tplnr": "FL-1002", "name": "Pump Station B" }
        ]
      },
      {
        "type": "asset",
        "name": "Assets", "key": "assets", "status": "active",
        "columns": [ { "name": "EQUNR", "key": "equnr", "type": "text", "isPrimaryKey": true }, { "name": "Name", "type": "text" } ],
        "items": [
          { "equnr": "EQ-5001", "name": "Centrifugal Pump" }
        ]
      },
      {
        "type": "list",
        "name": "Priorities", "key": "priorities", "status": "active",
        "columns": [ { "name": "PRIOK", "key": "priok", "type": "text", "isPrimaryKey": true }, { "name": "Name", "type": "text" } ],
        "items": [
          { "priok": "1", "name": "Emergency" },
          { "priok": "2", "name": "High" }
        ]
      },
      {
        "type": "department",
        "name": "Departments", "key": "departments", "status": "active",
        "columns": [ { "name": "Name", "type": "text", "isTitle": true } ],
        "items": [
          { "name": "Maintenance" },
          { "name": "Operations" }
        ]
      }
    ]
  }'

Each table is routed to its surface by its type, so you can create locations, assets, lists, and departments together — or send a single table when that's all you need.

Filing work requests against a location

Locations are the anchor for worker features. Create a work request at the workspace and address the location by location — the location's primary‑key value (its name / code). Treedis finds that location row and files the work request against it. Optionally link an asset with assetKey (the asset table) + asset (that asset row's primary‑key value), and/or a department with department (the department's title). The work request is sent as application/json; attachments go under files as base64 objects.

curl -X POST "https://api.treedis.com/v2/api/workspaces/7/work-requests" \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{
    "location": "R400-20-FL-1001",
    "assetKey": "assets",
    "asset": "R400-20-FL-1001-EQ",
    "title": "Pump leak",
    "status": "open",
    "priority": "high",
    "files": [
      { "filename": "photo.jpg", "contentType": "image/jpeg", "data": "/9j/4AAQSkZJRgABAQ..." }
    ]
  }'

See the Work Requests guide for the full workflow, and Work Orders for turning a request into planned work.

Delete & truncate

  • Delete a single recordDELETE …/locations/columns/{columnId} or …/locations/items/{itemId}.
  • Truncate itemsPOST …/locations/items/truncate removes all rows, keeping the table and its columns.
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations/items/truncate" \
  -H "Authorization: Bearer your-access-token"

Truncate responses report how many rows were removed (data.deleted).

Errors

Errors use the same envelope with success: false and an optional details object:

{
  "success": false,
  "code": 400,
  "message": "Cannot create a hierarchical loop",
  "details": {
    "error": "A table cannot have a parent that would create a circular reference"
  }
}
Status When
400 Validation failed, circular hierarchy, duplicate single‑use column type, or a key/column that can't be resolved
404 Table, column, or item not found

See the Connected Workers Locations tag in the API Reference for the full request and response schemas.