Channels¶
This page covers the endpoints that manage a persona's channels — the ways she's reachable from outside the dashboard. Today that's Telegram and Discord (each a bot token). A channel is verified once you pair it to your own account, after which she only listens to that account (see Vocabulary).
Every route takes the persona's id as a path param.
- Add and remove are config routes: they edit her persisted
channelslist and work whether she's running or not, returning 404 if no persona with that id exists. If she happens to be running, they restart her agent so the gateway change takes effect. - Pair is a live-agent route: it needs her running and returns 409 if she isn't.
Add channel¶
Add a Telegram or Discord channel to a persona. The token is validated against the provider before anything is saved; the channel is appended to her channels and persisted. If she's running, her agent is restarted to open the new gateway.
POST /api/persona/{persona_id}/channels
| Path param | Type | Description |
|---|---|---|
persona_id |
string | Her UUID. |
Request body¶
A JSON object:
| Field | Type | Required | Description |
|---|---|---|---|
kind |
string | yes | The channel type — telegram or discord. |
credentials |
object | yes | { "token": "<bot token>" }. The bot token for that provider. |
credentials.token |
string | yes | The bot token. Validated by a call to the provider's "get me" before saving. |
{
"kind": "telegram",
"credentials": { "token": "123456789:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
}
Response¶
200 — the kind that was added:
Adding the channel does not verify it. The new channel starts unverified; complete it with pair so she binds to your account.
Errors¶
| Status | Meaning |
|---|---|
404 |
No persona with that id. |
400 |
Token validation failed ("<kind> validation failed: <reason>") — bad token, unknown kind, or the provider rejected it. |
500 |
Saved, but restarting her running agent to pick up the channel failed ("Channel added but restart failed: <reason>"). |
Example¶
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/channels \
-H 'Content-Type: application/json' \
-d '{"kind": "telegram", "credentials": {"token": "123456789:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}}'
Remove channel¶
Remove a channel from a persona by its name. The channel is dropped from her channels and the change is persisted; if she's running, her agent is restarted so the gateway closes.
DELETE /api/persona/{persona_id}/channels/{channel_name}
| Path param | Type | Description |
|---|---|---|
persona_id |
string | Her UUID. |
channel_name |
string | The channel's name (the account/handle it was paired to). Matched exactly against channel.name. |
The match is on name, not kind — so identify the channel by the name shown for it (e.g. from GET /api/personas, each channel's name). Removing a name that isn't present is a no-op that still returns 200.
Response¶
200 — the name that was removed:
Errors¶
| Status | Meaning |
|---|---|
404 |
No persona with that id. |
500 |
Saved, but restarting her running agent failed ("Channel removed but restart failed: <reason>"). |
Example¶
curl -s -X DELETE http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/channels/my_handle
Pair¶
Claim a pairing code to verify a channel — binding it to your account so she only listens to you on it. The persona prints a short code on the channel; you submit it here. Requires a running persona.
POST /api/persona/{persona_id}/pair
| Path param | Type | Description |
|---|---|---|
persona_id |
string | Her UUID. |
Request body¶
JSON, validated by the PairRequest model:
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | yes | The pairing code she showed on the channel. Case-insensitive; valid for 10 minutes after she issues it. |
Response¶
200 — the paired persona and the now-verified channel:
{
"persona": { "id": "6c17c83c-...", "name": "Adam", "...": "full persona record" },
"channel": {
"type": "telegram",
"name": "my_handle",
"credentials": { "token": "123456789:AAE..." },
"verified_at": "2026-06-04T08:12:44.901+02:00"
}
}
channel.verified_at is set to the moment of pairing, and channel.name becomes the account that claimed the code.
Unmasked — contains the bot token
The persona here is the raw Persona dataclass (real organ api_keys) and channel.credentials.token is the bot token in the clear. HTTP responses that echo a persona are not masked. Don't log or forward it.
Errors¶
| Status | Meaning |
|---|---|
409 |
She isn't running ("Persona is not active."). |
400 |
The code is invalid or expired ("Pairing code is invalid or has expired."), no channel matches the code ("The channel associated with this pairing code could not be found."), or it's already verified ("This channel is already verified."). |
422 |
code missing or not a string (Pydantic validation). |
Example¶
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/pair \
-H 'Content-Type: application/json' \
-d '{"code": "AB12CD"}'
Related¶
- Personas — read a persona's current channels (
GET /api/personas), each with itstype,name, andverifiedflag. - Lifecycle —
restarthappens automatically here when she's running; the manual route is documented there. - The panel — Settings — the screen these routes sit behind.
- Vocabulary —
channel, what verified means.