LanaChat

API: Telegram accounts, pools and stories

8 min readUpdated Markdown

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 #

MethodPathDescriptionPermissionStatus
GET/accountsList accounts (creator_id=, health=connected,pending,expired)can_setupPlanned
POST/accountsAdd an account with its bot token; checked with Telegram before it is savedcan_setupPlanned
GET/accounts/{id}One account, its health and its load this hourcan_setupPlanned
PATCH/accounts/{id}Change its brain, market, traffic, alias or reply language; turn it on or offcan_setupPlanned
DELETE/accounts/{id}Disconnect the account (its conversations are kept)can_setupPlanned
POST/accounts/{id}/checkTest the connection now instead of waiting for the hourly checkcan_setupPlanned
GET/poolsEvery pool with its accounts, capacity and statuscan_trackingPlanned
GET/pools/settingsHourly cap of the workspace and the distribution rulescan_trackingPlanned
PUT/pools/settingsChange the hourly cap (100 to 100,000) and the distributioncan_trackingPlanned
PATCH/pools/accounts/{account_id}Take an account in or out of the pool, pause it, set its weight or hourly limitcan_trackingPlanned
GET/pools/eventsThe pool log: flood waits, pauses, resumes, links heldcan_trackingPlanned
GET/storiesPosted and scheduled stories (creator_id=, status=)can_setupPlanned
POST/storiesPost a story now or schedule it on one or more accountscan_setupPlanned
GET/stories/{id}One story with its views, reactions and link clickscan_setupPlanned
DELETE/stories/{id}Cancel a scheduled storycan_setupPlanned

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"
}
FieldTypeDescription
idstringStarts with acc_
creator_idstringThe creator this account belongs to
usernamestringThe Telegram @username of the account, without the @
bot_usernamestringThe bot linked through the business connection
healthstringconnected, pending or expired
activebooleanfalse when the account is turned off: the AI does not answer on it
brain_idstring or nullThe AI Brain that answers on this account
pool_idstringThe pool its market and traffic tags put it in
marketstringLanguage market, for example fr, en, pt-BR, or all
trafficstringTraffic source, for example instagram or tiktok
story_rightsbooleanWhether the business connection lets LanaChat post stories
last_activity_atstringLast message sent or received, ISO 8601 UTC
  • health is connected, pending (the business connection is not confirmed yet) or expired (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

ParameterTypeRequiredDescription
creator_idstringNoOnly the accounts of this creator
healthstringNoconnected, pending or expired; several separated by commas
limit, cursornumber, stringNoPagination
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

ParameterTypeRequiredDescription
creator_idstringYesThe creator the account belongs to
bot_tokenstringYesThe token of the bot she linked in her Telegram Business settings
marketstringNoLanguage market, for example fr
trafficstringNoTraffic 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

ParameterTypeRequiredDescription
brain_idstringNoThe brain that answers on this account
marketstringNoLanguage market; moves the account to the matching pool
trafficstringNoTraffic source; moves the account to the matching pool
activebooleanNofalse 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 }
}
FieldTypeDescription
cap_per_hournumberMessages the whole workspace may send in a rolling hour, 100 to 100,000
default_limit_per_hournumberHourly limit given to a new account in the pool
distribution.modestringweighted (random, in proportion to each account's weight), round_robin (each account in turn) or least_loaded (the account furthest from its limit)
distribution.warmupbooleanA new account starts at 50 messages an hour and reaches its full limit on day 7
distribution.hold_when_saturatedbooleanWhen 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

ParameterTypeRequiredDescription
cap_per_hournumberYes100 to 100,000, whole number
default_limit_per_hournumberYes10 to 1,000, whole number
distributionobjectYesmode, 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

ParameterTypeRequiredDescription
in_poolbooleanNofalse takes the account out of the pool: it keeps its conversations but gets no new fan
pausedbooleanNotrue pauses it in the pool
weightnumberNo0 to 100; share of new fans in weighted mode (0 is allowed: no new fan)
limit_per_hournumberNo10 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"
}
  • state is active or flood_wait: on a Telegram flood wait the account pauses itself until flood_wait_until, then resumes on its own.
  • During warm-up (warmup_day 1 to 7) the account sends less than its limit_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

ParameterTypeRequiredDescription
creator_idstringNoOnly the events of this creator's accounts
limit, cursornumber, stringNoPagination
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

ParameterTypeRequiredDescription
creator_idstringNoOnly this creator's stories
statusstringNoFor example scheduled
limit, cursornumber, stringNoPagination
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

ParameterTypeRequiredDescription
account_idsarray of stringsYesThe accounts that post it
media_idstringYesA photo or video of the creator's Vault
textstringNoCaption
link_idstringNoA tracking link shown on the story
duration_hoursnumberNoHow long the story stays up
run_atstring or nullNoWhen 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.

Latest news about Lana on Telegram

New releases and beta invites, first in the channel.