Skip to content
eternego / docs

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 channels list 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:

{ "kind": "telegram" }

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:

{ "removed": "my_handle" }

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.
{ "code": "AB12CD" }

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"}'

  • Personas — read a persona's current channels (GET /api/personas), each with its type, name, and verified flag.
  • Lifecyclerestart happens automatically here when she's running; the manual route is documented there.
  • The panel — Settings — the screen these routes sit behind.
  • Vocabularychannel, what verified means.