Guides
Channels
Let people talk to agents from Slack, Telegram and Discord, and have agents answer GitHub and any webhook
View as Markdown · Docs index for coding agents
A channel lets people talk to agents from a messaging service (Telegram, Slack
or Discord), or has agents answer activity on GitHub. A webhook channel
lets any service that sends webhooks (Sentry, Linear, Stripe, your own) start
agents. For Discord you can also skip making a bot: add the Camel Discord
bot to your server from the console. Manage
channels with /v1/channels or the console's Channels page:
curl https://run.camelai.com/v1/channels \
-H "Authorization: Bearer $CAMELAI_API_KEY" -H "Content-Type: application/json" \
-d '{"type": "telegram", "credentials": {"botToken": "<from @BotFather>"},
"definition": "def_...", "access": {"allow": ["@ada", "123456789"]}}'Each conversation's agent is made from the channel's definition. A channel
created without one gets an empty definition of its own.
| Service | Credentials | Messages arrive by | One conversation (one agent) is |
|---|---|---|---|
telegram | botToken | Webhook, registered for you | A chat |
slack | botToken (xoxb-...), signingSecret | Webhook, pasted into the app | A thread started by an @mention, or a DM |
discord | botToken | The Gateway, which camelRun keeps connected | A DM, or a channel or thread where the bot is @mentioned |
| Camel Discord bot | None: one Discord authorization from the console | Camel's shared Gateway | An allowed server channel or thread where Camel is @mentioned |
github | appId, privateKey, webhookSecret | Webhook, pasted into the GitHub App | A pull request or issue |
webhook | secret, optional replyUrl | Webhook, pasted into the sending service | Whatever the key template names |
Creating a channel checks its credentials with the service. Credentials are stored encrypted, and the API returns only masked values.
Add the Camel Discord bot
Camel is camelRun's own Discord bot. Adding it to a server takes one step and no Discord application or bot token:
Add Camel
On the console's Channels page, select Add Camel to Discord, or open run.camelai.com/console/?start=discord, which signs you in first if needed. In Discord, choose a server you own or have Manage Server in, and authorize Camel. That adds the bot and connects the server to your camelRun account. One server belongs to one camelRun account at a time.
Configure the server
The server's settings open in the console. Choose a definition, or create one with the prompt, model and tools you want. Select the allowed channels, then who may talk to Camel: a list of Discord user IDs, or every member. Saving turns Camel on in that server; until then it doesn't answer there.
Mention Camel
In an allowed channel, send a message that @mentions Camel. Pick the entry with the App badge in Discord's autocomplete: a role with the same name doesn't count.
Each allowed channel or thread has its own persistent agent, with history shared by the people in that conversation. Every new turn needs a direct mention of Camel, and direct messages are ignored. Camel asks for View Channel, Send Messages, Send Messages in Threads, Attach Files and Read Message History, never Administrator, and no privileged intents. It has no slash commands.
Members who can talk to Camel use the definition's tools with your camelRun account's credentials, and their usage is billed to your account. Choose the tools and the allowed members accordingly.
- Limits. Each member has a rate limit (5 turns a minute by default, up to 100), and the server has a daily turn limit (100 by default, up to 10,000). Turns you start through the API count against it. There is no dollar budget per server yet; your account's credit and spend limits apply. An account connects at most 10 servers, or 1 while on free credit, which also caps each server at 500 turns a day.
- No schedules. A definition with the
schedulebuiltin can't serve a server, since any member could have the agent wake itself outside those limits. - Changing it. Configure edits the definition, tools included, and can apply it to existing conversations; the console reports which were updated, queued or failed.
- Pausing and removing. Pause stops new replies and pending sends. Disconnect keeps the conversation history and stops replies, but leaves Camel in the server. Removing Camel from the server disconnects it, and adding it back needs reactivation in the console. A saved configuration isn't proof a reply was delivered: test with a new mention in an allowed channel.
- Moving a server. A server's administrators decide who runs Camel there. To move it to another camelRun account, remove Camel from the server, then add it again from that account. The previous account keeps its past conversations but sees no new ones.
The Camel bot is set up from the console only, not with POST /v1/channels.
For your own bot name and avatar, or to answer DMs, use the discord channel
with your own bot token below.
Set up each service
The runtime also supports email channels, an address that agents answer mail at. They require a runtime configured to receive mail, and aren't enabled on run.camelai.com.
What all channels share
- Each external conversation gets its own agent, made on first contact from the channel's definition, at its revision then.
- Senders must be on the allowlist (
access.allow) unless the channel setsaccess.public. Each sender is rate limited (limits.perSenderPerMinute, default 10), and the channel has a daily turn cap (limits.turnsPerDay, default 1,000). - Each message carries its sender as
from, and tool calls carry a runtime-setorigin({channel, conversationId, sender}) that tools can authorize against. - Attachments are streamed into the agent's workspace at
uploads/<requestId>/<name>: up to 10 files a message, 25 MiB each (20 MB on Telegram) and 100 MiB in all. A file too large or that fails to download is left out, and the prompt says so. - The turn's final answer is sent back when the turn ends, split to the
service's message limit (4,096 characters on Telegram, 4,000 on Slack, 2,000
on Discord), with a typing indicator meanwhile where the service has one.
Channel agents also get a
send_messagetool for updates mid-turn, which can send files too. - Files the agent presents follow the reply: up to 10 MB as photos and 50 MB as documents on Telegram, 100 MiB on Slack, and 10 MiB on Discord. A larger file is sent as a signed link that works for 24 hours.
- Messages are recorded durably before they are acknowledged, duplicates are dropped, and replies go through a durable outbox, so each part is sent once.
- Questions and approvals appear as text, and the next fitting message from an allowed person answers them. See Human input.
Generic webhooks
A webhook channel turns each delivery from any service into a prompt. Give it
the secret the service signs with, then point the service at the channel's
webhookUrl:
curl https://run.camelai.com/v1/channels \
-H "Authorization: Bearer $CAMELAI_API_KEY" -H "Content-Type: application/json" \
-d '{"type": "webhook", "credentials": {"secret": "<the signing secret>"}, "definition": "def_...",
"settings": {"signature": {"type": "hmac-sha256", "header": "Sentry-Hook-Signature"},
"key": "sentry-{{data.issue.id}}",
"filter": [{"path": "action", "in": ["created"]}],
"prompt": "Sentry issue {{data.issue.title}} ({{data.issue.web_url}}) was created. Triage it."}}'| Setting | |
|---|---|
signature | How a delivery proves itself: {"type": "standard"} (Standard Webhooks, the default), {"type": "hmac-sha256", "header", "prefix"?, "encoding"?} (GitHub, Sentry, Linear, Shopify and most others), or {"type": "token", "header"}. Unsigned or wrongly signed deliveries get a 401 |
key | Picks the conversation, and so the agent. Deliveries that render to the same key go to the same agent. Without a key, the channel has one agent |
prompt | What the agent is told. By default, the payload itself. Either way the whole payload is attached as payload.json |
sender | Who a delivery is from, for from and rate limits, such as {{actor.email}} |
filter | Conditions that must all hold (path with in, equals or exists), or the delivery is acknowledged and ignored |
idPath, idHeader | Where a delivery's id is, so retries are dropped |
Templates are {{path}}: a dotted path into the JSON payload
(data.items.0.id), or {{headers.<name>}} for a request header. Bodies must
be JSON, up to 1 MiB.
There's no conversation to answer, so the agent acts through its tools and the
turn's end reaches you as a run.completed event. To get
the reply too, set credentials.replyUrl: each reply is POSTed there as
{"type": "message", "conversationId", "text"}, signed per Standard Webhooks
with the channel's secret.
A webhook channel is public (access.public: true) and allows 60 deliveries a
minute per sender: the signature is what keeps others out. It still has the
daily turn cap.