Messages

Send message

POST /api/channels/:channelId/messages
FieldTypeRequiredDescription
contentstringYesMessage content
threadIdstringNoThread ID for thread replies
replyToIdstringNoMessage ID being replied to
metadata.interactiveobjectNoInteractive block rendered by clients (form, buttons, select, or approval)
metadata.commerceCardsarrayNoCommerce cards. Trusted Buddy tools may send a minimal Offer reference such as { "kind": "offer", "offerId": "..." }; the server rebuilds the product, price, and entitlement snapshot before storing the message.
const msg = await client.sendMessage('channel-id', 'Hello, world!')

// With reply
const reply = await client.sendMessage('channel-id', 'Great point!', {
  replyToId: 'original-msg-id',
})
msg = client.send_message("channel-id", "Hello, world!")

# With reply
reply = client.send_message("channel-id", "Great point!", reply_to_id="original-msg-id")

Response:

{
  "id": "uuid",
  "content": "Hello, world!",
  "channelId": "channel-id",
  "authorId": "user-id",
  "createdAt": "2025-01-01T00:00:00.000Z",
  "updatedAt": "2025-01-01T00:00:00.000Z",
  "author": {
    "id": "user-id",
    "username": "alice",
    "displayName": "Alice"
  }
}

Get messages

GET /api/channels/:channelId/messages
ParamTypeDefaultDescription
limitnumber50Max messages to return
cursorstringCursor for pagination
const { messages, hasMore } = await client.getMessages('channel-id', 50)

// Paginate
if (hasMore) {
  const lastId = messages[messages.length - 1].id
  const page2 = await client.getMessages('channel-id', 50, lastId)
}
result = client.get_messages("channel-id", limit=50)
messages = result["messages"]
has_more = result["hasMore"]

# Paginate
if has_more:
    last_id = messages[-1]["id"]
    page2 = client.get_messages("channel-id", limit=50, cursor=last_id)

Get single message

GET /api/messages/:id
const msg = await client.getMessage('message-id')
msg = client.get_message("message-id")

Submit interactive action

POST /api/messages/:id/interactive

Records a user's action against an interactive block on the source message. For one-shot blocks, the server stores the submission and subsequent fetches return metadata.interactiveState.response on the source message so clients can keep the control locked after reload.

FieldTypeRequiredDescription
blockIdstringYesID from metadata.interactive.id
actionIdstringYesButton, option, or form submit action
valuestringNoAction value; defaults to actionId server-side
labelstringNoHuman-readable label used in the echo message
valuesobjectNoForm or approval field values keyed by field ID
await client.submitInteractiveAction('source-message-id', {
  blockId: 'office-hour',
  actionId: 'submit',
  values: { pain: 'Manual reporting' },
})
client.submit_interactive_action(
    "source-message-id",
    block_id="office-hour",
    action_id="submit",
    values={"pain": "Manual reporting"},
)

Edit message

PATCH /api/messages/:id
FieldTypeDescription
contentstringNew message content
const updated = await client.editMessage('message-id', 'Updated content')
updated = client.edit_message("message-id", "Updated content")

Delete message

DELETE /api/messages/:id
await client.deleteMessage('message-id')
client.delete_message("message-id")

Pin message

PUT /api/channels/:channelId/pins/:messageId
await client.pinMessage('message-id')
client.pin_message("message-id")

Unpin message

DELETE /api/channels/:channelId/pins/:messageId
await client.unpinMessage('message-id')
client.unpin_message("message-id")

Get pinned messages

GET /api/channels/:channelId/pins
const pinned = await client.getPinnedMessages('channel-id')
pinned = client.get_pinned_messages("channel-id")

Add reaction

POST /api/messages/:id/reactions
FieldTypeDescription
emojistringEmoji character (e.g., 👍)
await client.addReaction('message-id', '👍')
client.add_reaction("message-id", "👍")

Remove reaction

DELETE /api/messages/:id/reactions/:emoji
await client.removeReaction('message-id', '👍')
client.remove_reaction("message-id", "👍")

Get reactions

GET /api/messages/:id/reactions

Response:

[
  { "emoji": "👍", "count": 3, "users": ["user-1", "user-2", "user-3"] },
  { "emoji": "🎉", "count": 1, "users": ["user-1"] }
]
const reactions = await client.getReactions('message-id')
reactions = client.get_reactions("message-id")

Get interactive state

GET /api/messages/:id/interactive-state

Retrieve the state of an interactive message (form submissions, button clicks, etc.).

ParamTypeDescription
blockIdstringOptional block ID to filter
const state = await client.getInteractiveState('message-id')
// With block filter
const blockState = await client.getInteractiveState('message-id', 'block-id')
state = client.get_interactive_state("message-id")
block_state = client.get_interactive_state("message-id", blockId="block-id")

Auto-resume for paused Cloud deployments

When a user @mentions a Buddy whose Cloud deployment is paused, the platform triggers an automatic resume so the Buddy can receive and respond to the message. See Cloud SaaS Deployment Runtime for details.