---
title: Channel
description: Channel container that holds threads, with methods for listing, posting, and iteration.
type: reference
---

A `Channel` represents a channel or conversation container that holds threads. Both `Thread` and `Channel` extend the shared `Postable` interface, so they share common methods like `post()`, `state`, and `messages`.

Get a channel via `thread.channel` or `chat.channel()`:

```typescript
// Navigate from a thread
const channel = thread.channel;

// Get directly by ID
const channel = chat.channel("slack:C123ABC");
```

## Properties

<TypeTable
  type={{
    id: {
      description: 'Channel ID (e.g., "slack:C123ABC", "gchat:spaces/ABC123").',
      type: 'string',
    },
    name: {
      description: 'Channel name (e.g., "#general"). Null until fetchMetadata() is called.',
      type: 'string | null',
    },
    adapter: {
      description: 'The platform adapter this channel belongs to.',
      type: 'Adapter',
    },
    isDM: {
      description: 'Whether this is a direct message conversation.',
      type: 'boolean',
    },
  }}
/>

## Channel ID format

Channel IDs are derived from thread IDs by dropping the thread-specific part. By default, this is the first two colon-separated segments:

| Platform | Thread ID | Channel ID |
|----------|-----------|------------|
| Slack | `slack:C123ABC:1234567890.123456` | `slack:C123ABC` |
| Teams | `teams:{base64}:{base64}` | `teams:{base64}` |
| Google Chat | `gchat:spaces/ABC123:{base64}` | `gchat:spaces/ABC123` |
| Discord | `discord:{guildId}:{channelId}/{messageId}` | `discord:{guildId}` |

## messages

Iterate channel-level messages (top-level, not thread replies) newest first. Auto-paginates lazily.

```typescript
for await (const msg of channel.messages) {
  console.log(msg.text);
}
```

## threads

Iterate threads in the channel, most recently active first. Returns lightweight `ThreadSummary` objects.

```typescript
for await (const thread of channel.threads()) {
  console.log(thread.rootMessage.text, thread.replyCount);
}
```

### ThreadSummary

<TypeTable
  type={{
    id: {
      description: 'Full thread ID.',
      type: 'string',
    },
    rootMessage: {
      description: 'The first message of the thread.',
      type: 'Message',
    },
    replyCount: {
      description: 'Number of replies (if available).',
      type: 'number | undefined',
    },
    lastReplyAt: {
      description: 'Timestamp of most recent reply.',
      type: 'Date | undefined',
    },
  }}
/>

## post

Post a message to the channel top-level (not in a thread).

```typescript
await channel.post("Hello channel!");
await channel.post({ markdown: "**Announcement**: New release!" });
```

Accepts the same message formats as `thread.post()` — see [PostableMessage](/docs/api/postable-message).

## schedule

Schedule a message for future delivery to the channel top-level. Currently only supported by the Slack adapter — other adapters throw `NotImplementedError`.

```typescript
const scheduled = await channel.schedule("Weekly reminder: update your status!", {
  postAt: new Date("2026-03-10T09:00:00Z"),
});

// Cancel before it's sent
await scheduled.cancel();
```

Accepts the same message formats as `channel.post()` (except streaming). See [ScheduledMessage](/docs/api/thread#scheduledmessage) for the return type.

## fetchMetadata

Fetch channel metadata from the platform.

```typescript
const info = await channel.fetchMetadata();
console.log(info.name, info.memberCount);
```

### ChannelInfo

<TypeTable
  type={{
    id: {
      description: 'Channel ID.',
      type: 'string',
    },
    name: {
      description: 'Channel name.',
      type: 'string | undefined',
    },
    isDM: {
      description: 'Whether this is a direct message.',
      type: 'boolean | undefined',
    },
    memberCount: {
      description: 'Number of members in the channel.',
      type: 'number | undefined',
    },
    metadata: {
      description: 'Platform-specific metadata.',
      type: 'Record<string, unknown>',
    },
  }}
/>

## state

Store typed, per-channel state. Works the same as thread state with a 30-day TTL.

```typescript
const state = await channel.state;
await channel.setState({ lastAnnouncement: new Date().toISOString() });
```

## postEphemeral

Post a message visible only to a specific user.

```typescript
await channel.postEphemeral(userId, "Only you can see this", {
  fallbackToDM: true,
});
```

## startTyping

Show a typing indicator. No-op on platforms that don't support it. On Slack, you can pass an optional `status` string to show a custom loading message (requires `assistant:write` scope).

```typescript
await channel.startTyping();

// With custom status (Slack only)
await channel.startTyping("Searching documents...");
```

## mentionUser

Get a platform-specific @-mention string.

```typescript
await channel.post(`Hey ${channel.mentionUser(userId)}, check this out!`);
```
