Files
featherChat/warzone/docs/BOT_API.md
Siavash Sameni 76cac77259 v0.0.28: BotFather-only registration, per-instance bot toggle, docs update
Security:
- Bot registration restricted to BotFather (requires botfather_token)
- Direct POST /v1/bot/register without BotFather auth → rejected

Deploy:
- systemd service reads /home/warzone/server.env for EXTRA_ARGS
- deploy/warzone-server.env.mequ: no bots (default)
- deploy/warzone-server.env.kh3rad3ree: --enable-bots
- setup.sh copies per-hostname env file

Docs updated:
- LLM_HELP.md: BotFather flow, plaintext bot messaging, E2E option, bridge
- LLM_BOT_DEV.md: botfather_token requirement, E2E mode, bridge section
- BOT_API.md: full BotFather flow, ownership, numeric IDs, webhook delivery
- SERVER.md: --enable-bots flag, per-instance config, bot system section
- USAGE.md: bot messaging, BotFather, bridge tool

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 09:52:12 +04:00

12 KiB

featherChat Bot API

Overview

featherChat exposes a Telegram Bot API-compatible HTTP interface, allowing developers to build bots that interact with featherChat users using familiar patterns. Bots are created exclusively through @botfather, receive a token, and communicate via long-polling or webhooks.

The server must be started with --enable-bots to activate bot functionality.

Key properties:

  • BotFather is required -- only @botfather can register bots. It is auto-created on first server start (token printed in server logs).
  • Bot aliases must end with Bot, bot, or _bot (auto-enforced on registration).
  • Bots receive encrypted user messages as base64 blobs (raw_encrypted field) unless registered as E2E bots. Plaintext bot-to-bot messages are delivered with a readable text field.
  • Bot-sent messages are plaintext (not E2E encrypted) unless the bot is registered in E2E mode.
  • chat_id accepts both hex fingerprints and numeric IDs (Telegram compatibility). Numeric IDs are also returned in from.id.
  • Each bot has an owner field linking to the creating user's fingerprint.

Quick Start

1. Message @botfather to create a bot (or use BotFather token from server logs).
   BotFather registers the bot via:
   POST /v1/bot/register
   {"name": "WeatherBot", "fingerprint": "aabbccdd...", "botfather_token": "<bf_token>"}

2. Extract the token from the response.

3. Poll for updates:
   POST /v1/bot/<token>/getUpdates
   {"timeout": 50}

4. Send a reply:
   POST /v1/bot/<token>/sendMessage
   {"chat_id": "<sender_fingerprint_or_numeric_id>", "text": "Hello!"}

Endpoints

1. Register a Bot

POST /v1/bot/register

Creates a new bot, stores it in the server database, and auto-registers an alias. Only @botfather can call this endpoint -- a valid botfather_token is required.

Request:

{
  "name": "MyBot",
  "fingerprint": "aabbccdd1122334455667788aabbccdd",
  "botfather_token": "<botfather_token>",
  "owner": "<creator_fingerprint>"
}
Field Type Description
name string Display name. Alias suffix auto-added if needed.
fingerprint string Hex-encoded public key fingerprint for the bot.
botfather_token string BotFather authorization token (required).
owner string Fingerprint of the user who requested creation.

E2E bot registration (optional additional fields):

Field Type Description
e2e bool Set to true to register as an E2E bot.
bundle object Full prekey bundle (identity_key, signed_prekey, signature, one_time_prekeys).
eth_address string Ethereum address for the bot.

Response:

{
  "ok": true,
  "result": {
    "token": "aabbccdd11223344:9f8e7d6c5b4a39281706abcdef012345",
    "name": "MyBot",
    "fingerprint": "aabbccdd1122334455667788aabbccdd",
    "alias": "@mybot_bot",
    "owner": "<creator_fingerprint>"
  }
}

Token format: <first-16-chars-of-fingerprint>:<32-hex-random-bytes>

Alias rules:

  • If the name already ends with Bot, bot, or _bot, the alias is the lowercased name (e.g. WeatherBot -> @weatherbot).
  • Otherwise _bot is appended (e.g. weather -> @weather_bot).
  • The alias is registered in both directions (alias -> fingerprint and fingerprint -> alias).

2. Get Bot Info

GET /v1/bot/:token/getMe

Returns information about the bot in a Telegram-compatible shape.

Response (valid token):

{
  "ok": true,
  "result": {
    "id": "aabbccdd1122334455667788aabbccdd",
    "is_bot": true,
    "first_name": "MyBot",
    "username": "MyBot"
  }
}

Response (invalid token):

{
  "ok": false,
  "description": "invalid token"
}

3. Get Updates (Long-Poll)

POST /v1/bot/:token/getUpdates

Returns queued messages for the bot and deletes them from the queue.

Request:

{
  "timeout": 5
}
Field Type Description
timeout u64 Optional. Long-poll wait in seconds. Capped at 50.

If the queue is empty and timeout > 0, the server waits up to timeout seconds (max 50) before returning an empty result, giving new messages a chance to arrive.

Note: If a webhook is configured via setWebhook, updates are delivered live to the webhook URL via POST instead of being queued for polling.

Response:

{
  "ok": true,
  "result": [ ...updates... ]
}

Update Types

Encrypted message (from a user — bot must decrypt if it has a session):

{
  "update_id": 1,
  "message": {
    "message_id": "uuid",
    "from": {
      "id": "sender_fingerprint",
      "is_bot": false,
      "first_name": "sender_finge"
    },
    "chat": {
      "id": "sender_fingerprint",
      "type": "private"
    },
    "date": 1711670400,
    "text": null,
    "raw_encrypted": "base64-encoded-wiremessage..."
  }
}

Key exchange (X3DH session initiation — same shape as encrypted message):

{
  "update_id": 2,
  "message": {
    "message_id": "uuid",
    "from": { "id": "sender_fp", "is_bot": false, "first_name": "sender_fp..." },
    "chat": { "id": "sender_fp", "type": "private" },
    "date": 1711670400,
    "text": null,
    "raw_encrypted": "base64-encoded-keyexchange..."
  }
}

Call signal:

{
  "update_id": 3,
  "message": {
    "message_id": "uuid",
    "from": { "id": "sender_fp", "is_bot": false, "first_name": "sender_fp..." },
    "chat": { "id": "sender_fp", "type": "private" },
    "date": 1711670400,
    "text": "/call_Offer",
    "call_signal": {
      "type": "Offer",
      "payload": "SDP or ICE data..."
    }
  }
}

File header:

{
  "update_id": 4,
  "message": {
    "message_id": "uuid",
    "from": { "id": "sender_fp", "is_bot": false, "first_name": "sender_fp..." },
    "chat": { "id": "sender_fp", "type": "private" },
    "date": 1711670400,
    "document": {
      "file_name": "report.pdf",
      "file_size": 204800
    }
  }
}

Bot message (plaintext, from another bot via sendMessage):

{
  "update_id": 5,
  "message": {
    "message_id": "uuid",
    "from": {
      "id": "other_bot_fingerprint",
      "is_bot": true
    },
    "chat": {
      "id": "other_bot_fingerprint",
      "type": "private"
    },
    "date": 1711670400,
    "text": "Hello from the other bot!"
  }
}

Note: Receipt and internal wire messages (FileChunk, GroupSenderKey, SenderKeyDistribution) are silently skipped and never delivered as updates.


4. Send Message

POST /v1/bot/:token/sendMessage

Sends a plaintext message to a user or another bot.

Request:

{
  "chat_id": "aabbccdd1122334455667788aabbccdd",
  "text": "Hello from MyBot!"
}
Field Type Description
chat_id string/int Recipient fingerprint (hex), Ethereum address, or numeric ID.
text string Message body.
parse_mode string Optional. "HTML" renders basic tags (, , , ).

chat_id accepts hex fingerprint strings, Ethereum addresses, or numeric integer IDs (Telegram compatibility). Non-hex characters in string chat_ids are stripped and the value is lowercased before routing.

Response:

{
  "ok": true,
  "result": {
    "message_id": "550e8400-e29b-41d4-a716-446655440000",
    "chat": {
      "id": "aabbccdd1122334455667788aabbccdd",
      "type": "private"
    },
    "text": "Hello from MyBot!",
    "date": 1711670400,
    "delivered": true
  }
}

The delivered field indicates whether the message was sent over a live WebSocket connection (true) or queued for later retrieval (false).


Alias Rules

Rule Detail
Bot aliases must end with Bot, bot, or _bot Enforced at registration time.
Non-bot users cannot register aliases with these suffixes Reserved for bots.
Auto-registered on bot creation No separate alias step needed.
Users message bots via alias e.g. @mybot_bot, resolved like any other alias.

Differences from Telegram Bot API

Feature Telegram featherChat
chat_id type Numeric integer Hex fingerprint string or numeric integer (both accepted)
getUpdates timeout Up to 50s Capped at 50s
Message content Always plaintext Encrypted messages arrive as raw_encrypted base64; E2E bots can decrypt
Bot-sent messages Plaintext Plaintext by default; E2E mode available
from.id Numeric integer Numeric integer (from.id_str has hex fingerprint)
parse_mode Renders HTML/Markdown HTML rendered (, , , )
Inline keyboards / callback queries Supported Stored + delivered, no popup
Webhooks (setWebhook) Supported Implemented -- updates delivered live to webhook URL
Media groups Supported Not yet (planned)
File download (getFile) Supported Not yet (planned)

Example: Simple Echo Bot (Python)

import requests
import time

TOKEN = "your_bot_token"
API = f"http://localhost:7700/v1/bot/{TOKEN}"

while True:
    resp = requests.post(f"{API}/getUpdates", json={"timeout": 50}).json()
    for update in resp.get("result", []):
        msg = update.get("message", {})
        text = msg.get("text") or "[encrypted]"
        chat_id = msg.get("chat", {}).get("id", "")
        if text and chat_id:
            requests.post(f"{API}/sendMessage", json={
                "chat_id": chat_id,
                "text": f"Echo: {text}",
            })
    time.sleep(1)

Example: Registration (curl)

curl -X POST http://localhost:7700/v1/bot/register \
  -H "Content-Type: application/json" \
  -d '{"name": "EchoBot", "fingerprint": "aabbccdd1122334455667788aabbccdd"}'

Authentication

All bot endpoints (except /register) are authenticated by the token in the URL path. Tokens are generated at registration time and stored server-side. There is no expiration mechanism in v1 -- tokens remain valid until the server database is cleared.

The token grants full access to poll and send messages as the bot. Treat it like a password.


Internal Details

  • Bot info is stored in the tokens sled tree under key bot:<token>.
  • A reverse lookup bot_fp:<fingerprint> -> <token> is also maintained.
  • Aliases are stored in the aliases sled tree (a:<alias> -> fingerprint, fp:<fingerprint> -> alias).
  • Queued messages live in the messages sled tree under prefix queue:<bot_fingerprint>:* and are deleted after getUpdates consumes them.
  • Messages are delivered via deliver_or_queue -- live WebSocket if online, otherwise queued.

Bot Bridge (tools/bot-bridge.py)

A compatibility layer for existing Telegram bot libraries. Translates between featherChat Bot API and standard TG libraries (python-telegram-bot, aiogram, Telegraf). Handles differences like fingerprint-based chat_id, numeric ID translation, and webhook forwarding.

python tools/bot-bridge.py --token YOUR_BOT_TOKEN --server http://localhost:7700

Future Plans

  • File send/receive APIs -- sendDocument, getFile.
  • Group bot support -- bots in group chats with sender-key encryption.