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 — notes, 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 {tableId} or {columnId}, pass either the numeric id or the key (e.g. …/cw/locations/functional-locations/columns/tplnr). A purely numeric value is an id; anything else is a key.
  • 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, so there is no GET /{tableId} — retrieve the table with GET on the collection. {tableId} in the sub-resource paths below always refers to that one table, addressable by its id or the key locations.

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

List endpoints return shallow objects (no columns/items); read the table's columns and items from their sub-resource endpoints below.

Location tables

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

  • GET / POST /v2/api/workspaces/{workspaceId}/cw/locations
  • PUT / DELETE /v2/api/workspaces/{workspaceId}/cw/locations/{tableId}
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 as a shallow object — read its columns from /{tableId}/columns and its items from /{tableId}/items:

{
  "success": true,
  "code": 200,
  "message": "Success",
  "data": [
    {
      "id": 15,
      "key": "functional-locations",
      "name": "Functional Locations",
      "status": "active",
      "parentId": null,
      "itemsCount": 2
    }
  ]
}

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/{tableId}/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 note 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/functional-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/{tableId}/items
  • GET / PUT / DELETE …/items/{itemId}
# insert a row
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations/functional-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 their table — an existing column is reused, only a new name creates a new column. A key is optional on tables and columns (omit to auto‑generate from the name).

Batch insert into a table

POST /v2/api/workspaces/{workspaceId}/cw/locations/{tableId}/bulk — optionally define columns, then insert rows.

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

Batch insert tables

POST /v2/api/workspaces/{workspaceId}/cw/locations/bulk — create multiple tables at once, each with its columns and rows. 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.

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, or list — alongside its columns and rows. One request can mix all three. 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" }
        ]
      }
    ]
  }'

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

Filing notes against a location

Locations are the anchor for worker features. Create a note 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 note against it. Optionally link an asset with assetKey (the asset table) + asset (that asset row's primary‑key value). The note is sent as application/json; attachments go under files as base64 objects.

curl -X POST "https://api.treedis.com/v2/api/workspaces/7/notes" \
  -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 Migration Guide for the full notes workflow.

Delete & truncate

  • Delete a single recordDELETE …/locations/{tableId}, …/columns/{columnId}, or …/items/{itemId}.
  • Truncate itemsPOST …/locations/{tableId}/items/truncate removes all rows, keeping the table and its columns.
curl -X POST "https://api.treedis.com/v2/api/workspaces/7/cw/locations/functional-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.