Official library for using the Slack Platform's Web API
—
Essential WebClient methods for making API calls, handling pagination, and uploading files.
Make calls to any Slack Web API method with automatic error handling and retry logic.
/**
* Make a generic API call to any Slack Web API method
* @param method - The API method name (e.g., 'chat.postMessage')
* @param options - Parameters for the API call
* @returns Promise resolving to the API response
*/
apiCall(method: string, options?: Record<string, unknown>): Promise<WebAPICallResult>;Usage Examples:
import { WebClient } from "@slack/web-api";
const web = new WebClient(token);
// Direct API call
const result = await web.apiCall('chat.postMessage', {
channel: '#general',
text: 'Hello world!'
});
// Call with complex parameters
const result = await web.apiCall('conversations.create', {
name: 'new-channel',
is_private: false
});
// Override token per call
const result = await web.apiCall('auth.test', {
token: 'xoxp-different-token'
});Automatically handle cursor-based pagination for methods that return large datasets.
/**
* Paginate through all results of an API method
* @param method - The API method name that supports pagination
* @param options - Parameters for the API call
* @returns AsyncIterable for iterating through all pages
*/
paginate(
method: string,
options?: Record<string, unknown>
): AsyncIterable<WebAPICallResult>;Usage Examples:
import { WebClient } from "@slack/web-api";
const web = new WebClient(token);
// Iterate through all conversation members
const members = [];
for await (const page of web.paginate('conversations.members', {
channel: 'C1234567890',
limit: 100
})) {
members.push(...page.members);
}
// Get all channels
const channels = [];
for await (const page of web.paginate('conversations.list', {
types: 'public_channel,private_channel'
})) {
channels.push(...page.channels);
}
// Use with custom accumulator function
async function getAllUsers() {
const users = [];
for await (const page of web.paginate('users.list')) {
users.push(...page.members);
// Optional: break early based on condition
if (users.length > 1000) break;
}
return users;
}Use pagination with custom page reduction and stopping criteria.
/**
* Custom page reducer function for accumulating results
* @param accumulator - Current accumulated value
* @param page - Current page result
* @returns Updated accumulator value
*/
type PageReducer<A = any> = (
accumulator: A | undefined,
page: WebAPICallResult
) => A;
/**
* Predicate function to determine when to stop pagination
* @param page - Current page result
* @returns True to continue, false to stop
*/
type PaginatePredicate = (page: WebAPICallResult) => boolean;Usage Examples:
// Custom accumulator pattern
const userCount = await web.paginate('users.list')
.reduce((count = 0, page) => count + page.members.length, 0);
// Stop pagination based on condition
for await (const page of web.paginate('conversations.history', {
channel: 'C1234567890'
})) {
const oldestMessage = page.messages[page.messages.length - 1];
// Stop if we've reached messages older than 30 days
if (Date.now() - (oldestMessage.ts * 1000) > 30 * 24 * 60 * 60 * 1000) {
break;
}
// Process messages...
}Modern file upload implementation using Slack's external upload flow.
/**
* Upload files using the v2 external upload method
* @param options - File upload configuration
* @returns Promise resolving to upload results
*/
filesUploadV2(options: FilesUploadV2Arguments): Promise<WebAPICallResult & {
files: FilesCompleteUploadExternalResponse[];
}>;
interface FilesUploadV2Arguments {
/** Channels or conversations where the file will be shared */
channel_id?: string;
/** Alternative to channel_id - channel names */
channels?: string;
/** Title of the file */
title?: string;
/** File content as Buffer, Stream, or string */
file?: Buffer | NodeJS.ReadableStream | string;
/** Filename if file content is provided */
filename?: string;
/** File type/extension */
filetype?: string;
/** Alternative file content (deprecated) */
content?: string;
/** Initial comment about the file */
initial_comment?: string;
/** Thread timestamp to upload file to a thread */
thread_ts?: string;
/** Alt text for screen readers */
alt_text?: string;
/** Snippet type for text files */
snippet_type?: string;
}Usage Examples:
import { WebClient } from "@slack/web-api";
import { createReadStream } from "fs";
const web = new WebClient(token);
// Upload file from filesystem
const result = await web.filesUploadV2({
channels: '#general',
file: createReadStream('./report.pdf'),
filename: 'monthly-report.pdf',
title: 'Monthly Report',
initial_comment: 'Here is this month\'s report'
});
// Upload text content as file
await web.filesUploadV2({
channels: 'D1234567890', // DM channel
content: 'console.log("Hello, world!");',
filename: 'hello.js',
filetype: 'javascript',
title: 'Hello World Script'
});
// Upload to specific thread
await web.filesUploadV2({
channel_id: 'C1234567890',
file: Buffer.from('Log data here...'),
filename: 'debug.log',
thread_ts: '1234567890.123456',
alt_text: 'Debug log file'
});All API methods return a standardized response format with consistent error handling.
interface WebAPICallResult {
/** Indicates if the API call was successful */
ok: boolean;
/** Error message if the call failed */
error?: string;
/** Additional response metadata */
response_metadata?: {
/** Warning messages from Slack */
warnings?: string[];
/** Cursor for pagination */
next_cursor?: string;
/** OAuth scopes associated with the token */
scopes?: string[];
/** Messages array for bulk operations */
messages?: string[];
};
/** Method-specific response data */
[key: string]: any;
}Usage Examples:
const result = await web.chat.postMessage({
channel: '#general',
text: 'Hello!'
});
if (result.ok) {
console.log('Message posted:', result.ts); // Message timestamp
console.log('Channel:', result.channel); // Channel ID
// Check for warnings
if (result.response_metadata?.warnings) {
console.warn('Warnings:', result.response_metadata.warnings);
}
} else {
console.error('Error:', result.error);
}
// Handle pagination cursors
const listResult = await web.conversations.list({ limit: 100 });
if (listResult.response_metadata?.next_cursor) {
// More results available
const nextPage = await web.conversations.list({
limit: 100,
cursor: listResult.response_metadata.next_cursor
});
}interface FilesCompleteUploadExternalResponse {
id: string;
title: string;
name: string;
mimetype: string;
filetype: string;
pretty_type: string;
user: string;
created: number;
size: number;
permalink: string;
permalink_public?: string;
}Install with Tessl CLI
npx tessl i tessl/npm-slack--web-api