channel/getMany
Returns a paginated list of channels in the workspace, with optional filters for type and archive status. Supports returning all results automatically or limiting to a specific count. Requires channels:read scope.
When to Use
- Channel directory UI: Populate a dropdown or searchable list of all workspace channels in an internal admin tool or portal.
- Name-to-ID lookup: Find the channel ID for a given name when you only know the channel name but need the ID for other operations.
- Compliance audit: Enumerate all private channels to verify they comply with naming conventions, purpose documentation, and access policies.
- Member aggregation: Retrieve all channels and sum
numMembersacross them for workspace-wide usage reporting. - Admin channel picker: Build a dynamic channel selector that refreshes the available options without hard-coding channel lists in configuration.
Configuration
Connection
| Field | Type | Required | Description |
|---|---|---|---|
botToken | string | Required | Bot Token starting with xoxb-. Requires channels:read scope. Add groups:read to include private channels. |
Operation Fields
| Field | Type | Required | Description |
|---|---|---|---|
returnAll | boolean | Optional | When true, automatically paginates through all results. Default: false. |
limit | integer | Optional | Maximum number of channels to return when returnAll is false. Default: 200. Max: 1000 per page. |
excludeArchived | boolean | Optional | Exclude archived channels from results. Default: true. |
types | string | Optional | Comma-separated channel types to include. Values: public_channel, private_channel, mpim, im. Default: public_channel. |
Performance Warning: Setting
returnAll: true on large workspaces (1000+ channels) will paginate through all results and may be slow. For large workspaces, prefer a bounded limit and handle nextCursor manually for pagination.
Sample Configuration
{
"operation": "channel/getMany",
"connection": {
"botToken": "{{credentials.slackBotToken}}"
},
"fields": {
"returnAll": false,
"limit": 200,
"excludeArchived": true,
"types": "public_channel,private_channel"
}
}
Validation Errors
| Error Code | Cause | Resolution |
|---|---|---|
missing_scope | Bot token lacks channels:read scope (or groups:read if requesting private channels). | Re-authorize the Slack app with the required scopes. Private channel enumeration requires explicit groups:read. |
invalid_cursor | The cursor value passed for manual pagination is invalid or expired. | Cursors expire — restart pagination from the beginning. Do not cache cursors between workflow runs. |
Output
Success Port
| Field | Type | Description |
|---|---|---|
channelCount | number | Total number of channels returned in this response. |
channels | array | Array of channel objects. Each contains: channelId, channelName, isPrivate, isArchived, numMembers. |
nextCursor | string | Pagination cursor for the next page. Empty string if no more results. |
status | string | success or error. |
errorCode | string | Slack error code when status is error. |
payload | object | Full raw Slack API response. |
Error Port
On failure with Continue on Error enabled, routes to the error port with status: "error" and populated errorCode.
Sample Output
{
"channelCount": 3,
"channels": [
{ "channelId": "C08AB3XYZ12", "channelName": "project-alpha", "isPrivate": false, "isArchived": false, "numMembers": 14 },
{ "channelId": "C08AB3XYZ13", "channelName": "general", "isPrivate": false, "isArchived": false, "numMembers": 98 },
{ "channelId": "G08AB3XYZ99", "channelName": "ops-private", "isPrivate": true, "isArchived": false, "numMembers": 5 }
],
"nextCursor": "dGVhbTpDMDhBQjNYWVoxMw==",
"status": "success",
"errorCode": "",
"payload": { "ok": true, "channels": [ ... ], "response_metadata": { "next_cursor": "..." } }
}
Expression Reference
| Expression | Result |
|---|---|
{{$node["channel-getmany"].json.channelCount}} | Total channels returned — use in reports or loop boundaries. |
{{$node["channel-getmany"].json.channels}} | Full channels array — pass to a Split In Batches node to process each channel. |
{{$node["channel-getmany"].json.channels.find(c => c.channelName === "general").channelId}} | Look up the ID of the channel named "general". |
{{$node["channel-getmany"].json.nextCursor}} | Pagination cursor — pass to next channel/getMany call for manual pagination. |
{{$node["channel-getmany"].json.channels.filter(c => c.numMembers > 100).length}} | Count of channels with more than 100 members. |
Node Policies & GuardRails
| Policy Area | Recommendation |
|---|---|
| Scope requirements | Requires channels:read for public channels. Add groups:read for private channels and im:read / mpim:read for DM types. |
| Rate limiting | Tier 2 (20+ req/min). returnAll on large workspaces will issue many paginated requests — add a cooldown between bulk operations that call this node frequently. |
| No hard-coded IDs | Use this node dynamically to resolve channel IDs rather than hard-coding them. Cache results when the channel list changes infrequently. |
| Archive filtering | Keep excludeArchived: true (default) for operational workflows. Only set to false for compliance audits that specifically need to enumerate archived channels. |
| Type filtering | Explicitly set the types field to only what you need. Including im and mpim returns DMs which can be very large in active workspaces. |
| Cursor expiry | Pagination cursors expire. Never store cursors between workflow runs — always start fresh. Handle invalid_cursor errors by restarting from page 1. |
Examples
Example 1 — Find Channel ID by Name
Lookup the channel ID for a channel whose name is known but whose ID is not stored. Used as a pre-step before other operations.
// $json.targetChannelName = "incident-response"
{ "operation": "channel/getMany", "fields": { "returnAll": true, "excludeArchived": false } }
// Code node:
const channel = $node["channel-getmany"].json.channels
.find(c => c.channelName === $json.targetChannelName);
return { channelId: channel ? channel.channelId : null };
Example 2 — Weekly Channel Audit Report
Scheduled weekly workflow that lists all channels, counts members, and posts a summary to the ops team.
{ "operation": "channel/getMany", "fields": { "returnAll": true, "types": "public_channel,private_channel" } }
// Code node: aggregate stats
const channels = $node["channel-getmany"].json.channels;
const totalMembers = channels.reduce((sum, c) => sum + c.numMembers, 0);
const privateCount = channels.filter(c => c.isPrivate).length;
return { total: channels.length, totalMembers, privateCount };
// message/send → #ops-team with summary
Example 3 — Naming Convention Enforcement
Compliance workflow that flags channels not following the team-{name} naming pattern.
{ "operation": "channel/getMany", "fields": { "returnAll": true, "excludeArchived": true } }
// Filter node: channels NOT matching pattern
const violations = $node["channel-getmany"].json.channels
.filter(c => !c.channelName.match(/^(team|project|client|incident)-/));
// Route violations to a reporting node