---
title: Channels (Telegram, Chatwoot…)
description: Connect a Lampson agent to Telegram, to WhatsApp and Instagram via Chatwoot, or to any platform with a channel plugin — even with no public URL.
---
# Channels

A **channel** connects an agent to a messaging platform: the agent answers your customers' messages. Lampson ships two, and every channel is a [plugin](/en/docs/plugins), so you can add the ones you need:

- **Telegram** — a bot, free and with no middleman.
- **Chatwoot** — an inbox that already brings together WhatsApp, Instagram, Facebook, email and web chat: one channel covers all of that.

For all of them, Lampson handles the same things: one conversation per customer, the [mailbox](/en/docs/api#the-mailbox) that merges messages sent in a burst into **one** answer, the "typing…" while the agent works, photos as images for models with vision, [permissions](/en/docs/agents#tools-and-permissions) and the trace.

## Commands

```sh
lampson channel list               # each channel: on/off, agent, mode, webhook URL
lampson channel on telegram        # turn it on (your decision, like a plugin)
lampson channel setup telegram     # get it working
lampson channel off telegram
```

In the web UI: **Channels** in the left panel — turn on, see the mode and the agent, "configure" and the latest events.

**Which agent answers**: `LAMPSON_CHANNEL_<CHANNEL>_AGENT=tienda` in `~/lampson/.env` (for example `LAMPSON_CHANNEL_TELEGRAM_AGENT`). If you don't set it, the default agent. → [Agents](/en/docs/agents)

## With or without a public URL

A platform announces new messages by calling a URL (a **webhook**). If your Lampson has a public URL ([`lampson --domain`](/en/docs/phone) or a tunnel), `lampson channel setup` registers that webhook.

**With no public URL** — Lampson on your home PC — the channels that allow it (Telegram) work all the same: `lampson channel setup` switches them to **no public URL mode** and Lampson itself asks the platform for new messages. No domain or tunnel needed; only that the workspace is on (with the hub running, a workspace with channels stays on).

## Telegram

1. In Telegram, talk to **@BotFather**, `/newbot`, and copy the token.
2. In `~/lampson/.env`:
   ```sh
   LAMPSON_TELEGRAM_TOKEN=123456789:AA…
   LAMPSON_TELEGRAM_WEBHOOK_SECRET=any-long-phrase
   LAMPSON_CHANNEL_TELEGRAM_AGENT=tienda
   ```
3. In the project folder:
   ```sh
   lampson channel on telegram
   lampson channel setup telegram
   ```

With a public URL, `setup` registers the webhook with the secret (Telegram sends it with every notification and Lampson rejects whatever doesn't carry it). With no public URL, it switches to no public URL mode.

What the channel does: it answers new messages from people (it ignores edits, messages from other bots and channel posts); a photo reaches the agent as an image, with its caption; voice notes, files and locations arrive as a note; long answers are split into messages of up to 4000 characters, cutting at a line break.

> If the bot token ended up written somewhere shared, regenerate it in @BotFather (`/revoke`) and change it in `.env`.

## Chatwoot

> **In testing.** The channel follows Chatwoot's official documentation and passes our tests against a simulated Chatwoot, but we haven't tested it against a real instance yet. If you use it and something doesn't work, [let us know](https://github.com/kitecosmic/lampson/issues).

1. In Chatwoot: **Settings → Integrations → Webhooks** → URL `https://your-lampson/w/<workspace>/ch/chatwoot`, event `message_created`. Copy the secret it shows you.
2. An access token (your profile's, or an agent bot's) with permission to reply.
3. In `~/lampson/.env`:
   ```sh
   LAMPSON_CHATWOOT_URL=https://app.chatwoot.com
   LAMPSON_CHATWOOT_TOKEN=…
   LAMPSON_CHATWOOT_WEBHOOK_SECRET=…
   LAMPSON_CHANNEL_CHATWOOT_AGENT=tienda
   ```
4. `lampson channel on chatwoot`.

The channel verifies Chatwoot's signature, answers only incoming public messages (its own replies and private notes are ignored: otherwise the bot would answer itself) and passes attached images as images. Chatwoot needs a public URL to reach Lampson.

## Writing your own channel

A channel is a plugin with `"channel"` in its `plugin.json`. It can have no tools for the model:

```json
{
  "name": "mi-canal",
  "description": "My messaging platform",
  "kind": "exec",
  "command": "node canal.js",
  "config": ["MICANAL_TOKEN"],
  "channel": {"agent": "", "typing": true, "poll": false}
}
```

`"config"` passes the plugin its secrets from `.env`: `LAMPSON_MICANAL_TOKEN` arrives as `PLUGIN_MICANAL_TOKEN`. The plugin receives the action in `PLUGIN_TOOL` and its data (JSON) in `PLUGIN_ARGS`, and prints one JSON to stdout:

| action | receives | prints |
|---|---|---|
| `receive` | the raw webhook: `{method, path, query, headers, body}` (the exact body, to verify signatures) | `{"messages": [{"thread", "text", "sent_at"?, "from"?, "images"?, "meta"?}], "http"?: {"status", "body"}}` |
| `send` | `{thread, text, meta, agent, session, batch}` | whatever you like; output that starts with `ERROR` counts as a failure |
| `typing` (optional) | `{thread, meta}` | — |
| `setup` (optional) | `{"mode": "webhook", "webhook_url"}` or `{"mode": "poll"}` | a message for the person |
| `poll` (optional) | `{cursor}` | `{"messages": [...], "cursor": <the next one>}` |

A channel's webhook is `https://your-lampson/w/<workspace>/ch/<channel>`: Lampson answers the platform right away and the agent works separately. What `send` receives in `meta` is what `receive` returned for the last message in the batch (your platform's ids). Each channel keeps a log in `.lampson/channels/<channel>.log`.

You can also ask the agent: "make a channel for Discord" — it writes it with this contract, validates it and asks you to turn it on.
