NormaHub knowledge base

Telegram bot on the AI API

The backend holds the key, NormaHub answers messages: architecture, dialog history, budget limits, and error handling.

1. Architecture: the key lives on the backend only

The rule everything else follows: the secret key lives on your server and nowhere else. The Telegram client sends text to your backend (webhook or polling), the backend attaches the key and calls NormaHub, the answer goes to the user. The client, the mini app, and logs never see the key.

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["NORMAHUB_API_KEY"],  # backend only!
    base_url="https://api.normahub.cc/v1",
)

def answer(text: str) -> str:
    result = client.chat.completions.create(
        model="MODEL_ID",
        messages=[
            {"role": "system", "content": "Answer briefly."},
            {"role": "user", "content": text[:2000]},
        ],
        max_tokens=256,
    )
    return result.choices[0].message.content or ""

Trim the input (text[:2000]) and cap the output (max_tokens=256): without these two lines, a single “tell me a long joke” from a user costs as much as a hundred ordinary replies. Create the key in the dashboard separately for the bot, with its own spend limit. Russian version of this guide: Telegram-бот на AI API.

2. Dialog history

The model remembers no past messages: memory is your job. Keep a sliding window of the last 5–6 messages per user and send it in messages together with the system prompt. Never send the whole log: every message would cost as much as the entire conversation so far; the math is in the token cost guide.

# Per-user history: last 6 messages, never the whole log
# Storage: in-memory dict for MVP, Redis/Postgres for production
history: dict[int, list] = {}

def push(user_id: int, role: str, text: str) -> None:
    history.setdefault(user_id, []).append({"role": role, "content": text})
    history[user_id] = history[user_id][-6:]  # sliding window

An in-memory dict is enough for an MVP; production wants Redis or Postgres with TTL. The system prompt sets language, length, and tone: the sharper the format, the fewer tokens spent on clarifications.

3. Protecting the budget

A public bot is an open wallet — cover it with three layers. First: a rate limit in code (N messages per minute per user, captcha or allowlist for expensive commands). Second: a spend limit on the API key in the dashboard — the emergency brake under attack. Third: max_tokens and input trimming on every call. Watch charges daily during the first week: anomalies show immediately.

Split models by command: a cheap one answers in DMs, a strong one only on an explicit command or for admins. Every model's input and output prices are in the catalog.

4. Errors and UX

Never show users a traceback: map errors to human answers. 402 — “service balance refilling, come back later” plus an alert to you; 429/503 — “model overloaded, retry in a minute” with a single retry button; 401/403 — to your log only, users cannot fix those. Write each call's request ID to the log next to user_id — support will find the operation without your key.

Handle slow answers in stages: an instant “Thinking…” first, then editMessageText with the result. The full code table and retry policies are in the errors guide. The architecture overview is on the Telegram bot solutions page.

Частые вопросы

Where should I store the Telegram bot's API key?

Only on the backend server, in environment variables. Never embed the key in the Telegram client, mini app, frontend, or a public repository: it will be extracted and your balance spent.

Which model should I pick for the bot?

A fast, cheap one for dialogs (short answers, max_tokens 256–512), a strong one for select heavy commands. Exact IDs and prices are in the models catalog.

A user is spamming the bot. What protects the budget?

Three layers: a per-user rate limit in code, a spend limit on the API key in the dashboard, and max_tokens on every call. One layer without the others is half a measure.

The bot answers slowly. What helps?

First reply with an interim message (“Thinking…”), then edit it with the answer. Long requests hit Telegram timeouts — keep max_tokens reasonable and set a client timeout.

Does a server need a VPN?

No. The backend reaches https://api.normahub.cc/v1 directly, and billing comes from your dashboard balance.