Workspaces, Spaces, Folders, Lists, and fields

Workspace hierarchy#

Method Endpoint Implemented behavior
GET /workspaces/{ws} Workspace configuration.
GET /workspaces/{ws}/hierarchy Nested Space → Folder/List hierarchy with stable IDs.
GET /workspaces/{ws}/diagnostics Catalog revision and invalid/duplicate/orphan diagnostics.
GET /workspaces/{ws}/spaces List Spaces.
POST /workspaces/{ws}/spaces Create a Space at the workspace root.
GET /workspaces/{ws}/folders?space_id= List Folders, optionally in one Space.
POST /workspaces/{ws}/folders Create a Folder inside a Space (space_id).
GET /workspaces/{ws}/lists?space_id=&folder_id= List Lists with optional ancestry filters.
POST /workspaces/{ws}/lists Create a List inside a Folder (folder_id) or Space (space_id).

Single Space, Folder, and List endpoints support GET, PATCH, PUT, and DELETE:

/workspaces/{ws}/spaces/{spaceId}
/workspaces/{ws}/folders/{folderId}
/workspaces/{ws}/lists/{listId}

DELETE on a container permanently deletes its whole subtree from the current server state — every Item, Doc, Page, View, and attachment below it — and then runs the same reference cleanup as Item deletion (surviving parent_task, relationships, documents, and relationship-type custom fields drop the deleted IDs; a cleanup that would empty a required field aborts the whole delete with 409 RESOURCE_IN_USE). This API operation does not move resources into the plugin's _trash folder. Use If-Match, keep server backups, and restore from retained file history when recovery is required.

Structured creation writes the marker file (_space.md / _folder.md / _list.md) and derives ancestry from where the directory sits. Send only a name (plus any domain fields such as icon/color) and the parent locator:

# Create a Space, then a Folder in it, then a List in the Folder.
curl -sX POST "$IT_BASE/workspaces/$IT_WS/spaces" -H "Authorization: Bearer $IT_KEY" \
  -H 'Content-Type: application/json' -d '{"name":"Product","icon":"compass","color":"#2563eb"}'
curl -sX POST "$IT_BASE/workspaces/$IT_WS/folders" -H "Authorization: Bearer $IT_KEY" \
  -H 'Content-Type: application/json' -d '{"name":"Backend","space_id":"SPC-…"}'
curl -sX POST "$IT_BASE/workspaces/$IT_WS/lists" -H "Authorization: Bearer $IT_KEY" \
  -H 'Content-Type: application/json' -d '{"name":"API","folder_id":"FLD-…"}'

The server generates the SPC-/FLD-/LST- id and a collision-free directory. The parent locator (space_id/folder_id) selects the destination only and is never written into the marker, so it can never disagree with resolved ancestry.

A new Space is seeded with the default Kanban status_set (todo/in_progress/done/complete) — the same template the plugin's Space wizard preselects — unless the request supplies its own status_set. Send an explicit status_set: [] to keep pure inheritance from the workspace level.


Fields#

Workspace, Space, Folder, List, Item, Doc, Page, and View all implement:

GET    {resource}/fields
GET    {resource}/fields/{fieldId}
PUT    {resource}/fields/{fieldId}
DELETE {resource}/fields/{fieldId}

Use PUT with { "value": ... }. The optional scope can be a query parameter or body property.

Scopes#

Scope Contents
core Frontmatter properties plus implemented structural/derived Item fields.
custom Item custom fields, including secrets.
content Only the Markdown body.

There is no secret scope: a secret is scope=custom, kind=secret.

Kinds#

Descriptors use kind=standard, property, custom, secret, or markdown. field_type adds details such as structural, derived, or the effective custom-field type. Respect read_only.

If a field ID exists in multiple scopes, omitting scope returns 409 AMBIGUOUS_FIELD rather than changing the wrong value.

# Core field
curl "$IT_BASE/workspaces/$IT_WS/items/TSK-00001/fields/status?scope=core" \
  -H "Authorization: Bearer $IT_KEY"

# Custom field
curl -X PUT "$IT_BASE/workspaces/$IT_WS/items/TSK-00001/fields/cf-owner" \
  -H "Authorization: Bearer $IT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"scope":"custom","value":"Ada"}'

# Body as Markdown only
curl "$IT_BASE/workspaces/$IT_WS/items/TSK-00001/fields/body?scope=content&format=md" \
  -H "Authorization: Bearer $IT_KEY"

Item-specific descriptors include writable structural list_id, read-only derived waiting_on, domain-aware relationships, and redacted secret custom fields. Secret and automatic-progress fields reject ordinary writes.

Effective field catalog#

GET /workspaces/{ws}/field-catalog?list_id={listId}

The response contains fields and effective_config. The latter includes the resolved status set, priorities, legacy-key task_types, tag palette, context labels, custom-field definitions, features, and field labels. Omit list_id for Workspace-level definitions. status_set, priorities, and task_types are never empty: levels that configure nothing resolve to the same built-in defaults the plugin uses, so labels lookups (e.g. labels.priority) always have a source.

Comments, checklist entries, activity entries, and attachment metadata are also available as complete Item fields. Prefer the individual child routes in Items and search when changing one comment, checklist entry, or attachment. activity remains server-managed and read-only.