messages_send
Send a message to a thread, channel, or contact. Supports Telegram, Email, LinkedIn, and other connected channels. For LinkedIn posts (comment_thread kind), this posts a comment on the post. Can automatically resolve recipients and channels when not specified. Can send files/images/documents as attachments — pass attachments=[file_id, ...] with integer file IDs obtained from collections.list_files, search.files, or files.search. text is optional when attachments are provided.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | Message text to send. Optional if attachments provided. | |
| format | No | Message format | text |
| silent | No | Send without notification | |
| buttons | No | Inline reply buttons shown under the message, one per row (max 10). Each item is {"label": "<visible button text>"} plus exactly one target: "value" (a string sent back as a normal incoming message when tapped, defaults to the label, max 64 bytes), "url" (opens a link) or "web_app" (opens an https page as a Telegram Mini App). A "url" button may add "track": true: the tap is then counted for this conversation (analytics_link_clicks_v in analytics.query) and the person is sent on to the url; "tag": <ai_tag id> beside it also puts that tag on the CONVERSATION at the tap (a group's tag is any member's tap; a first message to a new contact has no conversation yet and goes out untagged); "pass": "<name>" opens the url with <name>=<the chat's id on its channel> added, so the site can name the person back in its own events. Only on channels that support buttons (Telegram bot accounts); can accompany at most one attachment, and when the text is too long for a media caption the buttons arrive with the text as a second message. | |
| mentions | No | People of a group chat to @-tag so the platform really notifies them (WhatsApp, Telegram groups). Each item names one member of THIS chat by one of: "name" (as shown in the chat), "phone" (international number) or "entity_id". If the text already holds "@<name>" that spot is the tag, otherwise "@<name> " is put in front of the text. A person who is not in the chat, or who matches several, refuses the whole send and lists the members. Without this parameter a "@Name" in the text of a group message tags the member it names in the same way, and an @-word that names nobody refuses the send (on Telegram it stays text: a typed @username is a link there). Not combinable with attachments or buttons, and not available while the agent sends drafts. Text may be empty: the tags alone are sent. | |
| template | No | WhatsApp Business API only. An approved template to send instead of free text, in Meta's shape: {name, language, components:[{type:'body', parameters:[{type:'text', text:...}]}, ...]}; `language` is the code as a string ('en_US'). Required when the 24-hour window of the conversation is closed (the send answers WINDOW_EXPIRED otherwise). Read the approved templates and their variables with channels.list(account_id=...). | |
| thread_id | No | Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To write to a phone number nobody has a thread with yet: 'whatsapp_business:+<number in international format>' opens a WhatsApp conversation from a WhatsApp Business API number (from_account_id picks which one; the first message must be a `template`), and 'sms:+<number>' texts it from a workspace phone number that has SMS turned on (from_account_id picks which one), landing in that number's conversation with the recipient, next to their calls. 'x:@<handle>' sends a first X direct message to that person from a connected X account; X refuses it when their inbox is closed to the sender. 'discord:<user id>' (the person's numeric Discord id) sends a first Discord DM from a connected Discord account, into the DM that exists with them or one opened for it; new DMs are limited per account and day, and refused in words with a retry_after when over. 'skool:user:<user id>' (optionally '@<community id>' after the id, when the two share several communities) sends a first message on Skool from a connected Skool account; a Skool post thread ('skool:<account>:post:<post id>') takes a comment instead. NEVER use a chat-type word (dm, group, channel, livechat, comment_thread) — those are category labels from the SITUATION block, not ids. | |
| attachments | No | Array of integer file IDs to send as attachments (images, documents, any files). Get file IDs from collections.list_files (field `file_id`), search.files (field `file_id`), or files.search — only ids returned by those calls in this workspace. The file must already exist in the workspace (status=ready) — no separate upload step needed. When attachments are provided, `text` becomes optional (a caption can be included alongside). | |
| in_workspace | No | Run this one call in this workspace id instead of the session's. Nothing is stored; other sessions are not affected. | |
| private_reply | No | Comment threads only (Instagram, Facebook): answer the comment in the commenter's private messages instead of publicly under the post (Meta's Private Replies). One message per comment, within 7 days of the comment. The message is filed in the person's private conversation. To also answer publicly, make a second call without this flag. OMIT for a normal send. | |
| recipient_name | No | Name of person to send to (e.g., 'Jane', 'John'). Tool will auto-resolve channel. Optional if thread_id provided. | |
| from_account_id | No | Which of the workspace's accounts on this channel SENDS the message, i.e. the number or handle the recipient sees. A numeric thread_id is one conversation on one account: naming a different account for it is refused. With a channel_ref or recipient_username, the conversation ON THIS ACCOUNT is used, or opened where the channel can start one; if it has none, the send is refused rather than made from another account. OMIT and the platform picks the most recently active account, which is a coin flip in a workspace with several numbers: pass it whenever one of them must not be used to open conversations (a personal line, or one under a spam restriction). An account that is not active in this workspace is refused, never silently swapped. | |
| recipient_username | No | Telegram @username to message (e.g. '@some_username'). Use this for a Telegram user NOT yet in contacts — it resolves the handle, adds the contact, and creates the thread. Telegram only; for existing contacts prefer thread_id or recipient_name. | |
| reply_to_message_id | No | ID of message to reply to (optional) |