# LanaChat API: quick start, authentication and errors

_API · 8 min read · Updated 2026-10-22 · https://lanachat.ai/guides/api-overview/_

Everything your team does in the Console, your code can do too. The LanaChat API reads and changes your whole workspace: creators, Telegram accounts, AI Brains, scripts, the Vault, fans and conversations, tracking links, billing and your team. It is plain JSON over HTTPS, one URL per resource, with the same permissions as the Console. Webhooks push events to your server, and the MCP server lets an AI assistant such as Claude or Cursor work in your workspace with the same token.

> Note: This is the public API reference. Endpoints marked **Planned** are the published contract the backend is built from: they do not answer yet. The [MCP connection](https://lanachat.ai/guides/api-mcp/) uses the same access tokens.

## What you can build

- A sales dashboard in your own tools: today's revenue per creator, per link, per source.
- Alerts in Slack or Telegram when a fan buys, when a conversation needs review, or when an account loses its connection.
- A setup script that adds a creator, connects her accounts, uploads her Vault and writes her first script.
- A tracking pipeline: create one link per ad, read clicks, conversations and buyers every hour.
- An AI assistant that drafts scripts and persona changes for you to review, through [MCP](https://lanachat.ai/guides/api-mcp/).

## Quick start in 5 minutes

1. In the Console, open **Users › API & MCP** and press **Create token**.
2. Name it (for example "Reporting script"), choose **Custom permissions** and tick what it needs, for example **Read fans and conversations** and **Read sales**.
3. Save, then press **Copy token**. The token is shown once.

**4. Keep it in an environment variable**, so it never sits in your code:

```bash
export LANACHAT_TOKEN="lc_live_8f2c1d0e9b7a4c6f"
```

**5. Make your first call.** It returns your workspace and what the token may do:

```bash
curl https://api.lanachat.ai/v1/workspace \
  -H "Authorization: Bearer $LANACHAT_TOKEN"
```

```js
const res = await fetch('https://api.lanachat.ai/v1/workspace', {
  headers: { Authorization: `Bearer ${process.env.LANACHAT_TOKEN}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const workspace = await res.json();
console.log(workspace.name, workspace.token.permissions);
```

```python
import os
import requests

r = requests.get(
    "https://api.lanachat.ai/v1/workspace",
    headers={"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}"},
    timeout=30,
)
r.raise_for_status()
print(r.json()["name"])
```

```json
{
  "id": "ws_7Hq2",
  "name": "Mia Agency",
  "kind": "agency",
  "timezone": "Europe/Paris",
  "token": { "id": "tok_31", "name": "Reporting script", "permissions": ["can_fan_read", "can_sales_read"], "expires_at": "2027-01-06T00:00:00Z" }
}
```

That's it: every other endpoint works the same way. Ready-made scripts are in [API quick recipes](https://lanachat.ai/guides/api-recipes/).

## Every resource

| Resource | What it covers | Guide |
|---|---|---|
| Workspace | `GET /workspace`: the workspace and the token's permissions | This page |
| Creators | Creators, identity, persona and setup progress | [Creators](https://lanachat.ai/guides/api-creators/) |
| Telegram accounts | Accounts, pools, pool settings and stories | [Telegram accounts](https://lanachat.ai/guides/api-telegram-accounts/) |
| AI Brains | Brains, drafts, publishing, versions and the Playground | [AI Brains](https://lanachat.ai/guides/api-ai-brains/) |
| Scripts | Scripts, steps and folders | [Scripts](https://lanachat.ai/guides/api-scripts/) |
| Vault | Media, folders and signed uploads | [Vault](https://lanachat.ai/guides/api-vault/) |
| Fans and conversations | Fans, lists, sales of a fan, messages, takeover | [Conversations](https://lanachat.ai/guides/api-conversations/) |
| Tracking | Links, domains, pixels, events and stats | [Tracking](https://lanachat.ai/guides/api-tracking/) |
| Billing | Balance, ledger, deposits, licences, withdrawals, invoices | [Billing](https://lanachat.ai/guides/api-billing/) |
| Team | Members, roles and access tokens | [Team](https://lanachat.ai/guides/api-team/) |
| Webhooks | Events pushed to your server, signatures and retries | [Webhooks](https://lanachat.ai/guides/api-webhooks/) |
| MCP | The server for AI assistants and its tools | [MCP](https://lanachat.ai/guides/api-mcp/) |

## Base URL and versions

Every path in these guides is relative to:

```text
https://api.lanachat.ai/v1
```

The version is in the path. A breaking change gets a new version (`/v2`); new fields and new endpoints are added to `/v1` without notice, so ignore the fields you do not know.

## Authentication

Every request carries your token in the `Authorization` header, after the word `Bearer`:

```text
Authorization: Bearer lc_live_8f2c1d0e9b7a4c6f
```

- Create, edit, rotate and revoke tokens in **Users › API & MCP**, or with the [token endpoints](https://lanachat.ai/guides/api-team/). Only the workspace owner and agency owners can open that page.
- A token is shown once, when you create it. Store it like a password; **Rotate** or **Revoke** it from the same page.
- A request without a valid token answers `401`. A token without the permission an endpoint needs answers `403`.
- Tokens never go in a URL or in browser code: call the API from your server.
- Use one token per script or assistant, so each can be changed or revoked on its own.

## Workspaces

A token belongs to one workspace, the one it was created in. Every request reads and writes that workspace only; there is no workspace id in the paths. An owner token (the workspace that manages several agencies) may act on one of its agencies with the header `LanaChat-Workspace: ws_…`; any other token sending that header gets `403`.

## Permissions

Each endpoint lists the permission it needs. They are the ones you tick when you create a token:

| Permission | In the Console | Gives |
|---|---|---|
| `can_setup` | Manage workspace setup | Creators, media, Telegram accounts, scripts and team members |
| `can_engine` | Access AI configuration | AI Brain drafts, scripts' AI settings and tests |
| `can_publish` | Publish AI Brain drafts | Publishing a brain draft (needs `can_engine`) |
| `can_ai_test` | Test Advanced AI drafts | Trying drafts that use Advanced AI (owner workspace only) |
| `can_ai_tune` | Adjust Advanced AI settings | Changing the Advanced AI sensitivity settings (owner workspace only) |
| `can_ai_publish` | Publish Advanced AI profiles | Publishing profiles that use Advanced AI (owner workspace only) |
| `can_commercial_reports` | Read commercial experiment reports | Experiments and their review reports (owner workspace only) |
| `can_fan_read` | Read fans and conversations | Fans, conversations and messages, read only |
| `can_fan_import` | Import fan history | Importing past fans and messages |
| `can_sales_read` | Read sales | Sales, stats and the dashboard numbers |
| `can_chat` | New: Chat with fans | Sending messages, reactions and taking over a conversation |
| `can_tracking` | New: Manage tracking | Links, domains, pools, pixels and events |
| `owner` | Owner token | Billing, roles, webhooks and access tokens; only the workspace owner can create it |

- Turning **Access AI configuration** (`can_engine`) off also turns off publishing, Advanced AI and experiment reports.
- `can_chat`, `can_tracking` and the `owner` token are planned: the Console does not offer them yet.

## Requests and responses

- Bodies are JSON (`Content-Type: application/json`), in UTF-8. Uploads go through a [signed URL](https://lanachat.ai/guides/api-vault/), never through the API itself.
- Ids are strings with a prefix that says what they are: `cr_` creator, `acc_` Telegram account, `pool_`, `sto_` story, `br_` brain, `scr_` script, `med_` media, `fan_`, `conv_` conversation, `msg_`, `lnk_` link, `px_` pixel, `mem_` member, `tok_` token.
- Times are ISO 8601 in UTC (`2026-10-06T14:05:00Z`). Days in stats are UTC days.
- Money is in US cents (`amount_cents: 1900` is $19.00). Telegram Stars are whole numbers (`stars: 250`).
- `PATCH` changes only the fields you send. `PUT` replaces the whole object.
- A `POST` that creates something answers `201` with the new object; other successful calls answer `200`.

## Pagination

Every list answers one page and a cursor to the next one:

```bash
curl "https://api.lanachat.ai/v1/fans?limit=50&cursor=eyJpZCI6ImZhbl85MjAifQ" \
  -H "Authorization: Bearer $LANACHAT_TOKEN"
```

```json
{
  "data": [ { "id": "fan_921", "display_name": "Marco", "creator_id": "cr_lea" } ],
  "next_cursor": "eyJpZCI6ImZhbl85NzAifQ"
}
```

- `limit` is 1 to 100, 25 by default.
- `next_cursor` is `null` on the last page. A cursor is opaque: pass it back as it is, never build one.
- Lists are sorted newest first unless the endpoint says otherwise.

To read every page, loop until `next_cursor` is `null`:

```js
async function all(path) {
  const items = [];
  let cursor = null;
  do {
    const url = new URL('https://api.lanachat.ai/v1' + path);
    url.searchParams.set('limit', '100');
    if (cursor) url.searchParams.set('cursor', cursor);
    const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.LANACHAT_TOKEN}` } });
    if (!res.ok) throw new Error((await res.json()).error.message);
    const page = await res.json();
    items.push(...page.data);
    cursor = page.next_cursor;
  } while (cursor);
  return items;
}

const fans = await all('/fans?creator_id=cr_lea');
```

```python
import os
import requests

def all_items(path, **params):
    items, cursor = [], None
    while True:
        r = requests.get(
            "https://api.lanachat.ai/v1" + path,
            params={**params, "limit": 100, **({"cursor": cursor} if cursor else {})},
            headers={"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}"},
            timeout=30,
        )
        r.raise_for_status()
        page = r.json()
        items += page["data"]
        cursor = page["next_cursor"]
        if not cursor:
            return items

fans = all_items("/fans", creator_id="cr_lea")
```

## Errors

An error answers a 4xx or 5xx status and always the same body:

```json
{
  "error": {
    "code": "insufficient_balance",
    "message": "Your balance is $12.40 and this pack costs $170.00. Top up first."
  }
}
```

| Status | `code` | When |
|---|---|---|
| 400 | `invalid_request` | A field is missing or has the wrong format; `message` says which |
| 401 | `unauthorized` | No token, or a revoked or expired token |
| 402 | `insufficient_balance` | The balance does not cover a purchase |
| 403 | `forbidden` | The token lacks the permission the endpoint needs |
| 404 | `not_found` | The id does not exist in this workspace |
| 409 | `conflict` | The change would break a rule (a duplicate slug, the last sending account of a creator) |
| 429 | `rate_limited` | Too many requests; wait for `Retry-After` seconds |
| 500 | `server_error` | Our side failed; retry later with the same `Idempotency-Key` |

`message` is a plain English sentence you can show to a person. Branch your code on `code`, never on `message`.

## Rate limits

Each token may send **600 requests per minute**. Every answer carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds until the window resets). Above the limit the API answers `429` with a `Retry-After` header. Sending a message to a fan is also bound by Telegram's own limits: see the [pool rules](https://lanachat.ai/guides/api-telegram-accounts/).

A small helper that waits and tries again on `429` and `5xx`:

```js
async function lanachat(method, path, body) {
  const key = crypto.randomUUID();   // one key per action: a retry never does the work twice
  for (let attempt = 0; attempt < 5; attempt++) {
    const res = await fetch('https://api.lanachat.ai/v1' + path, {
      method,
      headers: {
        Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
        'Content-Type': 'application/json',
        ...(method === 'POST' ? { 'Idempotency-Key': key } : {}),
      },
      body: body ? JSON.stringify(body) : undefined,
    });
    if (res.status === 429 || res.status >= 500) {
      const wait = Number(res.headers.get('Retry-After')) || 2 ** attempt;
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }
    const data = await res.json();
    if (!res.ok) throw Object.assign(new Error(data.error.message), { code: data.error.code, status: res.status });
    return data;
  }
  throw new Error('LanaChat API: too many retries');
}
```

Use it everywhere: `await lanachat('GET', '/creators')`, `await lanachat('POST', '/links', { … })`.

## Idempotency

Send an `Idempotency-Key` header (any unique string up to 255 characters, a UUID is fine) on every `POST`. If the same key comes back within 24 hours, the API answers the first result again instead of doing the work twice: a network error never sends a message or buys a pack twice.

```bash
curl -X POST https://api.lanachat.ai/v1/billing/licences/buy \
  -H "Authorization: Bearer $LANACHAT_TOKEN" \
  -H "Idempotency-Key: 4b7f2a8e-1c3d-4e5f-9a0b-6c7d8e9f0a1b" \
  -H "Content-Type: application/json" \
  -d '{"pack": 10, "qty": 1}'
```

The same key with a different body answers `409`. In a shell, `$(uuidgen)` makes a fresh key for each new action.

## Webhooks

Instead of asking the API every minute, let LanaChat call you. A webhook sends an HTTPS `POST` to your server when a fan writes for the first time, buys, is refunded, when a media is ready or an account loses its connection. Every delivery is signed (HMAC-SHA256) and retried for 24 hours. The events, payloads and the signature check in Node and Python are in [Webhooks](https://lanachat.ai/guides/api-webhooks/).

## MCP for AI assistants

MCP is an open standard that lets an AI assistant use tools in an app. LanaChat's MCP server lets Claude, Cursor or any MCP client read your creators, draft scripts, edit a brain draft and read your sales, with the same access token and the same permissions. In Claude Code, one command connects it:

```bash
claude mcp add --transport http lanachat https://app.lanachat.ai/mcp \
  --header "Authorization: Bearer $LANACHAT_TOKEN"
```

The configuration for every assistant and the list of tools are in [API & MCP](https://lanachat.ai/guides/api-mcp/).

## Related

- [API quick recipes: copy, paste, run](https://lanachat.ai/guides/api-recipes/)
- [API & MCP: connect an AI assistant](https://lanachat.ai/guides/api-mcp/)
- [API: webhooks, events and signatures](https://lanachat.ai/guides/api-webhooks/)
