Skip to main content
A message action is an item in the menu on a message, such as File an issue or Summarize this. When a member picks it, Reintersect sends your app the message, plus its thread or its conversation when you ask for them, and your app answers with content, a live block or a short notice. Answers work like slash command answers: public, as a reply from your app, or private, shown only to the member who ran the action. Using Effect? See Message actions in the Effect guide.

Define a message action

src/requestApproval.tsx
The id ("request-approval") is unique within the app, 1 to 64 characters from A-Z, a-z, 0-9, _, . and -. An app has at most 10 message actions. Because the handler answers with ExpenseApproval.insert(…), the app must also include that block. Leaving it out makes the app incomplete, and app.fetch reports block:expense-approval as missing. See Composing an app.

Options

Context

The menu tells the member what the action sends: “Sends this message”, “Sends this thread”, “Sends this conversation” or “Sends the chat around this”. Ask for the least your action needs. agreed is the conversation’s Agreed statement, or null. Each context message is { id, text, author, createdAt }, with plain text of at most 2,000 characters, and the newest messages are kept within a budget of 32,000 characters.
src/summarize.tsx
context is typed by what you declare: an action declared with "thread" can receive the message or thread levels, never the conversation. Always check context.level. An install that hasn’t approved a wider context yet still runs the version that asked for less, and receives that narrower level.

Wider context needs approval

Asking for more context is an access change. Moving an action from "message" to "thread", or to "conversation", makes installs stay on their current version until a workspace admin approves the new access, and your app receives app.reconsentRequired. reintersect check --app warns about it before you deploy (access-widened). Asking for less never needs approval. See Publishing new versions.

Handler context

Answers

A message action answers exactly like a slash command:
Reintersect posts the answer as your app, headed with who asked, such as “Ada ran Log release note”. In a chat or a direct message it’s an inline reply to the message; on a board it’s a reply in the same thread.
Returning nothing finishes the run without feedback. Prefer a notice so the member knows the action ran. An answer from a message action needs no extra scope: it answers the member’s request.

Timing

Reintersect waits up to 30 seconds for an answer and doesn’t retry. For slower work, defer, exactly as for commands:
Only the member who picked the action sees your app thinking, unless you pass { visibility: "public" } as the second argument, as above, to show it to everyone who can see the message. It’s opt-in because the row shows which action ran. The answer keeps its own visibility either way. You have 15 minutes to answer through POST /v0/invocations/respond, which defer and reintersect.invocations.respond call for you. If the deferred task throws or fails, the SDK answers with a generic private danger notice so the member isn’t left waiting. Catch the failure inside the task to answer your own way.

Who sees the item

Message actions appear on circle chat messages, posts and replies, and direct messages, for members who can see the message, in workspaces where the app is installed. A development install shows its message actions only to its developer. Message actions aren’t available in circles connected to another workspace or a Slack channel. Running a message action in a private circle invites your app to that circle, so it can reply there and receive that circle’s events afterwards.

Over the wire

Without the SDK, a message action arrives as a messageAction.run delivery with { id, message, context, surface, invocationId, interactionToken }, and your endpoint answers 200 with { visibility, content?, block?: { type, props }, notice? }, or 202 with { visibility } (who sees your app thinking: "public" or "private") and answers later. See the delivery protocol.

Testing

Pass the thread or conversation your action should see as the third argument:
See Testing.