Skip to main content

Documentation Index

Fetch the complete documentation index at: https://vaquill.ai/docs/llms.txt

Use this file to discover all available pages before exploring further.

A Telegram bot that answers legal questions via the Vaquill /ask API, renders markdown tables as PNG images, and surfaces case-law sources as tappable inline-keyboard buttons. Source code at github.com/Vaquill-AI/integrations/telegram-bot.

Features

  • Per-chat conversation history (last N exchanges, configurable)
  • Markdown tables rendered as styled PNG images using Pillow
  • Source citations shown inline and as inline-keyboard buttons that open PDFs
  • Telegram HTML sanitisation with plain-text fallback
  • Automatic chunking of long answers (4096-char limit)
  • Per-user rate limits (per-minute and per-day)
  • Optional user ID allowlist

Prerequisites

RequirementWhere to get it
Python 3.10+python.org
Telegram accounttelegram.org
Telegram Bot Token@BotFather
Vaquill API keyapp.vaquill.ai - Settings > API Keys. See Authentication.

Platform setup

1

Open BotFather

Search for @BotFather in Telegram (or open t.me/botfather) and press Start.
2

Create the bot

Send /newbot. Provide a display name (e.g. Vaquill Legal AI), then a username ending in bot (e.g. vaquill_legal_bot). BotFather replies with your API token - copy it as TELEGRAM_BOT_TOKEN.
3

Register slash commands (optional)

Send /setcommands, choose your bot, and paste:
start - Start a new conversation
help - Show help information
examples - Show example questions
stats - View your usage statistics
clear - Clear conversation history
The bot also sets these on startup, but doing it manually makes them appear before the first run.
4

Description and avatar (optional)

/setdescription and /setabouttext set the text shown on the bot’s profile. /setuserpic sets the avatar (use a square image at least 512x512).

Quickstart

Local development uses polling mode - no public URL or HTTPS certificate required.
1

Clone and install

git clone https://github.com/Vaquill-AI/integrations.git
cd integrations/telegram-bot
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
2

Configure

cp .env.example .env
Fill in the two required values:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
VAQUILL_API_KEY=vq_key_your-api-key
VAQUILL_COUNTRY_CODE=US
3

Run

python bot.py
Look for INFO - Vaquill Telegram bot starting (mode=standard). Open Telegram, search your bot by username, tap Start, and ask:
What does FRCP Rule 12(b)(6) require for a motion to dismiss?
Create a separate test bot via BotFather for development so you do not disturb production users. Each token can only be polled by one process at a time.

Polling vs webhook

ModeBest forPublic URL?How to enable
PollingLocal dev, single instanceNoDefault - just run python bot.py
WebhookProduction, multi-instanceYes (HTTPS)Add an HTTP server and call Telegram’s setWebhook
To switch to webhook mode, deploy behind HTTPS and register:
curl -X POST "https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-domain.example.com/webhook"}'
Verify with getWebhookInfo. Switch back to polling any time with deleteWebhook.

Configuration

Top env vars. Full list in the repo .env.example.
VariableRequiredDefaultDescription
TELEGRAM_BOT_TOKENYes-Token from @BotFather
VAQUILL_API_KEYYes-Vaquill API key (vq_key_...)
VAQUILL_API_URLNohttps://api.vaquill.ai/api/v1API base URL
VAQUILL_MODENostandardstandard or deep
VAQUILL_COUNTRY_CODENo-Jurisdiction filter, e.g. US
RATE_LIMIT_PER_USER_PER_DAYNo100Per-user daily limit
RATE_LIMIT_PER_USER_PER_MINUTENo5Per-user minute limit
ALLOWED_USERSNo-Comma-separated Telegram user IDs (empty = open)
MAX_CONVERSATION_HISTORYNo10Exchange pairs kept in chat history
MAX_SOURCES_PER_RESPONSENo5Max source cards per reply
LOG_LEVELNoINFODEBUG, INFO, WARNING, ERROR
To find your own Telegram user ID, message @userinfobot.

Commands

CommandDescription
/startWelcome message with category buttons; clears conversation history
/helpShow available commands and tips
/examplesBrowse example questions by category as inline buttons
/statsShow messages used today, daily remaining, per-minute limit
/clearWipe conversation history for the current chat
Any non-command message is treated as a legal question.

Deployment

Docker

The included Dockerfile uses python:3.11-slim and installs DejaVu fonts for table-image rendering.
docker build -t vaquill-telegram-bot .
docker run --env-file .env vaquill-telegram-bot
Or with Compose:
services:
  telegram-bot:
    build: .
    env_file: .env
    restart: unless-stopped

Cloud hosts

Render

Deploy as a Background Worker (not Web Service) - polling does not need an HTTP port. render.yaml is included in the repo.

Railway

railway init && railway up. Add TELEGRAM_BOT_TOKEN and VAQUILL_API_KEY in the Variables tab.

VPS + systemd

Plain systemd unit with Restart=always. No reverse proxy needed.

Fly.io

fly launch, fly secrets set ..., fly deploy.
Example render.yaml:
services:
  - type: worker
    name: vaquill-telegram-bot
    runtime: python
    buildCommand: pip install -r requirements.txt
    startCommand: python bot.py
    envVars:
      - key: TELEGRAM_BOT_TOKEN
        sync: false
      - key: VAQUILL_API_KEY
        sync: false
      - key: VAQUILL_COUNTRY_CODE
        value: US

Troubleshooting

SymptomFix
Bot does not respondConfirm the process is running, the token is correct, and only one process is polling that token.
”Unauthorized” / 401 from VaquillVAQUILL_API_KEY is invalid or expired. Generate a new one.
”Insufficient credits” / 402Top up at app.vaquill.ai.
Rate limit immediatelyYou hit the per-minute cap. Wait 60 seconds or raise RATE_LIMIT_PER_USER_PER_MINUTE.
Tables render as text, not imagesPillow or fonts missing. In Docker the bot installs fonts-dejavu-core automatically; on macOS it falls back to Helvetica or the Pillow default.
HTML parse errors in TelegramThe bot catches BadRequest and falls back to plain text. No action needed unless it happens on every message.
Webhook set but no repliesCheck getWebhookInfo for pending_update_count. If growing, the endpoint is unreachable. Delete the webhook to go back to polling.

WhatsApp

Twilio-based, comparable consumer-messenger surface.

Signal

Privacy-focused alternative.

Chatbots overview

Compare all six platforms.

Authentication

How Vaquill API keys work.