Message
A message in a chat, task comment thread, document comment, file comment, annotation thread, or message thread (reply). Creating a message requires EXACTLY ONE parent context — set one of chatId, taskId, documentId, fileId, annotationId or parentMessageId, or set recipientMemberId to send a direct message to a team member (the 1:1 chat is created for you if it does not exist yet). fileId and annotationId are the one legal pair: send both to comment on a region of a file. Sending no context, or more than one, is rejected. Mention people with tagged and attach existing files with files in the same create call.
List Messages
List messages. Returns a paginated envelope (data, total, limit, hasMore, nextCursor). Filterable by 14 fields. Ordered by -createdAt unless you pass sort.
Required scope: messages:read
query Parameters
sortField to sort by. Prefix with - for descending (-createdAt); a createdAt:desc / createdAt:asc suffix works too, but never both markers at once. Default: -createdAt.
cursorOpaque cursor for the next page (the envelope nextCursor).
limitItems per page (1–200, default 50). A larger value is clamped to the cap rather than rejected, so always follow nextCursor instead of assuming one page held everything.
includeTotalWhen true, the response envelope includes the total number of matching rows. Omit it for cheaper pagination.
expandComma-separated relations to inline (see Expanding objects above). Valid values are listed in the enum.
purgeAt[null]Filter where purgeAt is null (pass true).
purgeAt[notNull]Filter where purgeAt is not null (pass true).
purgeAt[gt]Filter where purgeAt is greater than.
purgeAt[gte]Filter where purgeAt is greater than or equal to.
purgeAt[lt]Filter where purgeAt is less than.
purgeAt[lte]Filter where purgeAt is less than or equal to.
authorId[eq]Filter where authorId equals.
authorId[in]Filter where authorId is one of (comma-separated list).
chatId[eq]Filter where chatId equals.
chatId[in]Filter where chatId is one of (comma-separated list).
taskId[eq]Filter where taskId equals.
taskId[in]Filter where taskId is one of (comma-separated list).
documentId[eq]Filter where documentId equals.
documentId[in]Filter where documentId is one of (comma-separated list).
fileId[eq]Filter where fileId equals.
fileId[in]Filter where fileId is one of (comma-separated list).
annotationId[eq]Filter where annotationId equals.
annotationId[in]Filter where annotationId is one of (comma-separated list).
parentMessageId[eq]Filter where parentMessageId equals.
parentMessageId[in]Filter where parentMessageId is one of (comma-separated list).
sharedDocumentId[eq]Filter where sharedDocumentId equals.
sharedDocumentId[in]Filter where sharedDocumentId is one of (comma-separated list).
type[eq]Filter where type equals.
type[in]Filter where type is one of (comma-separated list).
subtype[eq]Filter where subtype equals.
subtype[in]Filter where subtype is one of (comma-separated list).
subtype[null]Filter where subtype is null (pass true).
subtype[notNull]Filter where subtype is not null (pass true).
isEdited[eq]Filter where isEdited equals.
createdAt[gt]Filter where createdAt is greater than.
createdAt[gte]Filter where createdAt is greater than or equal to.
createdAt[lt]Filter where createdAt is less than.
createdAt[lte]Filter where createdAt is less than or equal to.
updatedAt[gt]Filter where updatedAt is greater than.
updatedAt[gte]Filter where updatedAt is greater than or equal to.
updatedAt[lt]Filter where updatedAt is less than.
updatedAt[lte]Filter where updatedAt is less than or equal to.
List Messages › Responses
OK
The page of results.
totalTotal rows matching the query (across pages).
limithasMorenextCursorOpaque cursor for the next page; null on the last page.
Create Message
Create a Message. Server-assigned fields are ignored if sent.
Required scope: messages:write
query Parameters
expandComma-separated relations to inline (see Expanding objects above). Valid values are listed in the enum.
Headers
Idempotency-KeyOptional replay key (see Idempotent requests above).
Create Message › Request Body
textMessage body. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Nullable for non-text messages (gif, audio).
urlExternal URL — used for type=gif messages (GIF source URL). Null otherwise.
typeMessage kind: "text" | "gif" | "document" | "audio". Defaults to "text" when omitted on create; the non-text kinds require their own payload (url / sharedDocumentId / audioDuration), so only pass an explicit type for those. Fixed at creation — it cannot be changed afterwards.
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
audioDurationAudio playback duration in seconds — populated for type=audio messages.
chatIdThe chat this message belongs to (group, direct, or a project discussion). Exactly one parent context per message.
taskIdThe task this message comments on. Exactly one parent context per message.
documentIdThe document this message comments on. Exactly one parent context per message.
fileIdThe file this message comments on. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
annotationIdThe annotation this message is threaded under. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
parentMessageIdThe message this one replies to. Exactly one parent context per message.
recipientMemberIdSend a direct message: provide this instead of chatId, taskId or the other parent contexts. The 1:1 chat is created if it does not exist. Create-only, and must differ from the caller.
taggedTeam members to @-mention on this message, by id. Accepted when the message is created; the mention list of an existing message is not editable, so it is not part of the update body. Read them back with ?expand=tagged.
filesExisting files attached to this message, by id. Writable on create and on update: on update the array you send becomes the COMPLETE set, so a file dropped from it is detached (the file itself is not deleted). Omit the key to leave it untouched. Read them back with ?expand=files.
Decision Table
| Variant | Matching Criteria |
|---|---|
| type = object · requires: chatId | |
| type = object · requires: taskId | |
| type = object · requires: documentId | |
| type = object · requires: fileId | |
| type = object · requires: annotationId | |
| type = object · requires: parentMessageId | |
| type = object · requires: recipientMemberId |
chatIdThe chat this message belongs to (group, direct, or a project discussion). Exactly one parent context per message.
textMessage body. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Nullable for non-text messages (gif, audio).
urlExternal URL — used for type=gif messages (GIF source URL). Null otherwise.
typeMessage kind: "text" | "gif" | "document" | "audio". Defaults to "text" when omitted on create; the non-text kinds require their own payload (url / sharedDocumentId / audioDuration), so only pass an explicit type for those. Fixed at creation — it cannot be changed afterwards.
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
audioDurationAudio playback duration in seconds — populated for type=audio messages.
taskIdThe task this message comments on. Exactly one parent context per message.
documentIdThe document this message comments on. Exactly one parent context per message.
fileIdThe file this message comments on. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
annotationIdThe annotation this message is threaded under. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
parentMessageIdThe message this one replies to. Exactly one parent context per message.
recipientMemberIdSend a direct message: provide this instead of chatId, taskId or the other parent contexts. The 1:1 chat is created if it does not exist. Create-only, and must differ from the caller.
taggedTeam members to @-mention on this message, by id. Accepted when the message is created; the mention list of an existing message is not editable, so it is not part of the update body. Read them back with ?expand=tagged.
filesExisting files attached to this message, by id. Writable on create and on update: on update the array you send becomes the COMPLETE set, so a file dropped from it is detached (the file itself is not deleted). Omit the key to leave it untouched. Read them back with ?expand=files.
Create Message › Responses
Created
idUnique identifier for this resource.
createdAtCreation timestamp.
teamIdTeam this message belongs to. Read-only — resolved from your credentials and from the message's parent context.
typeMessage kind: "text" | "gif" | "document" | "audio". Defaults to "text" when omitted on create; the non-text kinds require their own payload (url / sharedDocumentId / audioDuration), so only pass an explicit type for those. Fixed at creation — it cannot be changed afterwards.
updatedAtLast update timestamp.
createdByActorIdWho created this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records created any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
updatedByActorIdWho last wrote to this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records last written any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
createdByActorTypeThe creator actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type; read-only, not directly writable.
updatedByActorTypeThe last writer actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type via the row's updatedByActorId; read-only, not directly writable.
purgeAtWhen this resource will be permanently deleted — soft-delete time + 30-day retention; null while live.
deletedByIdMember who soft-deleted this resource (server-stamped). A member id — resolve it with GET /members/{id}.
textMessage body, up to 655,350 characters. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Token glyphs are the literal wire ref format. Nullable for non-text messages.
urlExternal URL for type=gif messages.
subtypeNon-null on the system/lifecycle messages the server generates (task assigned, label applied, member joined a chat). Null on messages a person or an agent wrote. Read-only — you cannot create a system message through the API. A few values are not self-explanatory: hello is the welcome message posted in a new chat, tieTask / untieTask record a dependency being added or removed between two tasks, and moveSubtask records a subtask being re-parented.
isEditedTrue when the text has been edited at least once. Server-managed by the edit path.
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
botNameDisplay name shown for a message mirrored in from a connected app (for example a Slack channel). Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
botAvatarAvatar URL shown for a message mirrored in from a connected app. Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
audioDurationAudio playback duration in seconds — populated for type=audio messages.
Every edit made to this message, oldest first. Each entry carries timestamp and the editor: id is the team member who made the edit, or null when an agent or an integration did — in which case actorId identifies it. Server-managed.
authorIdThe team member who wrote this message — a member id, so resolve it with ?expand=author or GET /members/{id}. Null for system and app-mirrored messages — use createdByActorType to tell an agent-written message from a human one.
chatIdThe chat this message belongs to (group, direct, or a project discussion). Exactly one parent context per message.
taskIdThe task this message comments on. Exactly one parent context per message.
documentIdThe document this message comments on. Exactly one parent context per message.
fileIdThe file this message comments on. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
annotationIdThe annotation this message is threaded under. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
parentMessageIdThe message this one replies to. Exactly one parent context per message.
sharedDocumentIdA document shared into a chat message. Distinct from documentId, which marks a comment ON a document. Read-only — share a document from the Nifty app.
Resolved mentions found in text, as a read-only sidecar: each entry is { glyph (the raw <@id> token, still present in text), type (what the mention refers to — only member today), id, name (the display name, or null if the referenced member is deleted or not visible to you) }. Read text for the message; read mentions to show WHO is referenced without losing the ids. Absent when text has no mentions. Server-computed.
repliesCountHow many replies this message has in its thread — 0 when it has none. Named repliesCount because replies is the expandable thread relation on this resource. Server-computed. ⚠️ A reply hidden from your ROLE is excluded from ?expand=replies but is still counted here, so this can exceed the length of the array you receive.
repliersThe distinct TeamMembers who replied in this message's thread, as ids — [] when there is no thread. TeamMember shortids, NOT actor UUIDs: resolve one with GET /members/{id}. Server-computed, and carries the same role-redaction caveat as repliesCount.
createdDM idempotency signal (create-response only): true if recipientMemberId minted a new direct chat, false if an existing 1:1 was reused. Absent for non-DM creates.
Get Message
Retrieve a single Message by id.
Required scope: messages:read
path Parameters
id^[0-9A-Za-z_!]+$ · requiredId of the Message.
query Parameters
expandComma-separated relations to inline (see Expanding objects above). Valid values are listed in the enum.
Get Message › Responses
OK
idUnique identifier for this resource.
createdAtCreation timestamp.
teamIdTeam this message belongs to. Read-only — resolved from your credentials and from the message's parent context.
typeMessage kind: "text" | "gif" | "document" | "audio". Defaults to "text" when omitted on create; the non-text kinds require their own payload (url / sharedDocumentId / audioDuration), so only pass an explicit type for those. Fixed at creation — it cannot be changed afterwards.
updatedAtLast update timestamp.
createdByActorIdWho created this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records created any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
updatedByActorIdWho last wrote to this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records last written any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
createdByActorTypeThe creator actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type; read-only, not directly writable.
updatedByActorTypeThe last writer actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type via the row's updatedByActorId; read-only, not directly writable.
purgeAtWhen this resource will be permanently deleted — soft-delete time + 30-day retention; null while live.
deletedByIdMember who soft-deleted this resource (server-stamped). A member id — resolve it with GET /members/{id}.
textMessage body, up to 655,350 characters. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Token glyphs are the literal wire ref format. Nullable for non-text messages.
urlExternal URL for type=gif messages.
subtypeNon-null on the system/lifecycle messages the server generates (task assigned, label applied, member joined a chat). Null on messages a person or an agent wrote. Read-only — you cannot create a system message through the API. A few values are not self-explanatory: hello is the welcome message posted in a new chat, tieTask / untieTask record a dependency being added or removed between two tasks, and moveSubtask records a subtask being re-parented.
isEditedTrue when the text has been edited at least once. Server-managed by the edit path.
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
botNameDisplay name shown for a message mirrored in from a connected app (for example a Slack channel). Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
botAvatarAvatar URL shown for a message mirrored in from a connected app. Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
audioDurationAudio playback duration in seconds — populated for type=audio messages.
Every edit made to this message, oldest first. Each entry carries timestamp and the editor: id is the team member who made the edit, or null when an agent or an integration did — in which case actorId identifies it. Server-managed.
authorIdThe team member who wrote this message — a member id, so resolve it with ?expand=author or GET /members/{id}. Null for system and app-mirrored messages — use createdByActorType to tell an agent-written message from a human one.
chatIdThe chat this message belongs to (group, direct, or a project discussion). Exactly one parent context per message.
taskIdThe task this message comments on. Exactly one parent context per message.
documentIdThe document this message comments on. Exactly one parent context per message.
fileIdThe file this message comments on. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
annotationIdThe annotation this message is threaded under. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
parentMessageIdThe message this one replies to. Exactly one parent context per message.
sharedDocumentIdA document shared into a chat message. Distinct from documentId, which marks a comment ON a document. Read-only — share a document from the Nifty app.
Resolved mentions found in text, as a read-only sidecar: each entry is { glyph (the raw <@id> token, still present in text), type (what the mention refers to — only member today), id, name (the display name, or null if the referenced member is deleted or not visible to you) }. Read text for the message; read mentions to show WHO is referenced without losing the ids. Absent when text has no mentions. Server-computed.
repliesCountHow many replies this message has in its thread — 0 when it has none. Named repliesCount because replies is the expandable thread relation on this resource. Server-computed. ⚠️ A reply hidden from your ROLE is excluded from ?expand=replies but is still counted here, so this can exceed the length of the array you receive.
repliersThe distinct TeamMembers who replied in this message's thread, as ids — [] when there is no thread. TeamMember shortids, NOT actor UUIDs: resolve one with GET /members/{id}. Server-computed, and carries the same role-redaction caveat as repliesCount.
The related Team Member, present only when you pass ?expand=author.
The related Team Member, present only when you pass ?expand=deletedBy.
The related Actor, present only when you pass ?expand=createdByActor.
The related Actor, present only when you pass ?expand=updatedByActor.
The related Chat, present only when you pass ?expand=chat.
The related Task, present only when you pass ?expand=task.
The related Document, present only when you pass ?expand=document.
The related File, present only when you pass ?expand=file.
The related Annotation, present only when you pass ?expand=annotation.
The related Message, present only when you pass ?expand=parentMessage.
The related Document, present only when you pass ?expand=sharedDocument.
The linked Team Member rows, present only when you pass ?expand=tagged.
The linked Team Member rows, present only when you pass ?expand=seenBy.
The linked Role rows, present only when you pass ?expand=hiddenFor.
The linked File rows, present only when you pass ?expand=files.
The linked Message rows, present only when you pass ?expand=replies.
Delete Message
Move this Message to trash. It disappears from list results immediately and is permanently purged after a 30-day retention window; until then it can be restored.
Required scope: messages:delete
path Parameters
id^[0-9A-Za-z_!]+$ · requiredId of the Message.
Headers
Idempotency-KeyOptional replay key (see Idempotent requests above).
Delete Message › Responses
No Content
Update Message
Partially update a Message. Only the fields you send are changed.
Required scope: messages:write
path Parameters
id^[0-9A-Za-z_!]+$ · requiredId of the Message.
query Parameters
expandComma-separated relations to inline (see Expanding objects above). Valid values are listed in the enum.
Headers
Idempotency-KeyOptional replay key (see Idempotent requests above).
Update Message › Request Body
textMessage body. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Nullable for non-text messages (gif, audio).
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
filesExisting files attached to this message, by id. Writable on create and on update: on update the array you send becomes the COMPLETE set, so a file dropped from it is detached (the file itself is not deleted). Omit the key to leave it untouched. Read them back with ?expand=files.
expectedUpdatedAtOptional concurrency guard: the updatedAt you last read. If the resource has changed since, the update is rejected with 409 instead of overwriting the other writer. Re-read, re-derive your change from the current values, and retry with the fresh updatedAt.
Update Message › Responses
OK
idUnique identifier for this resource.
createdAtCreation timestamp.
teamIdTeam this message belongs to. Read-only — resolved from your credentials and from the message's parent context.
typeMessage kind: "text" | "gif" | "document" | "audio". Defaults to "text" when omitted on create; the non-text kinds require their own payload (url / sharedDocumentId / audioDuration), so only pass an explicit type for those. Fixed at creation — it cannot be changed afterwards.
updatedAtLast update timestamp.
createdByActorIdWho created this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records created any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
updatedByActorIdWho last wrote to this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records last written any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
createdByActorTypeThe creator actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type; read-only, not directly writable.
updatedByActorTypeThe last writer actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type via the row's updatedByActorId; read-only, not directly writable.
purgeAtWhen this resource will be permanently deleted — soft-delete time + 30-day retention; null while live.
deletedByIdMember who soft-deleted this resource (server-stamped). A member id — resolve it with GET /members/{id}.
textMessage body, up to 655,350 characters. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Token glyphs are the literal wire ref format. Nullable for non-text messages.
urlExternal URL for type=gif messages.
subtypeNon-null on the system/lifecycle messages the server generates (task assigned, label applied, member joined a chat). Null on messages a person or an agent wrote. Read-only — you cannot create a system message through the API. A few values are not self-explanatory: hello is the welcome message posted in a new chat, tieTask / untieTask record a dependency being added or removed between two tasks, and moveSubtask records a subtask being re-parented.
isEditedTrue when the text has been edited at least once. Server-managed by the edit path.
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
botNameDisplay name shown for a message mirrored in from a connected app (for example a Slack channel). Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
botAvatarAvatar URL shown for a message mirrored in from a connected app. Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
audioDurationAudio playback duration in seconds — populated for type=audio messages.
Every edit made to this message, oldest first. Each entry carries timestamp and the editor: id is the team member who made the edit, or null when an agent or an integration did — in which case actorId identifies it. Server-managed.
authorIdThe team member who wrote this message — a member id, so resolve it with ?expand=author or GET /members/{id}. Null for system and app-mirrored messages — use createdByActorType to tell an agent-written message from a human one.
chatIdThe chat this message belongs to (group, direct, or a project discussion). Exactly one parent context per message.
taskIdThe task this message comments on. Exactly one parent context per message.
documentIdThe document this message comments on. Exactly one parent context per message.
fileIdThe file this message comments on. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
annotationIdThe annotation this message is threaded under. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
parentMessageIdThe message this one replies to. Exactly one parent context per message.
sharedDocumentIdA document shared into a chat message. Distinct from documentId, which marks a comment ON a document. Read-only — share a document from the Nifty app.
Resolved mentions found in text, as a read-only sidecar: each entry is { glyph (the raw <@id> token, still present in text), type (what the mention refers to — only member today), id, name (the display name, or null if the referenced member is deleted or not visible to you) }. Read text for the message; read mentions to show WHO is referenced without losing the ids. Absent when text has no mentions. Server-computed.
repliesCountHow many replies this message has in its thread — 0 when it has none. Named repliesCount because replies is the expandable thread relation on this resource. Server-computed. ⚠️ A reply hidden from your ROLE is excluded from ?expand=replies but is still counted here, so this can exceed the length of the array you receive.
repliersThe distinct TeamMembers who replied in this message's thread, as ids — [] when there is no thread. TeamMember shortids, NOT actor UUIDs: resolve one with GET /members/{id}. Server-computed, and carries the same role-redaction caveat as repliesCount.
The related Team Member, present only when you pass ?expand=author.
The related Team Member, present only when you pass ?expand=deletedBy.
The related Actor, present only when you pass ?expand=createdByActor.
The related Actor, present only when you pass ?expand=updatedByActor.
The related Chat, present only when you pass ?expand=chat.
The related Task, present only when you pass ?expand=task.
The related Document, present only when you pass ?expand=document.
The related File, present only when you pass ?expand=file.
The related Annotation, present only when you pass ?expand=annotation.
The related Message, present only when you pass ?expand=parentMessage.
The related Document, present only when you pass ?expand=sharedDocument.
The linked Team Member rows, present only when you pass ?expand=tagged.
The linked Team Member rows, present only when you pass ?expand=seenBy.
The linked Role rows, present only when you pass ?expand=hiddenFor.
The linked File rows, present only when you pass ?expand=files.
The linked Message rows, present only when you pass ?expand=replies.
Search Messages
Full-text ranked search across messages. Ranked by relevance; pages are capped at 200 results. Filterable by 14 fields.
Required scope: messages:read
query Parameters
qFull-text search query. Trimmed before matching; URLs, e-mail addresses and HTML markup are rejected.
cursorOpaque cursor for the next page (the envelope nextCursor).
limitItems per page (1–200, default 50). A larger value is clamped to the cap rather than rejected, so always follow nextCursor instead of assuming one page held everything.
includeTotalWhen true, the response envelope includes the total number of matching rows. Omit it for cheaper pagination.
expandComma-separated relations to inline (see Expanding objects above). Valid values are listed in the enum.
purgeAt[null]Filter where purgeAt is null (pass true).
purgeAt[notNull]Filter where purgeAt is not null (pass true).
purgeAt[gt]Filter where purgeAt is greater than.
purgeAt[gte]Filter where purgeAt is greater than or equal to.
purgeAt[lt]Filter where purgeAt is less than.
purgeAt[lte]Filter where purgeAt is less than or equal to.
authorId[eq]Filter where authorId equals.
authorId[in]Filter where authorId is one of (comma-separated list).
chatId[eq]Filter where chatId equals.
chatId[in]Filter where chatId is one of (comma-separated list).
taskId[eq]Filter where taskId equals.
taskId[in]Filter where taskId is one of (comma-separated list).
documentId[eq]Filter where documentId equals.
documentId[in]Filter where documentId is one of (comma-separated list).
fileId[eq]Filter where fileId equals.
fileId[in]Filter where fileId is one of (comma-separated list).
annotationId[eq]Filter where annotationId equals.
annotationId[in]Filter where annotationId is one of (comma-separated list).
parentMessageId[eq]Filter where parentMessageId equals.
parentMessageId[in]Filter where parentMessageId is one of (comma-separated list).
sharedDocumentId[eq]Filter where sharedDocumentId equals.
sharedDocumentId[in]Filter where sharedDocumentId is one of (comma-separated list).
type[eq]Filter where type equals.
type[in]Filter where type is one of (comma-separated list).
subtype[eq]Filter where subtype equals.
subtype[in]Filter where subtype is one of (comma-separated list).
subtype[null]Filter where subtype is null (pass true).
subtype[notNull]Filter where subtype is not null (pass true).
isEdited[eq]Filter where isEdited equals.
createdAt[gt]Filter where createdAt is greater than.
createdAt[gte]Filter where createdAt is greater than or equal to.
createdAt[lt]Filter where createdAt is less than.
createdAt[lte]Filter where createdAt is less than or equal to.
updatedAt[gt]Filter where updatedAt is greater than.
updatedAt[gte]Filter where updatedAt is greater than or equal to.
updatedAt[lt]Filter where updatedAt is less than.
updatedAt[lte]Filter where updatedAt is less than or equal to.
Search Messages › Responses
OK
The page of results.
totalTotal rows matching the query (across pages).
limithasMorenextCursorOpaque cursor for the next page; null on the last page.
Restore Message
Restore a Message that was deleted, returning it to list results. Restoring one that is already active succeeds and changes nothing.
Required scope: messages:delete
path Parameters
id^[0-9A-Za-z_!]+$ · requiredId of the Message.
Headers
Idempotency-KeyOptional replay key (see Idempotent requests above).
Restore Message › Responses
OK
idUnique identifier for this resource.
createdAtCreation timestamp.
teamIdTeam this message belongs to. Read-only — resolved from your credentials and from the message's parent context.
typeMessage kind: "text" | "gif" | "document" | "audio". Defaults to "text" when omitted on create; the non-text kinds require their own payload (url / sharedDocumentId / audioDuration), so only pass an explicit type for those. Fixed at creation — it cannot be changed afterwards.
updatedAtLast update timestamp.
createdByActorIdWho created this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records created any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
updatedByActorIdWho last wrote to this record — a person, an agent, an automation or the system itself. Read-only, stamped by the server on writes made through this API, and null on records last written any other way, so treat it as present-or-null rather than always populated. This is an actor id (a UUID), not a member id: look it up with GET /actors/{id}, whose memberId gives you the person to use against /members.
createdByActorTypeThe creator actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type; read-only, not directly writable.
updatedByActorTypeThe last writer actor's type (human, agent, cron, recurringTask, automation, outboxRetry, systemDefault). Server-derived from actors.type via the row's updatedByActorId; read-only, not directly writable.
purgeAtWhen this resource will be permanently deleted — soft-delete time + 30-day retention; null while live.
deletedByIdMember who soft-deleted this resource (server-stamped). A member id — resolve it with GET /members/{id}.
textMessage body, up to 655,350 characters. Supports Markdown formatting, plus embedded mention tags (<@memberId> person, <?taskId> task, <#projectId> project, <??statusId> status, <^listId> list, <~labelId> label, <$portfolioId> portfolio, <!discussionId> discussion). Token glyphs are the literal wire ref format. Nullable for non-text messages.
urlExternal URL for type=gif messages.
subtypeNon-null on the system/lifecycle messages the server generates (task assigned, label applied, member joined a chat). Null on messages a person or an agent wrote. Read-only — you cannot create a system message through the API. A few values are not self-explanatory: hello is the welcome message posted in a new chat, tieTask / untieTask record a dependency being added or removed between two tasks, and moveSubtask records a subtask being re-parented.
isEditedTrue when the text has been edited at least once. Server-managed by the edit path.
hideLinkPreviewWhen true, link previews are not rendered for URLs in this message.
botNameDisplay name shown for a message mirrored in from a connected app (for example a Slack channel). Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
botAvatarAvatar URL shown for a message mirrored in from a connected app. Null for messages written by a person or an agent. Read-only — set by the mirroring integration, never by an API client.
audioDurationAudio playback duration in seconds — populated for type=audio messages.
Every edit made to this message, oldest first. Each entry carries timestamp and the editor: id is the team member who made the edit, or null when an agent or an integration did — in which case actorId identifies it. Server-managed.
authorIdThe team member who wrote this message — a member id, so resolve it with ?expand=author or GET /members/{id}. Null for system and app-mirrored messages — use createdByActorType to tell an agent-written message from a human one.
chatIdThe chat this message belongs to (group, direct, or a project discussion). Exactly one parent context per message.
taskIdThe task this message comments on. Exactly one parent context per message.
documentIdThe document this message comments on. Exactly one parent context per message.
fileIdThe file this message comments on. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
annotationIdThe annotation this message is threaded under. Exactly one parent context per message — fileId and annotationId may be sent together (a comment on an annotation drawn on a file).
parentMessageIdThe message this one replies to. Exactly one parent context per message.
sharedDocumentIdA document shared into a chat message. Distinct from documentId, which marks a comment ON a document. Read-only — share a document from the Nifty app.
Resolved mentions found in text, as a read-only sidecar: each entry is { glyph (the raw <@id> token, still present in text), type (what the mention refers to — only member today), id, name (the display name, or null if the referenced member is deleted or not visible to you) }. Read text for the message; read mentions to show WHO is referenced without losing the ids. Absent when text has no mentions. Server-computed.
repliesCountHow many replies this message has in its thread — 0 when it has none. Named repliesCount because replies is the expandable thread relation on this resource. Server-computed. ⚠️ A reply hidden from your ROLE is excluded from ?expand=replies but is still counted here, so this can exceed the length of the array you receive.
repliersThe distinct TeamMembers who replied in this message's thread, as ids — [] when there is no thread. TeamMember shortids, NOT actor UUIDs: resolve one with GET /members/{id}. Server-computed, and carries the same role-redaction caveat as repliesCount.