Skip to main content

Team Chat Bots

The Team Chat Bot API lets your own systems post into your workspace's Team Chat -- a deploy pipeline announcing a release in #engineering, a monitoring job dropping an alert into #ops, an order system messaging a specific teammate -- using the credentials you already have.

Authentication

Bots reuse your existing API key or OAuth authentication -- there is no separate bot token or bot credential. Add the teamchat:write scope to the token or OAuth client you want to post with:

Authorization: Bearer s7_api_your_token_here
Content-Type: application/json

Required scope: teamchat:write

Note the missing underscore

teamchat:write is written without an underscore, unlike the human-facing Team Chat scopes (team_chat:read, team_chat:create, team_chat:settings, team_chat:admin). It's a separate scope that grants only the two bot-sending endpoints on this page -- it does not grant read access to Team Chat or any of the human-facing endpoints.

How a bot is identified

A bot message is never attributed to a real teammate:

  • It always renders with a bot avatar in the UI -- never a person's profile picture.
  • You can set any display name per message via bot_name, up to 50 characters. There's no name registration or allowlist -- send "bot_name": "Deploy Bot" on one call and "bot_name": "Release Bot" on the next if you like.
  • The response and any resulting webhook always carry sender_type: "bot" / is_bot: true, so consumers can reliably tell a bot message apart from a teammate's.

Request body

Both endpoints below accept the same body:

FieldTypeRequiredDescription
textstringYesMessage text, 1-40,000 characters.
bot_namestringNoDisplay name for the bot, up to 50 characters. Sending a longer name returns 422 Unprocessable Entity. If omitted, a default bot name is used.
attachment_idsarray of stringNoIDs of attachments already uploaded to your workspace (see Upload an Attachment).
attachmentsarray of objectNoRicher attachment inputs -- see below.

Attachments

Bots can send image, video, audio, and document attachments the same two ways any other SendSeven message can: by referencing an already-uploaded attachment ID, or by handing SendSeven a public URL to fetch. Both forms can be mixed in the same request across multiple attachments, and attachment_ids and attachments are merged together in order.

Each item in attachments is either {"id": "..."} or {"url": "...", "filename": "..."} -- exactly one of id/url per item:

{
"attachments": [
{ "id": "9b3f1a8e-7c2d-4e5b-9f01-12a3b4c5d6e7" },
{ "url": "https://cdn.example.com/report.png", "filename": "report.png" }
]
}

A url item is downloaded into SendSeven's own storage using the exact same ingestion and validation as Create an Attachment from a URL -- the same SSRF protections, the same MIME allowlist, and the same 50 MB size limit. An oversized or unsupported file is rejected with 422 Unprocessable Entity.

See Attachments Overview for the full attachment lifecycle if you haven't used the attachments API before.

Post to a Channel as a Bot

POST /api/v1/team-chat/bot/channels/{channel_ref}/messages

channel_ref accepts either the channel's UUID or its name, with or without a leading # (3f7c1a92-..., #general, and general are all valid).

Required scope: teamchat:write

Rate limit: 60 requests per minute per tenant (shared with the DM endpoint below -- see Rate Limits).

Requirements

  • The target channel must have "Allow Bots to send messages" enabled, or the request is rejected with 403. The auto-created #general and #shoutbox channels have it on by default; channels you create are off by default unless you pass allow_bots: true when creating them (or turn it on in that channel's settings afterwards).
  • Bots can post to any channel with bot posting enabled -- including the auto-created #general and #shoutbox channels -- except the Knowledge Base channel, which always returns 403, regardless of allow_bots.
  • The channel must not be archived -- posting to an archived channel returns 409.

Cross-tenant sending

Add ?source_tenant_id= to post into a channel that belongs to a different tenant than the one your token authenticates as -- for example, an integration acting on behalf of an external Team Chat channel shared with another workspace.

curl

curl -X POST "https://api.sendseven.com/api/v1/team-chat/bot/channels/general/messages" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"text": "Deploy finished successfully :rocket:",
"bot_name": "Deploy Bot"
}'

Node.js

const response = await fetch(
"https://api.sendseven.com/api/v1/team-chat/bot/channels/general/messages",
{
method: "POST",
headers: {
Authorization: "Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00",
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "Deploy finished successfully :rocket:",
bot_name: "Deploy Bot",
}),
}
);
const message = await response.json();
console.log(message.id);

Response (201 Created)

{
"id": "9b21e7c4-13ad-4f0a-8f52-6c9d0e3a7711",
"channel_id": "3f7c1a92-5d84-4b1e-9a3c-70e2f8d41b05",
"dm_conversation_id": null,
"sender_type": "bot",
"is_bot": true,
"bot_name": "Deploy Bot",
"sender_user_id": null,
"content": "Deploy finished successfully :rocket:",
"message_type": "text",
"attachment_ids": null,
"attachments": null,
"mentioned_user_ids": [],
"mentioned_all": false,
"created_at": "2026-08-04T14:30:00Z"
}

Send a Direct Message as a Bot

POST /api/v1/team-chat/bot/users/{user_id}/messages

user_id is the recipient -- a user in your own workspace.

Required scope: teamchat:write

Rate limit: 60 requests per minute per tenant (shared with the channel endpoint above -- see Rate Limits).

Unlike channel posts, a bot DM is always allowed once you're authenticated -- there is no per-channel or per-user permission gate for direct messages, and no equivalent of allow_bots to turn on. The recipient must be an active member of your workspace; targeting a user in a different tenant returns 404 Not Found.

curl

curl -X POST "https://api.sendseven.com/api/v1/team-chat/bot/users/4c8a0f11-92be-4d7a-b0f3-1d5e6a82c904/messages" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"text": "Your export is ready to download.",
"bot_name": "Export Bot"
}'

Node.js

const userId = "4c8a0f11-92be-4d7a-b0f3-1d5e6a82c904";
const response = await fetch(
`https://api.sendseven.com/api/v1/team-chat/bot/users/${userId}/messages`,
{
method: "POST",
headers: {
Authorization: "Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00",
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "Your export is ready to download.",
bot_name: "Export Bot",
}),
}
);
const message = await response.json();
console.log(message.dm_conversation_id);

Response (201 Created)

The same shape as the channel response, with dm_conversation_id populated and channel_id null. sender_user_id is set to the token's own user (the bot identity itself still travels in bot_name):

{
"id": "a7d3f912-88bc-4e01-9a2f-51c6d0e8f223",
"channel_id": null,
"dm_conversation_id": "77c2b0e5-4a19-4c8f-9d63-2b8e1f704ac3",
"sender_type": "bot",
"is_bot": true,
"bot_name": "Export Bot",
"sender_user_id": "9e1f2a3b-4c5d-6e7f-8091-a2b3c4d5e6f7",
"content": "Your export is ready to download.",
"message_type": "text",
"attachment_ids": null,
"attachments": null,
"mentioned_user_ids": [],
"mentioned_all": false,
"created_at": "2026-08-04T14:32:00Z"
}
Direct messages don't trigger the Team Chat webhook

Sending a bot DM does not emit team_chat.message.created -- only channel messages do. If you're building something that needs to react to what happens after a bot DM, route the conversation through a channel instead. See Team Chat Webhook for the full explanation.

Response fields

FieldTypeDescription
idstringMessage ID.
channel_idstring | nullSet for channel sends, null for DMs.
dm_conversation_idstring | nullSet for DM sends, null for channel sends.
sender_typestringAlways "bot".
is_botbooleanAlways true.
bot_namestring | nullThe display name used for this message.
sender_user_idstring | nullnull for channel bot messages; the token's own user ID for DM bot messages.
contentstringThe message text you sent.
message_typestring"text", or "image"/"video"/"audio"/"document" when the message carries a single non-text attachment.
attachment_idsarray | nullLinked attachment IDs.
attachmentsarray | nullEnriched attachment info (id, filename, content_type, file_size, public_url, and width/height/duration where applicable).
mentioned_user_idsarrayUser IDs @mentioned in the text.
mentioned_allbooleanWhether @all was used.
created_atstringISO 8601 creation timestamp.

Rate limits

Both endpoints share a single 60 requests per minute budget per tenant -- sending 40 channel messages and 30 DMs in the same minute from the same tenant will hit the limit at message 61 regardless of which endpoint they came through. Exceeding it returns:

{ "detail": "Rate limit exceeded. Please slow down." }

with HTTP status 429.

Errors

StatusCause
403 Bots cannot post to the knowledge base channelchannel_ref resolved to the Knowledge Base channel, which never accepts bot posts.
403 This channel does not allow bot messagesThe target channel has "Allow Bots to send messages" turned off.
404 Channel not foundchannel_ref didn't resolve to any channel in the tenant.
404 User not found(DM endpoint) The target user_id isn't an active member of the tenant -- also returned for a cross-tenant target.
409 Channel is archivedThe target channel is archived.
422text was empty or over 40,000 characters, bot_name was over 50 characters, or an attachments item failed validation (missing/invalid id/url, unsupported MIME type, or over the 50 MB size limit).
429 Rate limit exceededMore than 60 requests/min from this tenant across both endpoints.

Next