Skip to main content

Crate slack_web_api

Crate slack_web_api 

Source
Expand description

§slack-web-api

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

  • One function per Web API method: chat.postMessage is SlackClient::chat_post_message, conversations.history is SlackClient::conversations_history, and so on. The full list is in api.
  • Request and response types for every method, core objects in objects, and typed Block Kit in blocks.
  • One shared connection pool (HTTP/2), a 30 second default timeout, optional retry on HTTP 429, cursor pagination and file upload.

This crate only calls the Web API. It does not receive events (Socket Mode, Events API, interactivity).

§Send a message

use slack_web_api::api::ChatPostMessageRequest;
use slack_web_api::SlackClient;

let client = SlackClient::new("xoxb-your-bot-token");
let res = client
    .chat_post_message(&ChatPostMessageRequest::new("C0123456789").text("Hello from Rust"))
    .await?;
println!("posted at {:?}", res.ts);

Required arguments are the parameters of new; every optional argument is a method of the same name.

§Send a Block Kit message

use slack_web_api::api::ChatPostMessageRequest;
use slack_web_api::blocks::{ActionsBlock, Block, ButtonElement, HeaderBlock, SectionBlock, TextObject};
let blocks = vec![
    Block::from(HeaderBlock::new(TextObject::plain("Deploy finished"))),
    Block::from(SectionBlock::new().text(TextObject::mrkdwn("*api-server* is now on `v2.3.0`"))),
    Block::from(ActionsBlock::new(vec![
        ButtonElement::new(TextObject::plain("Open")).url("https://example.com").into(),
    ])),
];
client
    .chat_post_message(&ChatPostMessageRequest::new("C0123456789").text("Deploy finished").blocks(blocks))
    .await?;

§Read channel history with pagination

use slack_web_api::api::ConversationsHistoryRequest;
let mut pages = client.pages(ConversationsHistoryRequest::new("C0123456789").limit(200));
while let Some(page) = pages.next_page().await {
    for message in page?.messages {
        println!("{:?}: {:?}", message.user, message.text);
    }
}

§Upload a file

files.upload was retired on 2025-11-12. SlackClient::upload_files runs its replacement (files.getUploadURLExternal, the upload, then files.completeUploadExternal).

use slack_web_api::{FileUpload, UploadDestination};
client
    .upload_files(
        vec![FileUpload::new("report.csv", "date,count\n2026-10-01,42\n")],
        UploadDestination::channel("C0123456789").initial_comment("Daily report"),
    )
    .await?;

§Handle errors

use slack_web_api::api::ConversationsInfoRequest;
use slack_web_api::SlackError;
match client.conversations_info(&ConversationsInfoRequest::new("C0123456789")).await {
    Ok(res) => println!("{:?}", res.channel.and_then(|c| c.name)),
    Err(err) if err.api_error() == Some("channel_not_found") => println!("no such channel"),
    Err(SlackError::RateLimited { retry_after }) => println!("still rate limited: {retry_after:?}"),
    Err(err) => eprintln!("{err}"),
}

§Share the client

SlackClient is cheap to clone and every clone shares one connection pool, so create it once. To reuse your application’s reqwest::Client, or to change the retry count or base URL, use the builder:

use slack_web_api::SlackClient;

let http = reqwest::Client::new();
let client = SlackClient::builder().http_client(http).token("xoxb-...").max_retries(5).build();
// Apps installed in many workspaces can switch the token and keep the pool.
let other_workspace = client.with_token("xoxb-other-workspace");

§Methods without types

SlackClient::call_raw calls any method by name with any parameters and returns the JSON as is.

§How requests and responses are handled

  • Requests are sent as application/x-www-form-urlencoded, which every method accepts. Lists of strings are sent comma-separated and objects (blocks, attachments) as JSON.
  • The built-in HTTP client has a 30 second request timeout and a 10 second connect timeout. A client passed with SlackClientBuilder::http_client keeps its own settings.
  • HTTP 429 is returned at once as SlackError::RateLimited with its Retry-After, because only the caller knows how long a request may wait. With SlackClientBuilder::max_retries the client waits for Retry-After and resends. Other failures are never retried, so a message is never posted twice.
  • Response fields are all optional. Scalars are read leniently, because Slack sometimes returns the same field as a string in one place and a number in another; unknown fields are skipped.

Modules§

api
Request and response types for every Slack Web API method, and the SlackClient function that calls each one.
blocks
Slack Block Kit types (blocks, elements, composition objects), plus message attachments, views and message metadata.
de
Lenient deserializers used by the generated response types.
objects
Core Slack objects shared by many responses, inferred from the documented examples of every method.

Structs§

FileUpload
A file to upload with SlackClient::upload_files.
Pages
Cursor pagination over a method. Created by SlackClient::pages.
ResponseMetadata
The response_metadata of a response: the pagination cursor plus warning and error details.
SlackApiError
Details of an "ok": false response.
SlackClient
Slack Web API client.
SlackClientBuilder
Builder for SlackClient.
UploadDestination
Where uploaded files are shared. With nothing set, the files stay private and unshared.

Enums§

SlackError
Error returned by a Web API call.

Traits§

CursorPaginated
A request that supports cursor-based pagination.
NextCursor
A response that carries the cursor for the next page.
SlackApiMethod
A request for one Web API method. Implemented by every generated *Request type.

Functions§

as_json
serialize_with helper that sends a list as a JSON array string instead of a comma-separated list. Used by arguments whose documented example looks like ["C1","C2"].