Slack

Sending and reading messages in your client's Slack workspace.

Website
slack.com
Connects by
Signing in with Slack
Category
Chat
Services
1
Tools
175
ServiceKey
Slackslack

Connecting

Your client presses Connect, picks a workspace if they're in more than one, and allows the Operate As app into it.

The connection is the app's own access to the workspace, not your client's personal account. Messages you send appear as coming from the Operate As app.

Check they're connected
curl https://api.operate.as/v1/me/clients \  -H "Authorization: Bearer $OPERATE_AS_API_KEY"
Response
[  {    "id": "6f1c2a7e-...",    "name": "Miller Dental",    "services": [      "slack"    ]  }]

Good to know

Invite the app to each channel

The app can only read and post in channels it's a member of. After connecting, your client types /invite @Operate As in each channel you'll use. Seeing the list of public channels (channels:read) doesn't need an invite.

Check ok, not just the status

Slack answers most errors with status 200 and "ok": false in the body, with the reason in error. Check data.ok as well as status.

The workspace may need an admin

Some workspaces only let admins install apps, or ask members to request approval. If your client can't install the app, a workspace admin needs to install or approve it.

Permissions

What the client readsPermission it asks for
Send messages to channels the app is added tochat:write
See the names of public channelschannels:read
Read messages in channels the app is added tochannels:history
See the people in your workspaceusers:read

Tools

Install Slack's typed package for your language:

pip install operate-as-slack
Run slack.send_message
curl -X POST https://api.operate.as/v1/actions/slack.send_message \  -H "Authorization: Bearer $OPERATE_AS_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "clientId": "6f1c2a7e-...",    "input": {      "channel": "<channel>",      "text": "<text>"    }  }'
InputTypeWhat it is
channelrequiredstringThe channel's ID or #name
textrequiredstringThe message
Response
{  "status": 200,  "data": {    "…": "the service's own response"  },  "encoding": "json"}

Pass-through

Paths continue from https://slack.com/api, and are Slack's method names.

See Pass-through requests for the full request and response format.

Call any endpoint
POST /v1/clients/{clientId}/slack/chat.postMessage
GET /v1/clients/{clientId}/slack/conversations.history?channel=C0123456789&limit=20
POST /v1/clients/{clientId}/slack/chat.postMessage
Authorization: Bearer oa_...
Content-Type: application/json

{ "channel": "C0123456789", "text": "New lead from the website" }

When access ends

How long access lastsUntil it's removed. Slack only makes access renew on a schedule when token rotation is on; without it, the app's access never expires.
RenewalNothing to renew or check daily.
What ends itYour client or a workspace admin removes the Operate As app from the workspace.
When it's removedWe cancel the access with Slack too.

See Keeping access alive and Removing access.

Calls answer
HTTP/1.1 409 ConflictContent-Type: application/json{  "detail": "Miller Dental's Slack access ended. Send them their link to reconnect."}
Your webhook receives
{  "id": "evt_3f9a1c…",  "type": "connection.expired",  "createdAt": "2026-10-16T08:00:00+00:00",  "data": {    "clientId": "6f1c2a7e-...",    "clientName": "Miller Dental",    "provider": "slack",    "services": [      "slack"    ],    "reconnectUrl": "https://…"  }}