slack-web-api 0.2.0

Typed async Slack Web API client for Rust: all 330 methods incl. admin, Block Kit, pagination, file upload, rate-limit retry (reqwest + rustls, no OpenSSL)
Documentation

slack-web-api

English | 日本語

Typed async Rust client for every Slack Web API method — all 330 of them, including admin.* — built on reqwest and rustls.

  • No OpenSSL: reqwest 0.13 + rustls, HTTP/2 and a shared connection pool
  • Request and response types for every method, plus typed Block Kit
  • Automatic retry on 429 using Retry-After (3 times by default)
  • Cursor pagination and file upload (the replacement for the retired files.upload) built in

It covers the Web API only. For Socket Mode or receiving Events API payloads, use another crate.

Installation

[dependencies]
slack-web-api = "0.2"

Usage

use slack_web_api::api::ChatPostMessageRequest;
use slack_web_api::blocks::{Block, SectionBlock, TextObject};
use slack_web_api::SlackClient;

#[tokio::main]
async fn main() -> Result<(), slack_web_api::SlackError> {
    // Create one client per application and clone it: clones share the connection pool.
    let client = SlackClient::new(std::env::var("SLACK_TOKEN").unwrap());

    let res = client
        .chat_post_message(
            &ChatPostMessageRequest::new("C0123456789")
                .text("New application received")
                .blocks(vec![Block::from(SectionBlock::new().text(TextObject::mrkdwn("*New application received*")))]),
        )
        .await?;
    println!("{:?}", res.ts);
    Ok(())
}

Method chat.postMessage becomes chat_post_message, with types ChatPostMessageRequest / ChatPostMessageResponse. Required arguments go to new(...); optional ones are set with methods of the same name.

Sharing your reqwest::Client

let client = slack_web_api::SlackClient::builder()
    .http_client(app_http_client.clone())
    .token("xoxb-...")
    .build();

For apps installed in many workspaces, client.with_token("xoxb-other") switches the token while keeping the pool.

Pagination

use slack_web_api::api::ConversationsListRequest;

let mut pages = client.pages(ConversationsListRequest::new().limit(200));
while let Some(page) = pages.next_page().await {
    for channel in page?.channels {
        println!("{:?}", channel.name);
    }
}

Uploading files

files.upload stopped working on 2025-11-12. upload_files runs files.getUploadURLExternal, the upload and files.completeUploadExternal for you, uploading several files concurrently.

use slack_web_api::{FileUpload, UploadDestination};

client
    .upload_files(
        vec![FileUpload::new("report.csv", bytes)],
        UploadDestination::channel("C0123456789").initial_comment("Monthly report"),
    )
    .await?;

Untyped calls

New methods or arguments that are not in the generated types yet can be called with call_raw:

let value = client.call_raw("chat.postMessage", &serde_json::json!({"channel": "C1", "text": "hi"})).await?;

Errors

SlackError::Api means Slack answered "ok": false; err.api_error() returns the code such as channel_not_found. Details for errors like invalid_blocks are in response_metadata.messages.

Supported APIs

Every method listed at https://docs.slack.dev/reference/methods (330 methods) except files.upload, which Slack retired; use upload_files instead. The per-method list with Rust function names is in the api module docs and in llms-full.txt.

Category Methods Examples
agents.* 2 agents.sessions.rename, agents.sessions.setStatus
api.* 1 api.test
apps.* 23 apps.activities.list, apps.auth.external.delete, apps.auth.external.get, ...
assistant.* 5 assistant.search.context, assistant.search.info, assistant.threads.setStatus, ...
auth.* 3 auth.revoke, auth.teams.list, auth.test
blocks.* 1 blocks.validate
bookmarks.* 4 bookmarks.add, bookmarks.edit, bookmarks.list, ...
bots.* 1 bots.info
calls.* 6 calls.add, calls.end, calls.info, ...
canvases.* 7 canvases.access.delete, canvases.access.set, canvases.create, ...
chat.* 13 chat.appendStream, chat.delete, chat.deleteScheduledMessage, ...
conversations.* 28 conversations.acceptSharedInvite, conversations.approveSharedInvite, conversations.archive, ...
dialog.* 1 dialog.open
dnd.* 5 dnd.endDnd, dnd.endSnooze, dnd.info, ...
emoji.* 1 emoji.list
entity.* 3 entity.acknowledgeCommentAction, entity.presentComments, entity.presentDetails
files.* 14 files.comments.delete, files.completeUploadExternal, files.delete, ...
functions.* 8 functions.completeError, functions.completeSuccess, functions.distributions.permissions.add, ...
migration.* 1 migration.exchange
oauth.* 6 oauth.access, oauth.v2.access, oauth.v2.beginShortTokenRotation, ...
openid.* 2 openid.connect.token, openid.connect.userInfo
pins.* 3 pins.add, pins.list, pins.remove
reactions.* 4 reactions.add, reactions.get, reactions.list, ...
reminders.* 5 reminders.add, reminders.complete, reminders.delete, ...
rtm.* 2 rtm.connect, rtm.start
search.* 3 search.all, search.files, search.messages
slackLists.* 12 slackLists.access.delete, slackLists.access.set, slackLists.create, ...
stars.* 3 stars.add, stars.list, stars.remove
team.* 9 team.accessLogs, team.billableInfo, team.billing.info, ...
tooling.* 1 tooling.tokens.rotate
usergroups.* 7 usergroups.create, usergroups.disable, usergroups.enable, ...
users.* 13 users.conversations, users.deletePhoto, users.discoverableContacts.lookup, ...
views.* 4 views.open, views.publish, views.push, ...
workflows.* 8 workflows.featured.add, workflows.featured.list, workflows.featured.remove, ...
admin.* 121 admin.analytics.getFile, admin.analytics.messages.activity, admin.analytics.messages.metadata, ...

Block Kit: every block, block element, rich text element and composition object, plus legacy attachments, views (modal / home) and message metadata, in slack_web_api::blocks.

How the response types are built

Response types are inferred from the documented response examples of all methods, and the core objects (Message, Conversation, User, File, ...) are shared across methods. Every field is optional (Option or an empty Vec), and scalar fields are read leniently: Slack sometimes returns the same field as a string in one place and a number in another, and that must not fail the whole response. Unknown fields are skipped; use call_raw to see everything. A test calls every method against a mock server returning its documented examples and checks no value is lost.

Regenerating the types

The types are generated in codegen/ from the Markdown version of the official docs (docs.slack.dev).

# Save each .md listed in docs.slack.dev/reference/methods.md into <dir>/m and the object pages into <dir>/obj, then:
python3 codegen/parse_docs.py methods <dir>/m > codegen/spec/methods.json
python3 codegen/parse_docs.py objects <dir>/obj > codegen/spec/objects.json
python3 codegen/generate.py && cargo fmt

License

MIT