The Channel interface represents a channel or conversation container that can hold multiple threads. It provides methods for posting messages, iterating threads and messages, and managing channel-level state.
Properties
Unique channel ID. Format: {adapter}:{channelId}
Examples:
Slack: slack:C123ABC
Teams: teams:{base64(conversationId)}
Google Chat: gchat:spaces/ABC123
adapter
readonly adapter : Adapter
The adapter this channel belongs to.
isDM
Whether this is a direct message conversation.
name
readonly name : string | null
Channel name (e.g., “#general”). Null until fetchMetadata() is called.
state
readonly state : Promise < TState | null >
Get the current channel state. Returns null if no state has been set.
interface ChannelState {
welcomeMessageSent ?: boolean ;
memberCount ?: number ;
}
const state = await channel . state ; // Type: ChannelState | null
messages
readonly messages : AsyncIterable < Message >
Iterate channel-level messages newest first (backward from most recent). Auto-paginates lazily.
This returns top-level channel messages, NOT thread replies. For threaded platforms like Slack, this returns messages posted to the channel directly (not in threads).
// Get the 10 most recent channel messages
const recent : Message [] = [];
for await ( const msg of channel . messages ) {
recent . push ( msg );
if ( recent . length >= 10 ) break ;
}
Methods
post()
post (
message : string | PostableMessage | CardJSXElement
): Promise < SentMessage >
Post a message to the channel (top-level, not in a thread).
message
string | PostableMessage | CardJSXElement
required
Message content to post Show PostableMessage types
string - Raw text
{ raw: string } - Explicit raw text
{ markdown: string } - Markdown text
{ ast: Root } - mdast AST
{ card: CardElement } - Rich card
CardElement - Direct card element
AsyncIterable<string> - Streaming text (accumulated before posting)
A SentMessage with methods to edit, delete, or add reactions
Streaming at the channel level accumulates all chunks before posting as a single message, since channel-level streaming is not typically supported.
// Post to channel
await channel . post ( "Hello channel!" );
// Post markdown
await channel . post ({
markdown: "**Important announcement**"
});
// Post a card
await channel . post (
< Card title = "Daily Standup" >
< Text > Meeting starts in 5 minutes !</ Text >
</ Card >
);
postEphemeral()
postEphemeral (
user : string | Author ,
message : AdapterPostableMessage | CardJSXElement ,
options : PostEphemeralOptions
): Promise < EphemeralMessage | null >
Post an ephemeral message visible only to a specific user in this channel.
User ID string or Author object (from message.author or event.user)
message
AdapterPostableMessage | CardJSXElement
required
Message content (string, markdown, card, etc.)
options
PostEphemeralOptions
required
If true, falls back to DM when native ephemeral is not supported. If false, returns null when unsupported.
EphemeralMessage with usedFallback: true if DM was used, or null if unsupported and fallbackToDM is false
// Slash command handler
chat . onSlashCommand ( "/secret" , async ( event ) => {
await event . channel . postEphemeral (
event . user ,
"This is just for you!" ,
{ fallbackToDM: false }
);
});
setState()
setState (
state : Partial < TState > ,
options ?: { replace? : boolean }
): Promise < void >
Set the channel state. Merges with existing state by default.
State object to set (will be merged with existing state unless replace: true)
If true, replace entire state instead of merging
interface ChannelState {
welcomeMessageSent ?: boolean ;
memberCount ?: number ;
}
// Merge with existing state
await channel . setState ({ welcomeMessageSent: true });
// Replace entire state
await channel . setState ({ memberCount: 42 }, { replace: true });
startTyping()
async startTyping ( status ?: string ): Promise < void >
Show typing indicator in the channel.
Optional status text shown where supported
await channel . startTyping ( "Preparing announcement..." );
async fetchMetadata (): Promise < ChannelInfo >
Fetch channel metadata from the platform (name, member count, etc.).
Channel metadata object Show ChannelInfo properties
Channel name (e.g., “general”)
Number of members in the channel
Platform-specific metadata
const info = await channel . fetchMetadata ();
console . log ( `Channel: ${ info . name } , Members: ${ info . memberCount } ` );
threads()
threads (): AsyncIterable < ThreadSummary >
Iterate threads in this channel, most recently active first. Returns lightweight ThreadSummary objects for efficiency.
Returns an empty iterable on threadless platforms (platforms that don’t support threaded conversations).
threadSummary
AsyncIterable<ThreadSummary>
Async iterable of thread summaries Show ThreadSummary properties
Root/first message of the thread
Number of replies (if available)
Timestamp of most recent reply
// List all threads in the channel
for await ( const threadSummary of channel . threads ()) {
console . log ( `Thread: ${ threadSummary . rootMessage . text } ` );
console . log ( `Replies: ${ threadSummary . replyCount } ` );
}
mentionUser()
mentionUser ( userId : string ): string
Get a platform-specific mention string for a user.
Platform-specific user ID
Formatted mention string (e.g., <@U123>)
const mention = channel . mentionUser ( userId );
await channel . post ( `Hey ${ mention } , welcome to the channel!` );
Type Parameters
TState
object
default: "Record<string, unknown>"
Custom state type stored per-channel
Platform-specific raw message type
Usage Examples
Channel Announcements
const channel = chat . channel ( "slack:C123ABC" );
await channel . post ({
markdown: "**Team Update:** We're launching the new feature today!"
});
Welcome New Members
chat . onMemberJoinedChannel ( async ( event ) => {
const channel = chat . channel ( event . channelId );
const state = await channel . state ;
if ( ! state ?. welcomeMessageSent ) {
await channel . post ( "Welcome to the team! 👋" );
await channel . setState ({ welcomeMessageSent: true });
}
});
List Active Threads
const channel = chat . channel ( "slack:C123ABC" );
// Get the 10 most active threads
const activeThreads : ThreadSummary [] = [];
for await ( const thread of channel . threads ()) {
activeThreads . push ( thread );
if ( activeThreads . length >= 10 ) break ;
}
// Post summary
const summary = activeThreads
. map ( t => `- ${ t . rootMessage . text . slice ( 0 , 50 ) } ... ( ${ t . replyCount } replies)` )
. join ( " \n " );
await channel . post ( `**Active Discussions:** \n ${ summary } ` );
Slash Command Response
chat . onSlashCommand ( "/announce" , async ( event ) => {
// Post public announcement
await event . channel . post ({
markdown: `**Announcement from ${ event . user . fullName } :** \n ${ event . text } `
});
// Confirm privately to the user
await event . channel . postEphemeral (
event . user ,
"Your announcement has been posted!" ,
{ fallbackToDM: false }
);
});
Channel State Management
interface ChannelState {
dailyStandupSent ?: boolean ;
lastAnnouncementDate ?: string ;
}
// Daily standup reminder
const channel = chat . channel ( "slack:C123ABC" );
const state = await channel . state ;
const today = new Date (). toISOString (). split ( 'T' )[ 0 ];
if ( state ?. lastAnnouncementDate !== today ) {
await channel . post ( "Time for daily standup! 🎯" );
await channel . setState ({
dailyStandupSent: true ,
lastAnnouncementDate: today
});
}
See Also