> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2-codex-docs-audit-20260719-0149.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Interfaces

> Slack, Telegram, WhatsApp, Discord, plus protocol interfaces for agents and browsers.

An interface is an adapter between AgentOS and a surface where users already are. It receives events from Slack, Telegram, WhatsApp, or other channels, maps them onto AgentOS's run and session model, and routes responses back to the right thread, channel, or user.

The agent doesn't change. The same agent definition answers a Slack DM, a Telegram message, and an AG-UI browser stream. Memory follows the user across surfaces when the interfaces resolve to the same `user_id`.

## Available interfaces

Two categories. Chat surfaces meet humans where they already are. Protocol surfaces are how other systems talk to your agent.

### Chat surfaces

| Interface    | Use case                                                                                             | Setup                                                  |
| ------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| **Slack**    | Team chat, DMs, channel mentions, thread sessions                                                    | [Slack](/agent-os/interfaces/slack/introduction)       |
| **Telegram** | Personal assistants, mobile chat                                                                     | [Telegram](/agent-os/interfaces/telegram/introduction) |
| **WhatsApp** | Customer support and mobile chat                                                                     | [WhatsApp](/agent-os/interfaces/whatsapp/introduction) |
| **Discord**  | Community servers, gaming, custom commands. Runs in its own process via `agno.integrations.discord`. | [Discord](/agent-os/interfaces/discord/introduction)   |

### Protocol surfaces

| Interface | Use case                                                               | Setup                                            |
| --------- | ---------------------------------------------------------------------- | ------------------------------------------------ |
| **A2A**   | Other agents talk to yours over a standardized agent-to-agent protocol | [A2A](/agent-os/interfaces/a2a/introduction)     |
| **AG-UI** | Browser clients consuming SSE streams of run output                    | [AG-UI](/agent-os/interfaces/ag-ui/introduction) |

## Setup

Each interface registers its own routes on the FastAPI app. Slack lands events at `/slack/events`. Telegram at `/telegram/webhook`. The `agent=...` parameter tells the interface which agent to dispatch incoming messages to.

```python theme={null}
from agno.os import AgentOS
from agno.os.interfaces.slack import Slack
from agno.os.interfaces.telegram import Telegram

agent_os = AgentOS(
    agents=[agent],
    db=db,
    interfaces=[
        Slack(agent=agent, token="xoxb-...", signing_secret="..."),
        Telegram(agent=agent, token="bot-token"),
    ],
)
```

If your AgentOS has multiple agents, wire each interface to a different one (Slack to your customer support agent, Telegram to a personal assistant) or wire several interfaces to the same agent.

## Credentials at a glance

Per-interface setup pages have the full OAuth flows, scope lists, and webhook configuration. The summary:

| Interface | Needs                                                                          |
| --------- | ------------------------------------------------------------------------------ |
| Slack     | Bot token (`xoxb-...`), signing secret, OAuth scopes for the events you handle |
| Telegram  | Bot token from @BotFather                                                      |
| WhatsApp  | Business API token, verify token, phone number ID                              |
| Discord   | Bot token (`DISCORD_BOT_TOKEN`)                                                |
| A2A       | None by default; behind AgentOS JWT auth when `authorization=True`             |
| AG-UI     | None by default; behind AgentOS JWT auth when `authorization=True`             |

## Sessions per surface

Every interface maps surface state to AgentOS sessions, so a conversation in Slack carries forward like any other session. The next reply in the same thread reuses the same session and history, no re-mentioning required.

| Interface | Session ID                                               | User ID                                         |
| --------- | -------------------------------------------------------- | ----------------------------------------------- |
| Slack     | `<entity_id>:<channel_id>:<thread_ts>`                   | Slack user ID, or resolved email when enabled   |
| Telegram  | `tg:<entity_id>:<chat_id>` with an optional topic suffix | Telegram user ID                                |
| WhatsApp  | `wa:<entity_id>:<user_id>`                               | Phone number or encrypted user ID               |
| Discord   | Thread ID                                                | Discord user ID                                 |
| A2A       | A2A context ID                                           | JWT subject, or request metadata when anonymous |
| AG-UI     | Client thread ID                                         | JWT subject, or client-supplied when anonymous  |

Slack checks for an existing legacy `<entity_id>:<thread_ts>` session before creating the channel-scoped ID. This preserves history created by earlier versions.

### Resolving Slack user IDs

By default Slack hands you opaque user IDs like `U07ABCXYZ`. Set `resolve_user_identity=True` to use the member's email as `user_id` when Slack provides one:

```python theme={null}
Slack(agent=agent, token=..., signing_secret=..., resolve_user_identity=True)
```

The interface calls `users.info`, uses the returned email as `user_id`, and adds the display name to run metadata. It falls back to the Slack user ID when no email is available. This option is off by default and adds a Slack API call per message.

## One agent, many surfaces

A single agent can answer on every surface at once. Memory follows the user across surfaces, provided you can map their Slack ID to the same `user_id` the AG-UI client passes:

```python theme={null}
agent_os = AgentOS(
    agents=[support_agent],
    db=db,
    interfaces=[
        Slack(agent=support_agent, token=..., signing_secret=...),
        Telegram(agent=support_agent, token=...),
        Whatsapp(agent=support_agent, access_token=..., verify_token=...),
        AGUI(agent=support_agent),
    ],
)
```

The questions the agent answered in Slack last week show up in its memory when the user opens the AG-UI widget on your website. Session history stays scoped to each surface's `session_id`, and interfaces pass surface context along with the run, like the Slack channel name.

## Conditional registration

Don't register interfaces you don't have credentials for:

```python theme={null}
interfaces = []

if SLACK_TOKEN and SLACK_SIGNING_SECRET:
    interfaces.append(Slack(agent=agent, token=SLACK_TOKEN, signing_secret=SLACK_SIGNING_SECRET))

if TELEGRAM_TOKEN:
    interfaces.append(Telegram(agent=agent, token=TELEGRAM_TOKEN))

agent_os = AgentOS(agents=[agent], db=db, interfaces=interfaces)
```

The [Scout](/deploy/templates/scout/overview), [Dash](/deploy/templates/dash/overview), and [Coda](/deploy/templates/coda/overview) apps use this pattern. Slack only loads when both env vars are set, so dev runs without credentials don't crash.

## Custom interfaces and one-off webhooks

The interface API is small. Subclass `BaseInterface`, return your routes from `get_router`, and dispatch incoming messages to the agent. See [BaseInterface](https://github.com/agno-agi/agno/blob/v2.7.4/libs/agno/agno/os/interfaces/base.py) for the full surface.

For one-off webhooks (a CRM event, a GitHub action, a custom dashboard), don't write an interface. Add a route directly to the FastAPI app:

```python theme={null}
app = agent_os.get_app()

@app.post("/webhooks/stripe")
async def handle_stripe(event: dict):
    response = await agent.arun(f"Process Stripe event: {event}", user_id="system")
    return {"ok": True, "response": response.content}
```

A custom interface is for surfaces you'll reuse across agents and OS instances. A direct route is for one-off integrations.
