Skip to main content
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

id

readonly id: string
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

readonly isDM: boolean
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
sentMessage
SentMessage
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
string | Author
required
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
result
EphemeralMessage | null
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
Partial<TState>
required
State object to set (will be merged with existing state unless replace: true)
options
object
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.
status
string
Optional status text shown where supported
await channel.startTyping("Preparing announcement...");

fetchMetadata()

async fetchMetadata(): Promise<ChannelInfo>
Fetch channel metadata from the platform (name, member count, etc.).
channelInfo
ChannelInfo
Channel metadata object
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
// 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.
userId
string
required
Platform-specific user ID
mention
string
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
TRawMessage
unknown
default:"unknown"
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