Purple Chat API Documentation

Machine-readable OpenAPI 3.0 specification: https://marketplace.moveworks.com/api/purple-suite/chat/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=chat, or combined with other apps comma-separated (e.g. ?apps=chat,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/chat/channels

List Purple Collab channels

Public and private channels in the Purple Collab chat workspace (the Slack-style team messaging system — not an ITSM queue or a community forum). Use it to resolve a channel name to the channel ID that messages reference. Supports server-side querying with _filter/_search/_orderby/_select/_top/_skip/_count (OData $-params, renamed with a leading underscore for MCP).

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
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:

    Channel

    • id string
    • name string
    • type string
    • description string
    • memberCount integer
    • members arrayArray of user IDs who are members of this channel
      Array of user IDs who are members of this channel

      array of:

      string

    • createdBy 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/chat/channels

Create a Purple Collab channel

Creates a new public or private channel in the Purple Collab workspace. Use only when the user wants a brand-new channel; to post into an existing one, look up its ID with the channel list tool and create a message instead.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections

Request body

application/json — required

Channel

  • id string
  • name string
  • type string
  • description string
  • memberCount integer
  • members arrayArray of user IDs who are members of this channel
    Array of user IDs who are members of this channel

    array of:

    string

  • createdBy string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Channel

  • id string
  • name string
  • type string
  • description string
  • memberCount integer
  • members arrayArray of user IDs who are members of this channel
    Array of user IDs who are members of this channel

    array of:

    string

  • createdBy string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/chat/channels/{id}

Get channel

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Found

application/json

Channel

  • id string
  • name string
  • type string
  • description string
  • memberCount integer
  • members arrayArray of user IDs who are members of this channel
    Array of user IDs who are members of this channel

    array of:

    string

  • createdBy string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/chat/channels/{id}

Delete channel

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/chat/channels/{id}

Update channel

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Request body

Fields to update (partial)

application/json

Channel

  • id string
  • name string
  • type string
  • description string
  • memberCount integer
  • members arrayArray of user IDs who are members of this channel
    Array of user IDs who are members of this channel

    array of:

    string

  • createdBy string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Channel

  • id string
  • name string
  • type string
  • description string
  • memberCount integer
  • members arrayArray of user IDs who are members of this channel
    Array of user IDs who are members of this channel

    array of:

    string

  • createdBy string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/chat/messages

List Purple Collab chat messages

Messages posted in Purple Collab channels, including thread replies. Pass channelId to read one channel's history or parent_message_id to read a single thread. Supports server-side querying with _filter/_search/_orderby/_select/_top/_skip/_count (OData $-params, renamed with a leading underscore for MCP).

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
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.
channelIdquerystringnoFilter messages by channel ID
parent_message_idquerystringnoFilter to thread replies of a specific parent message ID

Responses

200
Paginated list

application/json

  • data array

    array of:

    Message

    • id string
    • channelId stringID of the channel this message belongs to
    • author string
    • text string
    • reactions objectMap of emoji to list of user emails who reacted
    • editedAt string
    • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
    • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
    • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
    • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
      Append-only log of all interactions on this message; managed by POST /messages/:id/interact

      array of:

      • action_id string
      • value
      • timestamp 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/chat/messages

Post a message to a Collab channel

Posts a new top-level message into a Purple Collab channel (channelId, author email and text). To answer inside an existing thread, use the message reply tool instead so the reply is linked to its parent.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections

Request body

application/json — required

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/chat/messages/{id}

Get message

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Found

application/json

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/chat/messages/{id}

Delete a Collab message

Permanently removes a message from Purple Collab. Destructive and irreversible — the text is gone and any thread replies are orphaned; prefer editing the message when the user only wants to change what it says.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/chat/messages/{id}

Edit a Collab message or its reactions

Partially updates an existing Purple Collab message — typically to edit its text or rewrite the emoji reactions map. Interactive-button state is not set here; use the message interact tool for that.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Request body

Fields to update (partial)

application/json

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/chat/scheduled-messages

List scheduled messages

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
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.
channelIdquerystringnoFilter scheduled messages by channel ID

Responses

200
Paginated list

application/json

  • data array

    array of:

    ScheduledMessage

    A message queued to be delivered to a channel at a future time (Slack-style scheduled message).
    • id string
    • channelId stringID of the channel the message will be posted to
    • author string
    • text string
    • scheduledFor stringWhen the message is scheduled to be sent
    • 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/chat/scheduled-messages

Create scheduled message

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections

Request body

application/json — required

ScheduledMessage

A message queued to be delivered to a channel at a future time (Slack-style scheduled message).
  • id string
  • channelId stringID of the channel the message will be posted to
  • author string
  • text string
  • scheduledFor stringWhen the message is scheduled to be sent
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

ScheduledMessage

A message queued to be delivered to a channel at a future time (Slack-style scheduled message).
  • id string
  • channelId stringID of the channel the message will be posted to
  • author string
  • text string
  • scheduledFor stringWhen the message is scheduled to be sent
  • createdAt string
  • updatedAt string

GET /api/purple-suite/chat/scheduled-messages/{id}

Get scheduled message

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Found

application/json

ScheduledMessage

A message queued to be delivered to a channel at a future time (Slack-style scheduled message).
  • id string
  • channelId stringID of the channel the message will be posted to
  • author string
  • text string
  • scheduledFor stringWhen the message is scheduled to be sent
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/chat/scheduled-messages/{id}

Delete scheduled message

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/chat/scheduled-messages/{id}

Update scheduled message

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Request body

Fields to update (partial)

application/json

ScheduledMessage

A message queued to be delivered to a channel at a future time (Slack-style scheduled message).
  • id string
  • channelId stringID of the channel the message will be posted to
  • author string
  • text string
  • scheduledFor stringWhen the message is scheduled to be sent
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

ScheduledMessage

A message queued to be delivered to a channel at a future time (Slack-style scheduled message).
  • id string
  • channelId stringID of the channel the message will be posted to
  • author string
  • text string
  • scheduledFor stringWhen the message is scheduled to be sent
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/chat/drafts

List drafts

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
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.
channelIdquerystringnoFilter drafts by channel ID

Responses

200
Paginated list

application/json

  • data array

    array of:

    Draft

    An unsent message draft (Slack-style draft). Saving a draft does NOT deliver the message.
    • id string
    • channelId stringTarget channel, when the draft is for a channel
    • recipient stringTarget user email, when the draft is a direct message
    • author string
    • text 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/chat/drafts

Create draft

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections

Request body

application/json — required

Draft

An unsent message draft (Slack-style draft). Saving a draft does NOT deliver the message.
  • id string
  • channelId stringTarget channel, when the draft is for a channel
  • recipient stringTarget user email, when the draft is a direct message
  • author string
  • text string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

Draft

An unsent message draft (Slack-style draft). Saving a draft does NOT deliver the message.
  • id string
  • channelId stringTarget channel, when the draft is for a channel
  • recipient stringTarget user email, when the draft is a direct message
  • author string
  • text string
  • createdAt string
  • updatedAt string

GET /api/purple-suite/chat/drafts/{id}

Get draft

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Found

application/json

Draft

An unsent message draft (Slack-style draft). Saving a draft does NOT deliver the message.
  • id string
  • channelId stringTarget channel, when the draft is for a channel
  • recipient stringTarget user email, when the draft is a direct message
  • author string
  • text string
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/chat/drafts/{id}

Delete draft

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/chat/drafts/{id}

Update draft

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Request body

Fields to update (partial)

application/json

Draft

An unsent message draft (Slack-style draft). Saving a draft does NOT deliver the message.
  • id string
  • channelId stringTarget channel, when the draft is for a channel
  • recipient stringTarget user email, when the draft is a direct message
  • author string
  • text string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

Draft

An unsent message draft (Slack-style draft). Saving a draft does NOT deliver the message.
  • id string
  • channelId stringTarget channel, when the draft is for a channel
  • recipient stringTarget user email, when the draft is a direct message
  • author string
  • text string
  • createdAt string
  • updatedAt string
404
Not found

POST /api/purple-suite/chat/messages/{id}/reply

Reply in a Collab message thread

Posts a threaded reply under an existing Purple Collab message: the new message gets parent_message_id set and the parent's thread_count is incremented. Use this rather than creating a plain message whenever the user is responding inside a thread.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyesDocument ID

Request body

application/json — required

All provided fields are spread into the reply message document. id, parent_message_id, thread_count, createdAt, and updatedAt are set automatically.
  • channelId string requiredID of the channel this reply belongs to
  • author string requiredEmail of the user posting the reply
  • text string requiredReply message text
  • reactions objectInitial reactions map (emoji → list of user emails); optional
  • editedAt stringTimestamp of last edit; optional, defaults to null

Responses

201
Reply message created

application/json

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string
404
Parent message not found

POST /api/purple-suite/chat/messages/{id}/interact

Click a button on a Collab message

Records an interactive block-kit style action on a Purple Collab message: sets interactive_state[action_id] to the supplied value and appends to the append-only interactions log. Use it to answer an approve/choose prompt on a bot message; use the message update tool for text or reaction edits.

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyesDocument ID

Request body

application/json — required

  • action_id string requiredIdentifier of the interactive element that was triggered
  • valueNew value to set for the action (any JSON-serialisable value)

Responses

200
Updated message after interaction

application/json

Message

  • id string
  • channelId stringID of the channel this message belongs to
  • author string
  • text string
  • reactions objectMap of emoji to list of user emails who reacted
  • editedAt string
  • parent_message_id stringSet when this message is a thread reply; populated automatically by POST /messages/:id/reply
  • thread_count integerNumber of replies in this message's thread; incremented automatically by POST /messages/:id/reply
  • interactive_state objectCurrent state of interactive button values keyed by action_id; managed by POST /messages/:id/interact
  • interactions arrayAppend-only log of all interactions on this message; managed by POST /messages/:id/interact
    Append-only log of all interactions on this message; managed by POST /messages/:id/interact

    array of:

    • action_id string
    • value
    • timestamp string
  • createdAt string
  • updatedAt string
400
action_id is required
404
Message not found

GET /api/purple-suite/chat/users

List Purple Collab workspace members

People with a chat account in the Purple Collab workspace — display name, email, presence (active/away/offline/do_not_disturb), chat role and timezone. These are chat accounts, not HR employee records (see the hris app) or the canonical people directory (see the identity app). Supports server-side querying with _filter/_search/_orderby/_select/_top/_skip/_count (OData $-params, renamed with a leading underscore for MCP).

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
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

    • id string
    • displayName string
    • email string
    • status string
    • role string
    • timezone string
    • joinedAt 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/chat/users

Create user

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections

Request body

application/json — required

User

  • id string
  • displayName string
  • email string
  • status string
  • role string
  • timezone string
  • joinedAt string
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

User

  • id string
  • displayName string
  • email string
  • status string
  • role string
  • timezone string
  • joinedAt string
  • createdAt string
  • updatedAt string

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

Get user

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Found

application/json

User

  • id string
  • displayName string
  • email string
  • status string
  • role string
  • timezone string
  • joinedAt string
  • createdAt string
  • updatedAt string
404
Not found

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

Delete user

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

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

Update user

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Request body

Fields to update (partial)

application/json

User

  • id string
  • displayName string
  • email string
  • status string
  • role string
  • timezone string
  • joinedAt string
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

User

  • id string
  • displayName string
  • email string
  • status string
  • role string
  • timezone string
  • joinedAt string
  • createdAt string
  • updatedAt string
404
Not found

GET /api/purple-suite/chat/files

List files

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
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:

    File

    • id string
    • name string
    • mimeType string
    • size integerFile size in bytes
    • url string
    • uploadedBy string
    • channelId stringChannel the file was shared in, if applicable
    • messageId stringMessage the file is attached to, if applicable
    • 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/chat/files

Create file

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections

Request body

application/json — required

File

  • id string
  • name string
  • mimeType string
  • size integerFile size in bytes
  • url string
  • uploadedBy string
  • channelId stringChannel the file was shared in, if applicable
  • messageId stringMessage the file is attached to, if applicable
  • createdAt string
  • updatedAt string

Responses

201
Created

application/json

File

  • id string
  • name string
  • mimeType string
  • size integerFile size in bytes
  • url string
  • uploadedBy string
  • channelId stringChannel the file was shared in, if applicable
  • messageId stringMessage the file is attached to, if applicable
  • createdAt string
  • updatedAt string

GET /api/purple-suite/chat/files/{id}

Get file

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Found

application/json

File

  • id string
  • name string
  • mimeType string
  • size integerFile size in bytes
  • url string
  • uploadedBy string
  • channelId stringChannel the file was shared in, if applicable
  • messageId stringMessage the file is attached to, if applicable
  • createdAt string
  • updatedAt string
404
Not found

DELETE /api/purple-suite/chat/files/{id}

Delete file

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Responses

200
Deleted

application/json

  • success boolean
404
Not found

PATCH /api/purple-suite/chat/files/{id}

Update file

Parameters

NameInTypeRequiredDescription
X-Instance-IDheaderstringyesThe Purple Suite instance ID that scopes all subcollections
idpathstringyes

Request body

Fields to update (partial)

application/json

File

  • id string
  • name string
  • mimeType string
  • size integerFile size in bytes
  • url string
  • uploadedBy string
  • channelId stringChannel the file was shared in, if applicable
  • messageId stringMessage the file is attached to, if applicable
  • createdAt string
  • updatedAt string

Responses

200
Updated

application/json

File

  • id string
  • name string
  • mimeType string
  • size integerFile size in bytes
  • url string
  • uploadedBy string
  • channelId stringChannel the file was shared in, if applicable
  • messageId stringMessage the file is attached to, if applicable
  • createdAt string
  • updatedAt string
404
Not found