API: Telegram accounts, pools and stories
A Telegram account is one account of a creator, connected to LanaChat through a business connection (a bot she adds in her Telegram settings). Accounts are grouped in pools: a pool is one creator, one market and one traffic source, and new conversations from a tracking link are spread across the sending accounts of the right pool. Stories are posted on one or more accounts at once.
Endpoints #
| Method | Path | Description | Permission | Status |
|---|---|---|---|---|
| GET | /accounts | List accounts (creator_id=, health=connected,pending,expired) | can_setup | Planned |
| POST | /accounts | Add an account with its bot token; checked with Telegram before it is saved | can_setup | Planned |
| GET | /accounts/{id} | One account, its health and its load this hour | can_setup | Planned |
| PATCH | /accounts/{id} | Change its brain, market, traffic, alias or reply language; turn it on or off | can_setup | Planned |
| DELETE | /accounts/{id} | Disconnect the account (its conversations are kept) | can_setup | Planned |
| POST | /accounts/{id}/check | Test the connection now instead of waiting for the hourly check | can_setup | Planned |
| GET | /pools | Every pool with its accounts, capacity and status | can_tracking | Planned |
| GET | /pools/settings | Hourly cap of the workspace and the distribution rules | can_tracking | Planned |
| PUT | /pools/settings | Change the hourly cap (100 to 100,000) and the distribution | can_tracking | Planned |
| PATCH | /pools/accounts/{account_id} | Take an account in or out of the pool, pause it, set its weight or hourly limit | can_tracking | Planned |
| GET | /pools/events | The pool log: flood waits, pauses, resumes, links held | can_tracking | Planned |
| GET | /stories | Posted and scheduled stories (creator_id=, status=) | can_setup | Planned |
| POST | /stories | Post a story now or schedule it on one or more accounts | can_setup | Planned |
| GET | /stories/{id} | One story with its views, reactions and link clicks | can_setup | Planned |
| DELETE | /stories/{id} | Cancel a scheduled story | can_setup | Planned |
The account object #
{
"id": "acc_1001",
"creator_id": "cr_lea",
"username": "lea_officiel",
"bot_username": "lea_helper_bot",
"health": "connected",
"active": true,
"brain_id": "br_lea_main",
"pool_id": "pool_lea_fr_instagram",
"market": "fr",
"traffic": "instagram",
"story_rights": true,
"last_activity_at": "2026-10-06T13:58:20Z"
}
| Field | Type | Description |
|---|---|---|
id | string | Starts with acc_ |
creator_id | string | The creator this account belongs to |
username | string | The Telegram @username of the account, without the @ |
bot_username | string | The bot linked through the business connection |
health | string | connected, pending or expired |
active | boolean | false when the account is turned off: the AI does not answer on it |
brain_id | string or null | The AI Brain that answers on this account |
pool_id | string | The pool its market and traffic tags put it in |
market | string | Language market, for example fr, en, pt-BR, or all |
traffic | string | Traffic source, for example instagram or tiktok |
story_rights | boolean | Whether the business connection lets LanaChat post stories |
last_activity_at | string | Last message sent or received, ISO 8601 UTC |
healthisconnected,pending(the business connection is not confirmed yet) orexpired(the bot lost access; reconnect it).- The bot token is never returned. LanaChat never asks for a phone number, a password or a 2FA code.
Accounts #
List accounts #
GET /accounts · can_setup
| Parameter | Type | Required | Description |
|---|---|---|---|
creator_id | string | No | Only the accounts of this creator |
health | string | No | connected, pending or expired; several separated by commas |
limit, cursor | number, string | No | Pagination |
curl "https://api.lanachat.ai/v1/accounts?creator_id=cr_lea&health=connected,expired" \
-H "Authorization: Bearer $LANACHAT_TOKEN"
{
"data": [
{ "id": "acc_1001", "creator_id": "cr_lea", "username": "lea_officiel", "bot_username": "lea_helper_bot", "health": "connected", "active": true, "brain_id": "br_lea_main", "pool_id": "pool_lea_fr_instagram", "market": "fr", "traffic": "instagram", "story_rights": true, "last_activity_at": "2026-10-06T13:58:20Z" },
{ "id": "acc_1004", "creator_id": "cr_lea", "username": "lea_backup", "bot_username": "lea_helper2_bot", "health": "connected", "active": true, "brain_id": "br_lea_main", "pool_id": "pool_lea_fr_instagram", "market": "fr", "traffic": "instagram", "story_rights": false, "last_activity_at": "2026-10-06T13:51:02Z" }
],
"next_cursor": null
}
Add an account #
POST /accounts · can_setup
| Parameter | Type | Required | Description |
|---|---|---|---|
creator_id | string | Yes | The creator the account belongs to |
bot_token | string | Yes | The token of the bot she linked in her Telegram Business settings |
market | string | No | Language market, for example fr |
traffic | string | No | Traffic source, for example instagram |
curl -X POST https://api.lanachat.ai/v1/accounts \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"creator_id": "cr_lea", "bot_token": "<bot token>", "market": "fr", "traffic": "instagram"}'
{
"id": "acc_1007",
"creator_id": "cr_lea",
"username": "lea_officiel",
"bot_username": "lea_helper_bot",
"health": "pending",
"active": true,
"brain_id": "br_lea_main",
"pool_id": "pool_lea_fr_instagram",
"market": "fr",
"traffic": "instagram",
"story_rights": false,
"last_activity_at": null
}
The answer is the account (201) with health: "pending" until the creator confirms the business connection in Telegram. The bot token is checked with Telegram before anything is saved: a token Telegram refuses answers 400. An account already active in another workspace is refused (409). Each account needs a licence to reply: see Billing.
Get an account #
GET /accounts/{id} · can_setup
curl https://api.lanachat.ai/v1/accounts/acc_1001 \
-H "Authorization: Bearer $LANACHAT_TOKEN"
The answer is the account object, with its load this hour. An unknown id answers 404.
Update an account #
PATCH /accounts/{id} · can_setup
| Parameter | Type | Required | Description |
|---|---|---|---|
brain_id | string | No | The brain that answers on this account |
market | string | No | Language market; moves the account to the matching pool |
traffic | string | No | Traffic source; moves the account to the matching pool |
active | boolean | No | false turns the account off, true turns it back on |
The alias and the reply language of the account can be changed the same way.
curl -X PATCH https://api.lanachat.ai/v1/accounts/acc_1004 \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"traffic": "tiktok", "active": true}'
The answer is the updated account. Turning off the last sending account of a creator who has active links answers 409.
Disconnect an account #
DELETE /accounts/{id} · can_setup
curl -X DELETE https://api.lanachat.ai/v1/accounts/acc_1004 \
-H "Authorization: Bearer $LANACHAT_TOKEN"
Its conversations are kept. Removing the last sending account of a creator who has active links answers 409.
Check the connection now #
POST /accounts/{id}/check · can_setup
curl -X POST https://api.lanachat.ai/v1/accounts/acc_1001/check \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"
LanaChat checks every account once an hour; this call tests it now. The answer is the account with its fresh health.
Pools #
A pool is formed by its accounts' tags (market and traffic); there is nothing to create. A new conversation goes to the pool whose traffic matches the link source and whose market matches the fan's language, then to the creator's "All traffic" pool, then to any of her pools that still sends. Existing conversations always stay on their account.
List pools #
GET /pools · can_tracking
curl https://api.lanachat.ai/v1/pools \
-H "Authorization: Bearer $LANACHAT_TOKEN"
{
"data": [
{
"id": "pool_lea_fr_instagram",
"name": "French · Instagram",
"creator_id": "cr_lea",
"accounts": ["acc_1001", "acc_1004"],
"sent_last_hour": 312,
"capacity_per_hour": 400,
"status": "near"
}
],
"next_cursor": null
}
status is sending, near (80% of its capacity), saturated (95%) or none (no sending account).
Get the pool settings #
GET /pools/settings · can_tracking
curl https://api.lanachat.ai/v1/pools/settings \
-H "Authorization: Bearer $LANACHAT_TOKEN"
{
"cap_per_hour": 2000,
"default_limit_per_hour": 200,
"distribution": { "mode": "weighted", "warmup": true, "hold_when_saturated": true }
}
| Field | Type | Description |
|---|---|---|
cap_per_hour | number | Messages the whole workspace may send in a rolling hour, 100 to 100,000 |
default_limit_per_hour | number | Hourly limit given to a new account in the pool |
distribution.mode | string | weighted (random, in proportion to each account's weight), round_robin (each account in turn) or least_loaded (the account furthest from its limit) |
distribution.warmup | boolean | A new account starts at 50 messages an hour and reaches its full limit on day 7 |
distribution.hold_when_saturated | boolean | When no account can take a new fan, hold the fan until one frees up, oldest first; otherwise give the fan to the least loaded account even above its limit |
When the workspace reaches cap_per_hour, links keep redirecting but new conversations are held until the hour drops under the cap.
Change the pool settings #
PUT /pools/settings · can_tracking
| Parameter | Type | Required | Description |
|---|---|---|---|
cap_per_hour | number | Yes | 100 to 100,000, whole number |
default_limit_per_hour | number | Yes | 10 to 1,000, whole number |
distribution | object | Yes | mode, warmup and hold_when_saturated, as above |
curl -X PUT https://api.lanachat.ai/v1/pools/settings \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cap_per_hour": 3000, "default_limit_per_hour": 200, "distribution": {"mode": "least_loaded", "warmup": true, "hold_when_saturated": true}}'
The answer is the new settings. A cap outside 100 to 100,000 answers 400.
Change an account in the pool #
PATCH /pools/accounts/{account_id} · can_tracking
| Parameter | Type | Required | Description |
|---|---|---|---|
in_pool | boolean | No | false takes the account out of the pool: it keeps its conversations but gets no new fan |
paused | boolean | No | true pauses it in the pool |
weight | number | No | 0 to 100; share of new fans in weighted mode (0 is allowed: no new fan) |
limit_per_hour | number | No | 10 to 1,000 messages an hour for this account |
curl -X PATCH https://api.lanachat.ai/v1/pools/accounts/acc_1004 \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"weight": 40, "limit_per_hour": 300}'
{
"account_id": "acc_1004",
"creator_id": "cr_lea",
"username": "lea_backup",
"in_pool": true,
"paused": false,
"weight": 40,
"limit_per_hour": 300,
"sent_last_hour": 88,
"new_conversations_today": 41,
"state": "active",
"flood_wait_until": null,
"warmup_day": 7,
"added_at": "2026-09-20T10:00:00Z"
}
stateisactiveorflood_wait: on a Telegram flood wait the account pauses itself untilflood_wait_until, then resumes on its own.- During warm-up (
warmup_day1 to 7) the account sends less than itslimit_per_hour: 50 an hour on day 1, the full limit on day 7. - Taking out, pausing or removing the last sending account of a creator who has active links is refused (
409).
Read the pool log #
GET /pools/events · can_tracking
| Parameter | Type | Required | Description |
|---|---|---|---|
creator_id | string | No | Only the events of this creator's accounts |
limit, cursor | number, string | No | Pagination |
curl "https://api.lanachat.ai/v1/pools/events?creator_id=cr_lea&limit=2" \
-H "Authorization: Bearer $LANACHAT_TOKEN"
{
"data": [
{ "at": "2026-10-06T13:40:12Z", "kind": "resumed", "creator_id": "cr_lea", "account_id": "acc_1004", "text": "@lea_backup is sending again." },
{ "at": "2026-10-06T13:25:12Z", "kind": "flood_wait", "creator_id": "cr_lea", "account_id": "acc_1004", "text": "@lea_backup hit a Telegram flood wait of 900 seconds." }
],
"next_cursor": "eyJhdCI6IjIwMjYtMTAtMDZUMTM6MjU6MTJaIn0"
}
kind is flood_wait, account_paused, resumed, link_paused (the workspace cap was reached, new fans are held), account_added, account_removed or settings. text is a plain English sentence.
Stories #
List stories #
GET /stories · can_setup
| Parameter | Type | Required | Description |
|---|---|---|---|
creator_id | string | No | Only this creator's stories |
status | string | No | For example scheduled |
limit, cursor | number, string | No | Pagination |
curl "https://api.lanachat.ai/v1/stories?creator_id=cr_lea&status=scheduled" \
-H "Authorization: Bearer $LANACHAT_TOKEN"
{
"data": [ { "id": "sto_88", "status": "scheduled", "run_at": "2026-10-06T19:00:00Z", "account_ids": ["acc_1001", "acc_1004"] } ],
"next_cursor": null
}
Post a story #
POST /stories · can_setup
| Parameter | Type | Required | Description |
|---|---|---|---|
account_ids | array of strings | Yes | The accounts that post it |
media_id | string | Yes | A photo or video of the creator's Vault |
text | string | No | Caption |
link_id | string | No | A tracking link shown on the story |
duration_hours | number | No | How long the story stays up |
run_at | string or null | No | When to post it (ISO 8601 UTC); leave it out to post now |
curl -X POST https://api.lanachat.ai/v1/stories \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"account_ids": ["acc_1001", "acc_1004"], "media_id": "med_5521", "text": "New set tonight", "link_id": "lnk_3", "duration_hours": 24, "run_at": "2026-10-06T19:00:00Z"}'
{ "id": "sto_88", "status": "scheduled", "run_at": "2026-10-06T19:00:00Z", "account_ids": ["acc_1001", "acc_1004"] }
An account without the "manage stories" right in its business connection (story_rights: false) is refused, with the reason in message.
Get a story #
GET /stories/{id} · can_setup
curl https://api.lanachat.ai/v1/stories/sto_88 \
-H "Authorization: Bearer $LANACHAT_TOKEN"
The answer is the story with its views, reactions and link clicks once it is posted.
Cancel a scheduled story #
DELETE /stories/{id} · can_setup
curl -X DELETE https://api.lanachat.ai/v1/stories/sto_88 \
-H "Authorization: Bearer $LANACHAT_TOKEN"
Only a scheduled story can be cancelled.