Slack

Slack API integration with managed OAuth. Send messages, manage channels, search conversations, and interact with Slack workspaces. Use this skill when users want to post messages, list channels, get user info, or automate Slack workflows. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).

Audits

Pass

Install

openclaw skills install slack-api

Slack

Access the Slack API with managed OAuth authentication. Send messages, manage channels, list users, and automate Slack workflows.

Quick Start

CLI:

maton slack message send --channel C0123456789 --text 'Hello from Maton!'
maton api '/slack/api/chat.postMessage'

Python:

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'channel': 'C0123456789', 'text': 'Hello from Maton!'}).encode()
req = urllib.request.Request('https://api.maton.ai/slack/api/chat.postMessage', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Base URL

https://api.maton.ai/slack/{method}

Maton proxies requests to slack.com and automatically injects your OAuth token.

Installation

NPM:

npm install -g @maton-ai/cli

Homebrew:

brew install maton-ai/cli/maton

Authentication

CLI:

maton login                          # Opens browser for API key
maton login --interactive            # Skip browser, paste API key directly
maton whoami                         # Show current auth state

Manual:

  1. Sign in or create an account at maton.ai
  2. Go to maton.ai/settings
  3. Copy your API key
  4. Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"

Connection Management

Manage your Slack OAuth connections at https://api.maton.ai.

List Connections

CLI:

maton connection list slack --status ACTIVE
maton api -X GET /connections -f app=slack -f status=ACTIVE

Python:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=slack&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Create Connection

CLI:

maton connection create slack
maton api /connections -f app=slack

Python:

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'slack'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Get Connection

CLI:

maton connection view {connection_id}
maton api /connections/{connection_id}

Python:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "connection": {
    "connection_id": "{connection_id}",
    "status": "ACTIVE",
    "creation_time": "2025-12-08T07:20:53.488460Z",
    "last_updated_time": "2026-01-31T20:03:32.593153Z",
    "url": "https://connect.maton.ai/?session_token=...",
    "app": "slack",
    "metadata": {}
  }
}

Open the returned url in a browser to complete OAuth authorization.

Delete Connection

CLI:

maton connection delete {connection_id}
maton api -X DELETE /connections/{connection_id}

Python:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Specifying Connection

If you have multiple Slack connections, specify which one to use:

CLI:

maton slack message send --channel C0123456789 --text 'Hello!' --connection {connection_id}
maton api /slack/api/chat.postMessage --connection {connection_id}

Python:

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'channel': 'C0123456789', 'text': 'Hello!'}).encode()
req = urllib.request.Request('https://api.maton.ai/slack/api/chat.postMessage', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If you have multiple connections, always specify the connection to ensure requests go to the intended account.

Security & Permissions

  • Access is scoped to messages, channels, users, files, and reactions within the connected Slack account.
  • All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.

API Reference

Authentication

Auth Test

GET /slack/api/auth.test

Returns current user and team info.

Example:

maton slack whoami

Messages

Post Message

POST /slack/api/chat.postMessage
Content-Type: application/json

{
  "channel": "C0123456789",
  "text": "Hello, world!"
}

Example:

maton slack message send --channel C0123456789 --text 'Hello, world!'

With blocks:

POST /slack/api/chat.postMessage
Content-Type: application/json

{
  "channel": "C0123456789",
  "blocks": [
    {"type": "section", "text": {"type": "mrkdwn", "text": "*Bold* and _italic_"}}
  ]
}

Example:

maton slack message send --channel C0123456789 --blocks '[{"type":"section","text":{"type":"mrkdwn","text":"*Bold* and _italic_"}}]'

Post /me-style Message

maton slack message me --channel C0123456789 --text 'is deploying'

Post Thread Reply

POST /slack/api/chat.postMessage
Content-Type: application/json

{
  "channel": "C0123456789",
  "thread_ts": "1234567890.123456",
  "text": "This is a reply in a thread"
}

Example:

maton slack message reply --channel C0123456789 --thread-ts 1234567890.123456 --text 'This is a reply in a thread'

Update Message

POST /slack/api/chat.update
Content-Type: application/json

{
  "channel": "C0123456789",
  "ts": "1234567890.123456",
  "text": "Updated message"
}

Example:

maton slack message update --channel C0123456789 --ts 1234567890.123456 --text 'Updated message'

Delete Message

POST /slack/api/chat.delete
Content-Type: application/json

{
  "channel": "C0123456789",
  "ts": "1234567890.123456"
}

Example:

maton slack message delete --channel C0123456789 --ts 1234567890.123456

Schedule Message

POST /slack/api/chat.scheduleMessage
Content-Type: application/json

{
  "channel": "C0123456789",
  "text": "Scheduled message",
  "post_at": 1734567890
}

Example:

maton slack schedule create --channel C0123456789 --text 'Scheduled message' --post-at 1734567890

List Scheduled Messages

GET /slack/api/chat.scheduledMessages.list

Example:

maton slack schedule list

Delete Scheduled Message

POST /slack/api/chat.deleteScheduledMessage
Content-Type: application/json

{
  "channel": "C0123456789",
  "scheduled_message_id": "Q1234567890"
}

Example:

maton slack schedule delete --channel C0123456789 --id Q1234567890

Get Permalink

GET /slack/api/chat.getPermalink?channel=C0123456789&message_ts=1234567890.123456

Example:

maton slack message permalink --channel C0123456789 --message-ts 1234567890.123456

Conversations (Channels)

List Channels

GET /slack/api/conversations.list?types=public_channel,private_channel&limit=100

Types: public_channel, private_channel, im, mpim

Example:

maton slack channel list --types public_channel,private_channel --limit 100

Get Channel Info

GET /slack/api/conversations.info?channel=C0123456789

Example:

maton slack channel view C0123456789

Get Channel History

GET /slack/api/conversations.history?channel=C0123456789&limit=100

Example:

maton slack message list --channel C0123456789 --limit 100

With time range:

GET /slack/api/conversations.history?channel=C0123456789&oldest=1234567890&latest=1234567899

Example:

maton slack message list --channel C0123456789 --oldest 1234567890 --latest 1234567899

Get Thread Replies

GET /slack/api/conversations.replies?channel=C0123456789&ts=1234567890.123456

Example:

maton slack message replies --channel C0123456789 --ts 1234567890.123456

Get Channel Members

GET /slack/api/conversations.members?channel=C0123456789&limit=100

Example:

maton slack channel members C0123456789 --limit 100

Create Channel

POST /slack/api/conversations.create
Content-Type: application/json

{
  "name": "new-channel-name",
  "is_private": false
}

Example:

maton slack channel create --name new-channel-name

Join Channel

POST /slack/api/conversations.join
Content-Type: application/json

{
  "channel": "C0123456789"
}

Example:

maton slack channel join C0123456789

Leave Channel

POST /slack/api/conversations.leave
Content-Type: application/json

{
  "channel": "C0123456789"
}

Example:

maton slack channel leave C0123456789

Archive Channel

POST /slack/api/conversations.archive
Content-Type: application/json

{
  "channel": "C0123456789"
}

Example:

maton slack channel archive C0123456789

Unarchive Channel

POST /slack/api/conversations.unarchive
Content-Type: application/json

{
  "channel": "C0123456789"
}

Example:

maton slack channel unarchive C0123456789

Rename Channel

POST /slack/api/conversations.rename
Content-Type: application/json

{
  "channel": "C0123456789",
  "name": "new-name"
}

Example:

maton slack channel rename C0123456789 --name new-name

Set Channel Topic

POST /slack/api/conversations.setTopic
Content-Type: application/json

{
  "channel": "C0123456789",
  "topic": "Channel topic here"
}

Example:

maton slack channel set-topic C0123456789 --topic 'Channel topic here'

Set Channel Purpose

POST /slack/api/conversations.setPurpose
Content-Type: application/json

{
  "channel": "C0123456789",
  "purpose": "Channel purpose here"
}

Example:

maton slack channel set-purpose C0123456789 --purpose 'Channel purpose here'

Invite to Channel

POST /slack/api/conversations.invite
Content-Type: application/json

{
  "channel": "C0123456789",
  "users": "U0123456789,U9876543210"
}

Example:

maton slack channel invite C0123456789 --users U0123456789,U9876543210

Kick from Channel

POST /slack/api/conversations.kick
Content-Type: application/json

{
  "channel": "C0123456789",
  "user": "U0123456789"
}

Example:

maton slack channel kick C0123456789 --user U0123456789

Mark Channel Read

POST /slack/api/conversations.mark
Content-Type: application/json

{
  "channel": "C0123456789",
  "ts": "1234567890.123456"
}

Example:

maton slack channel mark C0123456789 --ts 1234567890.123456

Direct Messages

Open DM Conversation

POST /slack/api/conversations.open
Content-Type: application/json

{
  "users": "U0123456789"
}

Example:

maton slack conversation open --users U0123456789

For group DM:

POST /slack/api/conversations.open
Content-Type: application/json

{
  "users": "U0123456789,U9876543210"
}

Example:

maton slack conversation open --users U0123456789,U9876543210

List DM Channels

GET /slack/api/conversations.list?types=im

Example:

maton slack channel list --types im

List Group DM Channels

GET /slack/api/conversations.list?types=mpim

Example:

maton slack channel list --types mpim

My Conversations

GET /slack/api/users.conversations?limit=100

Example:

maton slack conversation list --limit 100

Users

List Users

GET /slack/api/users.list?limit=100

Example:

maton slack user list --limit 100

Get User Info

GET /slack/api/users.info?user=U0123456789

Example:

maton slack user view U0123456789

Get User Presence

GET /slack/api/users.getPresence?user=U0123456789

Example:

maton slack user presence U0123456789

Lookup User by Email

GET /slack/api/users.lookupByEmail?email=user@example.com

Example:

maton slack user lookup --email user@example.com

Reactions

Add Reaction

POST /slack/api/reactions.add
Content-Type: application/json

{
  "channel": "C0123456789",
  "name": "thumbsup",
  "timestamp": "1234567890.123456"
}

Example:

maton slack reaction add --channel C0123456789 --ts 1234567890.123456 --emoji thumbsup

Remove Reaction

POST /slack/api/reactions.remove
Content-Type: application/json

{
  "channel": "C0123456789",
  "name": "thumbsup",
  "timestamp": "1234567890.123456"
}

Example:

maton slack reaction remove --channel C0123456789 --ts 1234567890.123456 --emoji thumbsup

Get Reactions on Message

GET /slack/api/reactions.get?channel=C0123456789&timestamp=1234567890.123456

Example:

maton slack reaction get --channel C0123456789 --ts 1234567890.123456

List My Reactions

GET /slack/api/reactions.list?limit=100

Example:

maton slack reaction list --limit 100

Stars

List Stars

GET /slack/api/stars.list?limit=100

Example:

maton slack star list --limit 100

Add Star

POST /slack/api/stars.add
Content-Type: application/json

{
  "channel": "C0123456789",
  "timestamp": "1234567890.123456"
}

Example:

maton slack star add --channel C0123456789 --ts 1234567890.123456

Remove Star

POST /slack/api/stars.remove
Content-Type: application/json

{
  "channel": "C0123456789",
  "timestamp": "1234567890.123456"
}

Example:

maton slack star remove --channel C0123456789 --ts 1234567890.123456

Pins

List Pins

GET /slack/api/pins.list?channel=C0123456789

Example:

maton slack pin list C0123456789

Add Pin

POST /slack/api/pins.add
Content-Type: application/json

{
  "channel": "C0123456789",
  "timestamp": "1234567890.123456"
}

Example:

maton slack pin add --channel C0123456789 --ts 1234567890.123456

Remove Pin

POST /slack/api/pins.remove
Content-Type: application/json

{
  "channel": "C0123456789",
  "timestamp": "1234567890.123456"
}

Example:

maton slack pin remove --channel C0123456789 --ts 1234567890.123456

Bookmarks

List Bookmarks

GET /slack/api/bookmarks.list?channel_id=C0123456789

Example:

maton slack bookmark list --channel C0123456789

Add Bookmark

POST /slack/api/bookmarks.add
Content-Type: application/json

{
  "channel_id": "C0123456789",
  "title": "Team Handbook",
  "type": "link",
  "link": "https://example.com/handbook"
}

Example:

maton slack bookmark add --channel C0123456789 --title 'Team Handbook' --type link --link https://example.com/handbook

Edit Bookmark

POST /slack/api/bookmarks.edit
Content-Type: application/json

{
  "bookmark_id": "Bk0123456789",
  "channel_id": "C0123456789",
  "title": "Updated Title",
  "link": "https://example.com/new"
}

Example:

maton slack bookmark edit --channel C0123456789 --bookmark-id Bk0123456789 --title 'Updated Title' --link https://example.com/new

Remove Bookmark

POST /slack/api/bookmarks.remove
Content-Type: application/json

{
  "bookmark_id": "Bk0123456789",
  "channel_id": "C0123456789"
}

Example:

maton slack bookmark remove --channel C0123456789 --bookmark-id Bk0123456789

Bots

Get Bot Info

GET /slack/api/bots.info?bot=B0123456789

Example:

maton slack bot view B0123456789

Note: this expects the B-prefixed bot ID (from bot_id on a message), not the bot's U-prefixed user ID. Passing a U… ID returns bot_not_found.


Files

List Files

GET /slack/api/files.list?count=100

Filter by channel, user, or file types:

GET /slack/api/files.list?channel=C0123456789&user=U0123456789&types=images,pdfs

Example:

maton slack file list --count 100
maton slack file list --channel C0123456789 --user U0123456789 --types images,pdfs

Upload File

POST /slack/api/files.upload
Content-Type: multipart/form-data

channels=C0123456789
content=file content here
filename=example.txt
title=Example File

Upload File v2 (Get Upload URL)

GET /slack/api/files.getUploadURLExternal?filename=example.txt&length=1024

Complete File Upload

POST /slack/api/files.completeUploadExternal
Content-Type: application/json

{
  "files": [{"id": "F0123456789", "title": "My File"}],
  "channel_id": "C0123456789"
}

Example:

maton slack file upload --file ./example.txt --channel C0123456789 --title 'My File'

Delete File

POST /slack/api/files.delete
Content-Type: application/json

{
  "file": "F0123456789"
}

Example:

maton slack file delete F0123456789

Get File Info

GET /slack/api/files.info?file=F0123456789

Example:

maton slack file view F0123456789

Search

Search Messages

GET /slack/api/search.messages?query=keyword

Example:

maton slack search messages 'keyword'

Search Files

GET /slack/api/search.files?query=keyword

Note: search.files matches against filename and title, not file body content. Newly uploaded files may take a moment to appear in results due to indexing lag.


Code Examples

CLI

# Send a message to a channel
maton slack message send --channel C0123456789 --text 'Hello team'

# List channels
maton slack channel list --types public_channel,private_channel

# Look up a user by email
maton slack user lookup --email alice@example.com

# Add a reaction to a message
maton slack reaction add --channel C012 --ts 1700000000.000100 --emoji thumbsup

JavaScript

const response = await fetch('https://api.maton.ai/slack/api/chat.postMessage', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.MATON_API_KEY}`
  },
  body: JSON.stringify({ channel: 'C0123456', text: 'Hello!' })
});
const result = await response.json();
console.log(result);

Python

import os
import requests

response = requests.post(
    'https://api.maton.ai/slack/api/chat.postMessage',
    headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
    json={'channel': 'C0123456', 'text': 'Hello!'}
)
print(response.json())

Notes

  • Channel IDs: C (public), G (private/group), D (DM)
  • User IDs start with U, Bot IDs start with B, Team IDs start with T
  • Message timestamps (ts) are unique identifiers
  • Use mrkdwn type for Slack-flavored markdown formatting
  • Thread replies use thread_ts to reference the parent message
  • Cursor-based pagination: use cursor from response_metadata.next_cursor

Shell Notes

  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.

Error Handling

StatusMeaning
400Missing Slack connection
401Invalid or missing Maton API key
429Rate limited (10 req/sec per account)
4xx/5xxPassthrough error from Slack API

Missing Scope Errors: If you encounter missing_scope errors, contact Maton Support to request additional scopes for your connection.

Troubleshooting: API Key Issues

CLI:

  1. Check your auth state:
maton whoami
  1. Verify the API key is valid by listing connections:
maton connection list

Manual:

  1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
  1. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Troubleshooting: Invalid App Name

  1. Ensure your URL path starts with slack. For example:
  • Correct: https://api.maton.ai/slack/api/chat.postMessage
  • Incorrect: https://api.maton.ai/api/chat.postMessage

Resources