Purple PM API Documentation

Machine-readable OpenAPI 3.0 specification: https://marketplace.moveworks.com/api/purple-suite/pm/openapi.json

The consolidated all-apps document at https://marketplace.moveworks.com/api/purple-suite/openapi.json can be narrowed to this app with ?apps=pm, or combined with other apps comma-separated (e.g. ?apps=pm,itsm).

Overview

--- **Acting as a user (`X-PS-Impersonate-User`).** Every endpoint accepts an optional `X-PS-Impersonate-User` request header whose value is the email of the instance user to act as. The effective user resolves in this order: the header if present, else the instance's configured default MCP user, else none. User-scoped paths additionally accept the literal `me` in place of an email, and Graph-style apps also serve `/me/…` twins of their `/users/{email}/…` paths that resolve the same way. This header is honored by all operations but is intentionally omitted from each operation's parameter list so it is not surfaced as a per-tool argument by MCP clients; see the `ImpersonateUser` entry under `components.parameters`.

Endpoints

GET /api/purple-suite/pm/projects

List projects

Purple Planner projects are the delivery workstreams that hold tasks, sprints and milestones, each with an owner, status, dates, progress and budget. This is project delivery, not a CRM account or an ERP cost centre. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Project

    • id string
    • name string
    • status string
    • owner string
    • startDate string
    • endDate string
    • progress integer
    • budget number
    • initiativeIds arrayIDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)
      IDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)

      array of:

      string

    • teamIds arrayIDs of the teams that own this project
      IDs of the teams that own this project

      array of:

      string

    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/projects

Create project

Open a new delivery workstream in Purple Planner. Only for genuinely new projects — to change an existing one use the update-project tool, and to file a unit of work use create-task instead.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Project

  • id string
  • name string
  • status string
  • owner string
  • startDate string
  • endDate string
  • progress integer
  • budget number
  • initiativeIds arrayIDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)
    IDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)

    array of:

    string

  • teamIds arrayIDs of the teams that own this project
    IDs of the teams that own this project

    array of:

    string

  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Project

  • id string
  • name string
  • status string
  • owner string
  • startDate string
  • endDate string
  • progress integer
  • budget number
  • initiativeIds arrayIDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)
    IDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)

    array of:

    string

  • teamIds arrayIDs of the teams that own this project
    IDs of the teams that own this project

    array of:

    string

  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/projects/{id}

Get project

Fetch one Purple Planner project by id (e.g. PROJ-001) with its owner, status, dates, progress, budget and the initiatives/teams it rolls up to.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Project

  • id string
  • name string
  • status string
  • owner string
  • startDate string
  • endDate string
  • progress integer
  • budget number
  • initiativeIds arrayIDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)
    IDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)

    array of:

    string

  • teamIds arrayIDs of the teams that own this project
    IDs of the teams that own this project

    array of:

    string

  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/projects/{id}

Delete project

Permanently delete a Purple Planner project. Destructive and irreversible, and its tasks/sprints keep a dangling projectId — prefer setting status to completed or cancelled with the update-project tool unless the record was created in error.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/projects/{id}

Update project

Partially update a Purple Planner project — status, owner, dates, progress, budget, initiativeIds or teamIds. Status changes are state-machine checked: a completed project cannot be reactivated (422).

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Project

  • id string
  • name string
  • status string
  • owner string
  • startDate string
  • endDate string
  • progress integer
  • budget number
  • initiativeIds arrayIDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)
    IDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)

    array of:

    string

  • teamIds arrayIDs of the teams that own this project
    IDs of the teams that own this project

    array of:

    string

  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Project

  • id string
  • name string
  • status string
  • owner string
  • startDate string
  • endDate string
  • progress integer
  • budget number
  • initiativeIds arrayIDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)
    IDs of the initiatives this project rolls up to (Linear-style initiative→project hierarchy)

    array of:

    string

  • teamIds arrayIDs of the teams that own this project
    IDs of the teams that own this project

    array of:

    string

  • createdAt string
  • updatedAt string
404
Not found
422
State machine violation — e.g. cannot reactivate a completed project

GET /api/purple-suite/pm/tasks

List tasks

Purple Planner tasks (issues) are the unit of work inside a project, carrying assignee, priority, story points, sprint, labels, dependencies and blockers. These are delivery issues, not ITSM incidents/service requests and not HR cases. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Task

    • id string
    • title string
    • projectId string
    • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
    • assignee string
    • priority string
    • storyPoints integer
    • dueDate string
    • sprintId string
    • dependencies arrayIDs of tasks this task depends on
      IDs of tasks this task depends on

      array of:

      string

    • labelIds arrayIDs of labels applied to this task (issue)
      IDs of labels applied to this task (issue)

      array of:

      string

    • teamId stringID of the team that owns this task (issue)
    • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
    • blockers arrayActive blocker IDs; task cannot be completed while non-empty
      Active blocker IDs; task cannot be completed while non-empty

      array of:

      string

    • reopenReason stringRequired when reopening a cancelled task
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.

POST /api/purple-suite/pm/tasks

Create task

File a new task (issue) in a Purple Planner project, optionally with assignee, priority, story points, sprint and labels. Returns 422 if the target project is already completed or cancelled.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Task

  • id string
  • title string
  • projectId string
  • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
  • assignee string
  • priority string
  • storyPoints integer
  • dueDate string
  • sprintId string
  • dependencies arrayIDs of tasks this task depends on
    IDs of tasks this task depends on

    array of:

    string

  • labelIds arrayIDs of labels applied to this task (issue)
    IDs of labels applied to this task (issue)

    array of:

    string

  • teamId stringID of the team that owns this task (issue)
  • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
  • blockers arrayActive blocker IDs; task cannot be completed while non-empty
    Active blocker IDs; task cannot be completed while non-empty

    array of:

    string

  • reopenReason stringRequired when reopening a cancelled task
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Task

  • id string
  • title string
  • projectId string
  • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
  • assignee string
  • priority string
  • storyPoints integer
  • dueDate string
  • sprintId string
  • dependencies arrayIDs of tasks this task depends on
    IDs of tasks this task depends on

    array of:

    string

  • labelIds arrayIDs of labels applied to this task (issue)
    IDs of labels applied to this task (issue)

    array of:

    string

  • teamId stringID of the team that owns this task (issue)
  • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
  • blockers arrayActive blocker IDs; task cannot be completed while non-empty
    Active blocker IDs; task cannot be completed while non-empty

    array of:

    string

  • reopenReason stringRequired when reopening a cancelled task
  • createdAt string
  • updatedAt string
422
State machine violation — e.g. cannot add a task to a completed or cancelled project

GET /api/purple-suite/pm/tasks/{id}

Get task

Fetch one Purple Planner task (issue) by id with its status, assignee, sprintId, labels, dependencies, blockers and openSubtasks — use it to check whether a task is actually completable.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Task

  • id string
  • title string
  • projectId string
  • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
  • assignee string
  • priority string
  • storyPoints integer
  • dueDate string
  • sprintId string
  • dependencies arrayIDs of tasks this task depends on
    IDs of tasks this task depends on

    array of:

    string

  • labelIds arrayIDs of labels applied to this task (issue)
    IDs of labels applied to this task (issue)

    array of:

    string

  • teamId stringID of the team that owns this task (issue)
  • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
  • blockers arrayActive blocker IDs; task cannot be completed while non-empty
    Active blocker IDs; task cannot be completed while non-empty

    array of:

    string

  • reopenReason stringRequired when reopening a cancelled task
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/tasks/{id}

Delete task

Permanently delete a Purple Planner task. Destructive and irreversible — to finish work normally set status to done/closed with the update-task tool; only delete issues filed by mistake.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/tasks/{id}

Update task

Partially update a Purple Planner task — retitle, reassign, reprioritise, move it to another sprint, or change status. Completion is guarded: moving to done/closed fails with 422 while openSubtasks > 0 or blockers is non-empty, and reopening a cancelled task requires reopenReason. To record that this task waits on another, use the add-dependency tool instead.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Task

  • id string
  • title string
  • projectId string
  • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
  • assignee string
  • priority string
  • storyPoints integer
  • dueDate string
  • sprintId string
  • dependencies arrayIDs of tasks this task depends on
    IDs of tasks this task depends on

    array of:

    string

  • labelIds arrayIDs of labels applied to this task (issue)
    IDs of labels applied to this task (issue)

    array of:

    string

  • teamId stringID of the team that owns this task (issue)
  • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
  • blockers arrayActive blocker IDs; task cannot be completed while non-empty
    Active blocker IDs; task cannot be completed while non-empty

    array of:

    string

  • reopenReason stringRequired when reopening a cancelled task
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Task

  • id string
  • title string
  • projectId string
  • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
  • assignee string
  • priority string
  • storyPoints integer
  • dueDate string
  • sprintId string
  • dependencies arrayIDs of tasks this task depends on
    IDs of tasks this task depends on

    array of:

    string

  • labelIds arrayIDs of labels applied to this task (issue)
    IDs of labels applied to this task (issue)

    array of:

    string

  • teamId stringID of the team that owns this task (issue)
  • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
  • blockers arrayActive blocker IDs; task cannot be completed while non-empty
    Active blocker IDs; task cannot be completed while non-empty

    array of:

    string

  • reopenReason stringRequired when reopening a cancelled task
  • createdAt string
  • updatedAt string
404
Not found
422
State machine violation — e.g. task has open subtasks or active blockers preventing completion, or reopenReason missing when reopening a cancelled task

POST /api/purple-suite/pm/tasks/{id}/add-dependency

Add a task dependency

Record that this Purple Planner task is blocked until dependency_id finishes, appending to its dependencies array. Use this rather than patching the task, because the server rejects (400) any edge that would create a circular dependency.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

application/json — required

  • dependency_id string requiredID of the task that must complete before this task

Responses

200
Updated task with new dependency

application/json

Task

  • id string
  • title string
  • projectId string
  • status stringCurrent task status. 'closed' is a terminal state equivalent to 'done'; transitions to 'done' or 'closed' are blocked while openSubtasks > 0 or blockers is non-empty.
  • assignee string
  • priority string
  • storyPoints integer
  • dueDate string
  • sprintId string
  • dependencies arrayIDs of tasks this task depends on
    IDs of tasks this task depends on

    array of:

    string

  • labelIds arrayIDs of labels applied to this task (issue)
    IDs of labels applied to this task (issue)

    array of:

    string

  • teamId stringID of the team that owns this task (issue)
  • openSubtasks integerNumber of open subtasks; task cannot be completed while > 0
  • blockers arrayActive blocker IDs; task cannot be completed while non-empty
    Active blocker IDs; task cannot be completed while non-empty

    array of:

    string

  • reopenReason stringRequired when reopening a cancelled task
  • createdAt string
  • updatedAt string
400
dependency_id missing or circular dependency detected
404
Task or dependency task not found

GET /api/purple-suite/pm/sprints

List sprints

Purple Planner sprints are the time-boxed iterations (planned | active | completed) of a project that tasks are assigned to via Task.sprintId, with velocity and completedPoints. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Sprint

    • id string
    • name string
    • projectId string
    • status string
    • startDate string
    • endDate string
    • velocity integer
    • completedPoints integer
    • startedAt string
    • completedAt string
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/sprints

Create sprint

Plan a new time-boxed iteration on a Purple Planner project. New sprints are 'planned'; activate one with the start-sprint tool rather than by creating another.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Sprint

  • id string
  • name string
  • projectId string
  • status string
  • startDate string
  • endDate string
  • velocity integer
  • completedPoints integer
  • startedAt string
  • completedAt string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Sprint

  • id string
  • name string
  • projectId string
  • status string
  • startDate string
  • endDate string
  • velocity integer
  • completedPoints integer
  • startedAt string
  • completedAt string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/sprints/{id}

Get sprint

Fetch one Purple Planner sprint by id with its dates, status, velocity, completedPoints and startedAt/completedAt stamps — the basis for burndown or sprint-health answers.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Sprint

  • id string
  • name string
  • projectId string
  • status string
  • startDate string
  • endDate string
  • velocity integer
  • completedPoints integer
  • startedAt string
  • completedAt string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/sprints/{id}

Delete sprint

Permanently delete a Purple Planner sprint. Destructive and irreversible, and tasks keep a dangling sprintId — to close out an iteration properly use complete-sprint, which rehomes unfinished work.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/sprints/{id}

Update sprint

Partially update sprint metadata such as name, dates or velocity. For lifecycle changes use start-sprint / complete-sprint instead — those enforce the rules and move the tasks.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Sprint

  • id string
  • name string
  • projectId string
  • status string
  • startDate string
  • endDate string
  • velocity integer
  • completedPoints integer
  • startedAt string
  • completedAt string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Sprint

  • id string
  • name string
  • projectId string
  • status string
  • startDate string
  • endDate string
  • velocity integer
  • completedPoints integer
  • startedAt string
  • completedAt string
  • createdAt string
  • updatedAt string
404
Not found

POST /api/purple-suite/pm/sprints/{id}/start

Start a sprint

Activate a planned Purple Planner sprint and stamp startedAt. Requires at least one task assigned to it (Task.sprintId), otherwise 422. Use this rather than patching status directly.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Sprint started

application/json

Sprint

  • id string
  • name string
  • projectId string
  • status string
  • startDate string
  • endDate string
  • velocity integer
  • completedPoints integer
  • startedAt string
  • completedAt string
  • createdAt string
  • updatedAt string
404
Not found
422
Sprint has no tasks assigned and cannot be started

POST /api/purple-suite/pm/sprints/{id}/complete

Complete a sprint

Close out a Purple Planner sprint and sweep its unfinished tasks (status != done) into next_sprint_id, or back to the backlog (sprintId=null, status=todo) when that is omitted. Irreversible, and it rewrites those tasks — the response reports moved_tasks and warns when open work was moved.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

application/json

  • next_sprint_id stringSprint ID to move incomplete tasks into; omit to return tasks to backlog

Responses

200
Sprint completed

application/json

  • sprint object

    Sprint

    • id string
    • name string
    • projectId string
    • status string
    • startDate string
    • endDate string
    • velocity integer
    • completedPoints integer
    • startedAt string
    • completedAt string
    • createdAt string
    • updatedAt string
  • moved_tasks integerNumber of incomplete tasks moved or returned to backlog
  • warning string
404
Not found

GET /api/purple-suite/pm/milestones

List milestones

Purple Planner milestones are dated delivery checkpoints on a project (upcoming | in_progress | completed | at_risk), coarser than tasks and independent of sprints. Use these for "are we going to hit the date" questions. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Milestone

    • id string
    • name string
    • projectId string
    • status string
    • dueDate string
    • completedAt string
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/milestones

Create milestone

Add a dated delivery checkpoint to a Purple Planner project. Use a milestone for a commitment date (e.g. 'MVP complete'), and a task for work someone has to do.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Milestone

  • id string
  • name string
  • projectId string
  • status string
  • dueDate string
  • completedAt string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Milestone

  • id string
  • name string
  • projectId string
  • status string
  • dueDate string
  • completedAt string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/milestones/{id}

Get milestone

Fetch one Purple Planner milestone by id with its project, due date, status and completedAt stamp.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Milestone

  • id string
  • name string
  • projectId string
  • status string
  • dueDate string
  • completedAt string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/milestones/{id}

Delete milestone

Permanently delete a Purple Planner milestone. Destructive and irreversible — if the checkpoint simply slipped or was met, update its dueDate or status instead.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/milestones/{id}

Update milestone

Partially update a Purple Planner milestone — move the due date, or flag it at_risk / in_progress / completed as delivery confidence changes.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Milestone

  • id string
  • name string
  • projectId string
  • status string
  • dueDate string
  • completedAt string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Milestone

  • id string
  • name string
  • projectId string
  • status string
  • dueDate string
  • completedAt string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/pm/initiatives

List initiatives

Purple Planner initiatives are the portfolio layer above projects (e.g. "26Q2 Platform Investments"), which projects roll up to via Project.initiativeIds. Use these for portfolio/quarterly-theme questions; the delivery work itself lives in projects and tasks. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Initiative

    A cross-project initiative (Linear-style); projects roll up to initiatives via Project.initiativeIds.
    • id string
    • name string
    • description string
    • status string
    • owner string
    • targetDate string
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/initiatives

Create initiative

Create a cross-project initiative in Purple Planner to group related projects under one portfolio theme and owner.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Initiative

A cross-project initiative (Linear-style); projects roll up to initiatives via Project.initiativeIds.
  • id string
  • name string
  • description string
  • status string
  • owner string
  • targetDate string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Initiative

A cross-project initiative (Linear-style); projects roll up to initiatives via Project.initiativeIds.
  • id string
  • name string
  • description string
  • status string
  • owner string
  • targetDate string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/initiatives/{id}

Get initiative

Fetch one Purple Planner initiative by id (e.g. INIT-001) with its owner, status and target date. Find the projects underneath it by filtering projects on initiativeIds.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Initiative

A cross-project initiative (Linear-style); projects roll up to initiatives via Project.initiativeIds.
  • id string
  • name string
  • description string
  • status string
  • owner string
  • targetDate string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/initiatives/{id}

Delete initiative

Permanently delete a Purple Planner initiative. Destructive and irreversible, and projects keep a dangling id in initiativeIds — mark it completed instead when the portfolio theme simply ends.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/initiatives/{id}

Update initiative

Partially update a Purple Planner initiative — rename it, change owner, target date or status (planned | active | completed).

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Initiative

A cross-project initiative (Linear-style); projects roll up to initiatives via Project.initiativeIds.
  • id string
  • name string
  • description string
  • status string
  • owner string
  • targetDate string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Initiative

A cross-project initiative (Linear-style); projects roll up to initiatives via Project.initiativeIds.
  • id string
  • name string
  • description string
  • status string
  • owner string
  • targetDate string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/pm/labels

List labels

Purple Planner labels are the tag vocabulary applied to tasks via Task.labelIds (e.g. "p1", "tech-debt"), each with a name, colour and description. Resolve a label name to its id here before filtering tasks by label. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Label

    An issue label/tag applied to tasks via Task.labelIds.
    • id string
    • name string
    • color string
    • description string
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/labels

Create label

Add a new label to the Purple Planner tag vocabulary. Check the existing labels first — this creates a new tag rather than applying one; applying is done by setting labelIds on a task.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Label

An issue label/tag applied to tasks via Task.labelIds.
  • id string
  • name string
  • color string
  • description string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Label

An issue label/tag applied to tasks via Task.labelIds.
  • id string
  • name string
  • color string
  • description string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/labels/{id}

Get label

Fetch one Purple Planner label by id with its name, colour and description.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Label

An issue label/tag applied to tasks via Task.labelIds.
  • id string
  • name string
  • color string
  • description string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/labels/{id}

Delete label

Permanently delete a Purple Planner label from the workspace vocabulary. Destructive — tasks keep the stale id in labelIds; to untag a single task, patch that task's labelIds instead.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/labels/{id}

Update label

Rename or recolour a Purple Planner label. Tasks referencing it by id pick the change up automatically.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Label

An issue label/tag applied to tasks via Task.labelIds.
  • id string
  • name string
  • color string
  • description string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Label

An issue label/tag applied to tasks via Task.labelIds.
  • id string
  • name string
  • color string
  • description string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/pm/users

List workspace members

Purple Planner workspace members are the people who can be a task assignee or project owner in this tool. This is not the chat roster, not the HR employee record, and not the canonical identity directory; use it to resolve an assignee or owner within Purple Planner. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    User

    A workspace member (issue assignee / project lead resolution).
    • id string
    • name string
    • email string
    • role string
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/users

Add workspace member

Add a person to the Purple Planner workspace so they can be assigned issues or own projects. This creates a project-tool membership only — it does not create an HR employee record or an identity account.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

User

A workspace member (issue assignee / project lead resolution).
  • id string
  • name string
  • email string
  • role string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

User

A workspace member (issue assignee / project lead resolution).
  • id string
  • name string
  • email string
  • role string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/users/{id}

Get workspace member

Fetch one Purple Planner workspace member by id (name, email, role) — the usual way to turn an assignee or owner reference into a person.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

User

A workspace member (issue assignee / project lead resolution).
  • id string
  • name string
  • email string
  • role string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/users/{id}

Remove workspace member

Remove a member from the Purple Planner workspace. Destructive and irreversible; their tasks and projects keep the id as a dangling assignee/owner, so reassign that work first.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/users/{id}

Update workspace member

Update a Purple Planner member's name, email or role. Affects this project tool only, not their HR record or chat account.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

User

A workspace member (issue assignee / project lead resolution).
  • id string
  • name string
  • email string
  • role string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

User

A workspace member (issue assignee / project lead resolution).
  • id string
  • name string
  • email string
  • role string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/pm/status_updates

List status updates

Purple Planner status updates are narrative progress posts written against a project or initiative, each with a health flag (on_track | at_risk | off_track). Use these for "what's the latest on X" questions; numeric progress lives on the project record. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    StatusUpdate

    A progress/status update posted against a project or initiative.
    • id string
    • projectId stringProject this update is about, if applicable
    • initiativeId stringInitiative this update is about, if applicable
    • author string
    • body string
    • health string
    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/status_updates

Post status update

Post a narrative progress update against a Purple Planner project or initiative, with body text and a health flag. Use this to communicate status; use update-project to change the project's own status field.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

StatusUpdate

A progress/status update posted against a project or initiative.
  • id string
  • projectId stringProject this update is about, if applicable
  • initiativeId stringInitiative this update is about, if applicable
  • author string
  • body string
  • health string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

StatusUpdate

A progress/status update posted against a project or initiative.
  • id string
  • projectId stringProject this update is about, if applicable
  • initiativeId stringInitiative this update is about, if applicable
  • author string
  • body string
  • health string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/status_updates/{id}

Get status update

Fetch one Purple Planner status update by id with its author, body, health flag and the project or initiative it covers.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

StatusUpdate

A progress/status update posted against a project or initiative.
  • id string
  • projectId stringProject this update is about, if applicable
  • initiativeId stringInitiative this update is about, if applicable
  • author string
  • body string
  • health string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/status_updates/{id}

Delete status update

Permanently delete a Purple Planner status update, removing it from the project's update history. Destructive and irreversible.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/status_updates/{id}

Update status update

Edit a previously posted Purple Planner status update — correct the body text or revise the health flag.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

StatusUpdate

A progress/status update posted against a project or initiative.
  • id string
  • projectId stringProject this update is about, if applicable
  • initiativeId stringInitiative this update is about, if applicable
  • author string
  • body string
  • health string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

StatusUpdate

A progress/status update posted against a project or initiative.
  • id string
  • projectId stringProject this update is about, if applicable
  • initiativeId stringInitiative this update is about, if applicable
  • author string
  • body string
  • health string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/pm/teams

List teams

Purple Planner teams are the delivery squads that own projects (Project.teamIds) and issues (Task.teamId), each with a short key such as PLAT and a memberIds roster. These are product/engineering squads, not HR departments or chat channels. Filter/sort server-side with $filter, $orderby, $select, $search, $top, $skip and $count (MCP clients send these as _filter, _orderby, …) rather than listing everything and filtering locally.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
limitqueryintegernoLegacy page size (default 50). Prefer $top. Ignored when $top/$skip are used.
cursorquerystringnoLegacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top.
$filterquerystringnoOData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: "status eq 'active'"; "salary gt 50000 and department eq 'Engineering'"; "contains(tolower(name),'acme')"; "closeDate gt 2026-01-01".
$selectquerystringnoComma-separated list of fields to return, e.g. "id,firstName,email". Nested fields via slash ("pto_balance/vacation_days"). The id field is always included.
$orderbyquerystringnoSort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last.
$searchquerystringnoFree-text, case-insensitive substring match across the resource's searchable fields.
$topqueryintegernoMaximum number of items to return (page size).
$skipqueryintegernoNumber of matching items to skip before returning results (offset paging). Combine with $top.
$countquerybooleannoWhen true, include @odata.count (total matches after $filter/$search, before paging) in the response.

Responses

200
Paginated list

application/json

  • data array

    array of:

    Team

    A team (Linear-style); projects/tasks are owned by a team via Project.teamIds / Task.teamId.
    • id string
    • name string
    • key stringShort team key (e.g. used in issue identifiers like PLAT-42)
    • memberIds arrayIDs of the users on this team
      IDs of the users on this team

      array of:

      string

    • createdAt string
    • updatedAt string
  • nextCursor stringCursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.
  • total integerTotal documents in the collection.
  • @odata.count integerPresent only when $count=true: total matches after $filter/$search.
  • @odata.truncated booleanPresent and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400
Invalid OData query (e.g. malformed $filter)

POST /api/purple-suite/pm/teams

Create team

Create a delivery squad in Purple Planner with a short key (e.g. PLAT) and member roster, so projects and issues can be assigned to it.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes

Request body

application/json — required

Team

A team (Linear-style); projects/tasks are owned by a team via Project.teamIds / Task.teamId.
  • id string
  • name string
  • key stringShort team key (e.g. used in issue identifiers like PLAT-42)
  • memberIds arrayIDs of the users on this team
    IDs of the users on this team

    array of:

    string

  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Team

A team (Linear-style); projects/tasks are owned by a team via Project.teamIds / Task.teamId.
  • id string
  • name string
  • key stringShort team key (e.g. used in issue identifiers like PLAT-42)
  • memberIds arrayIDs of the users on this team
    IDs of the users on this team

    array of:

    string

  • createdAt string
  • updatedAt string

GET /api/purple-suite/pm/teams/{id}

Get team

Fetch one Purple Planner team by id with its name, key and memberIds roster.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Found

application/json

Team

A team (Linear-style); projects/tasks are owned by a team via Project.teamIds / Task.teamId.
  • id string
  • name string
  • key stringShort team key (e.g. used in issue identifiers like PLAT-42)
  • memberIds arrayIDs of the users on this team
    IDs of the users on this team

    array of:

    string

  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/pm/teams/{id}

Delete team

Permanently delete a Purple Planner team. Destructive and irreversible, and projects/tasks keep a dangling team reference — reassign their ownership first.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/pm/teams/{id}

Update team

Rename a Purple Planner team, change its key, or add/remove people by rewriting memberIds.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyes
idpathstringyes

Request body

Fields to update (partial)

application/json

Team

A team (Linear-style); projects/tasks are owned by a team via Project.teamIds / Task.teamId.
  • id string
  • name string
  • key stringShort team key (e.g. used in issue identifiers like PLAT-42)
  • memberIds arrayIDs of the users on this team
    IDs of the users on this team

    array of:

    string

  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Team

A team (Linear-style); projects/tasks are owned by a team via Project.teamIds / Task.teamId.
  • id string
  • name string
  • key stringShort team key (e.g. used in issue identifiers like PLAT-42)
  • memberIds arrayIDs of the users on this team
    IDs of the users on this team

    array of:

    string

  • createdAt string
  • updatedAt string
404
Not found