# Slack in Python

Send Slack messages to channels, people and groups from Python services.

Your services send Slack messages to channels, people and groups through `self.slack.send`.

The connections are send-only - they are for delivering notifications, alerts and updates from your integrations to the people who need them.

## Get a bot token from Slack {#get-a-bot-token-from-slack}

A connection authenticates with a bot token of a Slack app installed in your workspace:

1. Go to [api.slack.com/apps](https://api.slack.com/apps) and click **Create New App**
2. Choose **From scratch**, name the app, e.g. `Zato`, and pick your workspace
3. In the left menu, click **OAuth and Permissions**
4. Under **Scopes** > **Bot Token Scopes**, add `chat:write`
5. Add `chat:write.public` too if the bot should be able to post to public channels without being invited to them first
6. Click **Install to Workspace** and approve the app
7. Copy the **Bot User OAuth Token** - it starts with `xoxb-` and it is what the connection needs

To message a private channel or group, invite the bot to it first, e.g. with `/invite @Zato`.

## Create a connection {#create-a-connection}

To create a connection, go to **Connections** > **Chat** > **Slack** in the Dashboard, click **Create a new connection** and fill in the form:

1. **Name:** My Slack
2. **Token:** the bot token from the previous step
3. Click **OK**

[Video: New Slack connection](https://zatosource-production.b-cdn.net/docs/gfx/chat/slack-create.webm?v=1790440794)

Dashboard menu: Connections > Chat > Slack

The same connections can also be created with [enmasse](https://zato.io/docs/admin/enmasse-reference.html#slack), using the `slack` key:

```yaml
slack:
  - name: My Slack
    token: Zato_Enmasse_Env.SlackToken
```

Use **Ping** on the connection's page to confirm that the token works - it invokes Slack's `auth.test` method.

## Send messages {#send-messages}

To send a message, call `self.slack.send` with the connection's name, the target and the text:

```python
from zato.server.service import Service

class NotifyOnboardingComplete(Service):

    def handle(self):
        self.slack.send('My Slack', channel='#onboarding', text='All accounts for Jane Doe are ready')
```

The target can be:

- A channel, e.g. `#alerts`
- A person, using their member ID, e.g. `U0123456789`
- A group conversation, using its ID

## Rich text {#rich-text}

The text uses Slack's own formatting (mrkdwn), so messages can be formatted inline:

```python
from zato.server.service import Service

class NotifyDeploymentDone(Service):

    def handle(self):
        text = '*Deployment finished* - details are _in the audit log_'
        self.slack.send('My Slack', channel='#deployments', text=text)
```

For fully structured messages, pass Block Kit blocks too - the text then becomes the fallback shown in notifications:

```python
from zato.server.service import Service

class NotifyInvoiceReceived(Service):

    def handle(self):

        data = self.request.payload

        blocks = [
            {
                'type': 'section',
                'text': {
                    'type': 'mrkdwn',
                    'text': '*New invoice received*'
                }
            },
            {
                'type': 'section',
                'fields': [
                    {'type': 'mrkdwn', 'text': '*Supplier:*\n' + data['supplier']},
                    {'type': 'mrkdwn', 'text': '*Amount:*\n' + data['amount']},
                ]
            }
        ]

        self.slack.send('My Slack', channel='#invoices', text='New invoice received', blocks=blocks)
```

## Call other Slack methods {#call-other-slack-methods}

The client behind each connection can invoke any Slack Web API method directly, when you need more than sending messages:

```python
from zato.server.service import Service

class ListSlackChannels(Service):

    def handle(self):

        # The underlying client, with its token and HTTP session
        client = self.slack['My Slack']

        # Invoke any Slack Web API method by its name
        response = client.invoke('conversations.list')

        for channel in response['channels']:
            self.logger.info('Channel: %s', channel['name'])
```

## See also {#see-also}

- [Microsoft Teams](https://zato.io/docs/dev/examples/microsoft-teams.html) - Send messages to Teams channels, people and groups
- [Scheduler](https://zato.io/docs/dev/examples/scheduler.html) - Send notifications on an interval or at a specific time
- [Enmasse](https://zato.io/docs/admin/enmasse.html) - Define Slack connections in YAML for automated deployments

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - The complete reference for writing services
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how both are structured
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
