Skip to main content

channels()

Returns a live channels resolver over the connections attached to a Mastra platform project, ready to hand to new Mastra({ channels }). Enabled provider instances are constructed once, without credentials, so their webhook and OAuth routes can mount at Mastra construction. The resolver caches the project's connections and binds credentials to these instances as connections change, without redeploying the app.

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { channels } from '@mastra/connect'

export const mastra = new Mastra({
agents: { assistant },
channels: await channels(),
})

Returns: Promise<ChannelsResolver>. See The resolver.

The documented channel setup covers Slack, Telegram, and Discord. Their implementations come from @mastra/slack, @mastra/telegram, and @mastra/discord, loaded on demand. Use those packages directly to configure a channel outside the platform connection flow.

The SDK also registers microsoft-teams, backed by @mastra/teams. SDK registration doesn't guarantee availability in the platform catalog. Constructing the Teams provider requires MASTRA_ENCRYPTION_KEY, a base64-encoded 32-byte value for protecting stored bot secrets. Without it, the resolver warns and skips Teams, including its routes.

Parameters
Direct link to Parameters

options?:

ChannelsOptions
Optional discovery and client configuration.
ChannelsOptions

projectId?:

string
Platform project whose connections to discover. Falls back to MASTRA_PROJECT_ID.

providers?:

string[] | ChannelsProviders
Channels to expose, keyed by registered provider ID (slack-channels, telegram, discord, microsoft-teams). slack is accepted as an alias for slack-channels; using both spellings throws. The array form is an allowlist: only the listed channels are constructed. The record form leaves unlisted registered channels enabled and configures listed channels individually: true (or {}) enables one with defaults, false excludes it, and an options object configures it. An ID that matches no channel provider throws at call time. See Per-provider options below.

client?:

ConnectClientOptions
Platform client overrides (accessToken, orgId, baseUrl, fetch). See ConnectClientOptions in tools().

ttlMs?:

number
How long a resolved snapshot stays fresh, in milliseconds. Default 30000. 0 revalidates on every resolution.

Use the array form to mount only the named channels. The record form leaves other registered channels enabled:

const onlyDiscord = await channels({ providers: ['discord'] })
const allExceptTelegram = await channels({ providers: { telegram: false } })

Per-provider options
Direct link to Per-provider options

Each value in the providers record form is true, false, or a ChannelsProviderOptions. false excludes the channel entirely: no instance is constructed and no routes are mounted.

connectionId?:

string
Pin a specific connection ID, bypassing single-active-connection resolution.

providerOptions?:

Record<string, unknown>
Provider-specific options forwarded to the channel provider constructor, for example Discord applicationId and publicKey. Credential fields (botToken, refreshToken, appId, appPassword) and framework-managed fields (baseUrl, encryptionKey) are reserved: the credential always comes from the platform connection, and reserved fields are rejected at the type level and stripped at runtime with a warning.

The resolver
Direct link to The resolver

The resolved ChannelsResolver satisfies @mastra/core's channels-resolver contract:

  • Callable: returns the current Record<string, ChannelProvider> of providers with an active connection. Mastra invokes it at runtime; the TTL cache makes repeat calls cheap. Only the first resolution waits on the platform. After the TTL expires, resolution returns the stale snapshot immediately and refreshes in the background, skipping the refresh during a short cooldown after a failed fetch, so a new connection can appear one resolution later than the TTL suggests.
  • getRoutes(): the union of API routes for every enabled channel, available synchronously so Mastra can mount them at construction. Routes exist before (and after) their provider has an active connection.
  • refresh(): fetches connections from the platform now and updates the cache. Rejects if the platform fetch fails.
  • disconnect(): clears the cached snapshot so the next resolution fetches fresh. It doesn't tear down providers, sessions, or credentials.

Providers without an active connection don't appear in the resolved map. Their routes stay mounted and begin working once a connection is attached.

Failure handling matches tools(): configuration errors (missing project ID, bad ttlMs, an unknown or malformed provider ID, both spellings of the Slack key) reject at call time, while per-provider problems (provider construction failure, needs_reauth, credential sync failure) are downgraded to warn-and-skip. Several active connections for one provider aren't a skip: the resolver warns and uses the first, and providers.<id>.connectionId pins the choice. The initial resolution rejects if its platform fetch fails. A failed background refresh warns and preserves the cached snapshot, while an explicit refresh() rejects on fetch failure.

Discord permissions
Direct link to Discord permissions

The Discord bot-invite URL requests the bot and applications.commands scopes with these permissions:

  • View Channels
  • Send Messages
  • Send Messages in Threads
  • Embed Links
  • Attach Files
  • Read Message History
  • Add Reactions
  • Use Application Commands

These permissions support chat, threads, files, reactions, and slash commands without granting moderation or channel-management access. Override the permission bitfield through providers.discord.providerOptions.permissions. See the Discord permissions reference for bit values.

Errors
Direct link to Errors

Throws MastraConnectError with a code property:

CodeWhen
missing_project_idNo project ID configured
missing_access_tokenNo platform token configured
invalid_optionsUnknown or malformed provider ID, both slack and slack-channels in one config, a malformed provider entry, or invalid ttlMs
no_active_connectionA channel needed its credential while its provider has no active connection
unauthorizedThe platform rejected the token (401/403)
platform_errorAny other platform request failure