Get API key

Uncensored Endpoint Telegram Bot: Build It in Python

To build an uncensored endpoint telegram bot you need three pieces: a bot token from BotFather, an API key, and about 80 lines of Python that pass each Telegram message to the chat completions route. This walkthrough gives the full code, then adds memory, streaming and limit handling.

Updated

Key points

  1. The bot uses python-telegram-bot for Telegram and the standard OpenAI SDK for the model.
  2. Keep a short history per chat and trim it so every request stays small and cheap.
  3. Stream by editing one message about once a second, not on every token.
  4. Cap parallel model calls at 8 with a semaphore and retry 429 responses.
Paper-plane chat bubble leaving a terminal toward a row of speech bubbles, representing a Telegram bot

What you are building

The bot has one job: take a text message from a Telegram chat, add it to that chat's history, send the history to the model uncensored, and post the answer back. Each Telegram chat gets its own memory, so two people talking to the bot never see each other's context.

The finished project is a single file with these parts:

  1. A client for the API, using the OpenAI SDK pointed at https://api.uncensoredendpoint.com/v1.
  2. A dictionary of chat histories, trimmed so it never grows without limit.
  3. A message handler that streams the answer by editing one Telegram message.
  4. A semaphore that keeps you under the 8 concurrent requests a full key allows.

Nothing here needs a database. When the bot restarts, the histories reset, which is fine for a first version. A later section covers where to add persistence.

Prerequisites

You need Python 3.10 or newer and two credentials.

  • A Telegram bot token. Open a chat with BotFather inside Telegram, send the command to create a new bot, pick a name and a username, and copy the token it returns. Treat the token like a password.
  • An API key. Sign up on the key page with Google or with email and password. New users can claim $0.50 of trial credit with one click, which is enough to test this bot many times. The trial key allows 2 concurrent requests and 60 requests per minute.

Install the two libraries and export the secrets as environment variables so they never land in your source code:

pip install "python-telegram-bot>=20" openai
export TELEGRAM_TOKEN="123456:your-bot-token"
export API_KEY="your-api-key"

If you later move from the trial to real traffic, credit comes from a crypto top-up of $20 to $500, either USDT on TRC20 or USDC on Base. The pricing page lists the bonus tiers.

A minimal working bot

Start with the smallest version that answers messages. It has no streaming and no trimming yet, so you can confirm the plumbing first.

import os
from collections import defaultdict

from openai import AsyncOpenAI
from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, MessageHandler, filters

client = AsyncOpenAI(
    base_url="https://api.uncensoredendpoint.com/v1",
    api_key=os.environ["API_KEY"],
    max_retries=3,
)

SYSTEM = "You are a friendly, direct assistant. Keep answers short unless asked for detail."
history = defaultdict(list)  # chat_id -> list of messages


async def on_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
    chat_id = update.effective_chat.id
    history[chat_id].append({"role": "user", "content": update.message.text})

    resp = await client.chat.completions.create(
        model="uncensored",
        messages=[{"role": "system", "content": SYSTEM}] + history[chat_id],
        temperature=0.8,
    )
    answer = resp.choices[0].message.content
    history[chat_id].append({"role": "assistant", "content": answer})
    await update.message.reply_text(answer[:4000])


app = ApplicationBuilder().token(os.environ["TELEGRAM_TOKEN"]).build()
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, on_text))
app.run_polling()

Run it, open your bot in Telegram, and say hello. The slice answer[:4000] exists because Telegram caps a single message at 4096 characters. A long model answer would otherwise make the send call fail. Later you can split long answers into several messages instead of cutting them.

The OpenAI SDK retries some failures on its own, including 429 responses, with a short backoff. Setting max_retries=3 gives you a little headroom without writing a retry loop yet.

Memory that does not grow forever

Chat completions are stateless. The model only knows what you send in each request, so the bot resends the history every turn. That is why unbounded history is the main cost and latency trap. The context window is 100,000 tokens, which is a lot, but you pay for every input token on every turn, and most chat bots do not need anywhere near that much.

A simple policy works well: keep the system prompt, and keep only the last N messages. Twenty messages, ten from the user and ten from the bot, suits casual chat.

MAX_MESSAGES = 20


def remember(chat_id, role, content):
    h = history[chat_id]
    h.append({"role": role, "content": content})
    if len(h) > MAX_MESSAGES:
        del h[: len(h) - MAX_MESSAGES]

Cutting at an arbitrary point can leave a history that starts with an assistant message. That is harmless for this model, but if you want it tidy, drop one more message when the first remaining one is not from the user.

For characters or long stories where the model must remember facts from early on, trimming loses them. Two common fixes are a pinned note and a rolling summary. A pinned note is a short block of facts you keep in the system prompt, such as names and the current scene. A rolling summary asks the model, every thirty messages or so, to compress the older half of the history into a paragraph, which you then store in place of those messages.

Add a /reset command that clears history[chat_id]. People like having a clean slate, and it costs you nothing.

Streaming the reply by editing one message

Waiting ten seconds for a long answer feels slow in a chat app. Streaming lets the reply grow on screen. Telegram does not accept a message token by token, so the trick is to send a placeholder, then edit it as text arrives. Edit about once a second at most. Telegram applies its own flood limits to bots, and hammering the edit call on every token gets you throttled and slows the stream.

import time


async def stream_answer(update, chat_id):
    msg = await update.message.reply_text("...")
    stream = await client.chat.completions.create(
        model="uncensored",
        messages=[{"role": "system", "content": SYSTEM}] + history[chat_id],
        stream=True,
    )
    text, last_edit = "", 0.0
    async for chunk in stream:
        if not chunk.choices:
            continue
        piece = chunk.choices[0].delta.content or ""
        text += piece
        if time.monotonic() - last_edit > 1.0 and text.strip():
            await msg.edit_text(text[:4000])
            last_edit = time.monotonic()
    if text.strip():
        await msg.edit_text(text[:4000])
    return text

Two details matter. First, always do a final edit after the loop, because the last chunks usually arrive between timed edits. Second, Telegram rejects an edit that does not change the text, so skip the call when nothing is new. The library raises an error for that case, and a try/except around the edit keeps the stream alive.

Remember that a streamed request holds its concurrency slot until the stream ends. A bot with many chats talking at once will hit the limit sooner with streaming than without, which leads to the next section.

Staying inside the rate limits

A full key allows 8 concurrent requests and 300 requests per minute. A trial key allows 2 and 60. A busy group chat can easily exceed 2 at once, so size your limit to the key you are using.

The cleanest guard is a semaphore around the model call. Requests beyond the cap wait in line inside your process instead of bouncing off the API:

import asyncio

slots = asyncio.Semaphore(8)  # use 2 with a trial key


async def on_text(update, context):
    chat_id = update.effective_chat.id
    remember(chat_id, "user", update.message.text)
    async with slots:
        text = await stream_answer(update, chat_id)
    remember(chat_id, "assistant", text)

If you still get an HTTP 429, read the error code. concurrency means too many calls at once, rate_limited means too many per minute, and a 429 with Retry-After: 5 means temporary overload; wait the five seconds. The SDK retry handles most of these. Failed or refused requests are not charged, so retries do not add to the bill.

One more guard is per-user pacing. If a single person sends ten messages in ten seconds, serialise their requests with a lock per chat so answers arrive in order and one chat cannot use all eight slots.

Persona, rules and group chats

The system prompt is where the bot gets its character. Write it like a short brief: who the bot is, how it speaks, how long answers should be, and anything it must not do. For a roleplay or companion bot for adults, describe the setting and tone in a few lines and let the user steer from there. Specific prompts beat long ones; the model follows a clear five-line persona better than a page of rules.

Some rules sit outside the prompt. The model answers without content refusals for lawful adult use, but sexual content involving minors is never allowed, and you should enforce that on your side too. If your bot is open to the public, say so in its description, add an age notice in the start message, and remember that Telegram has its own terms for bots that you also have to follow. Your users' conversations go to the API, and prompts are not used for training; tell your users what your own bot stores.

In group chats, do not answer every message. Respond only when the bot is mentioned or when someone replies to one of its messages, and ignore messages sent by other bots. In python-telegram-bot you can check update.message.entities for a mention or compare update.message.reply_to_message.from_user.id with the bot's own ID.

When something goes wrong, log the X-Request-Id response header for each call; you can read it through the SDK's raw response interface. The support page is the place to ask about a specific request.

Running it for real

Polling, as used above, is fine for a small bot: the process asks Telegram for new messages in a loop and needs no public address. Run it under systemd or a container with automatic restart, and keep the two secrets in the unit file's environment or a secrets store. A webhook setup lowers idle load, but it needs HTTPS and a public URL, so start with polling.

Estimate cost before you invite people. The API charges $0.15 per 1M input tokens and $0.50 per 1M output tokens. A typical turn with a trimmed history of 2,000 input tokens and 500 output tokens costs 2,000 x $0.15 / 1M = $0.0003 for input plus 500 x $0.50 / 1M = $0.00025 for output, which is $0.00055. A thousand turns cost $0.55. If a chat grows to 10,000 input tokens per turn, the input part alone becomes $0.0015, so trimming pays for itself quickly.

When you need persistence, store each chat's history as JSON in SQLite or Redis, load it on the first message after a restart, and write it back after each reply. Add a per-user daily message limit if the bot is public, so one enthusiastic user cannot drain the balance. The API docs list every parameter you can tune, and the key production checklist covers rotating keys and watching the balance header.

Questions and answers

Which library should I use for the Telegram side?

Any library works because the model side is a plain HTTP API. This guide uses python-telegram-bot version 20 or newer, which is asynchronous and pairs well with the async OpenAI client.

Why does my bot reply to itself or to everyone in a group?

In groups, restrict the handler to messages that mention the bot or reply to it, and ignore messages from bots. Otherwise every message in the group triggers a model call.

How much does a bot conversation cost?

A short exchange of 2,000 input tokens and 500 output tokens costs $0.00055, so a thousand of them cost $0.55. Long histories cost more because they are resent each turn.

Can the bot be used for adult roleplay?

The model is tuned to answer without content refusals for lawful adult use, and bots for fiction and companion chat are a typical case. Sexual content involving minors is never allowed, and Telegram has its own rules that you must follow.

Your key is one form away

Create an account, copy the key, change the base URL. That is the whole setup.

Get API keyRead the docs