A Telegram bot that tracks shared expenses in group chats. Record who paid for what, see who owes whom, and settle debts — all within your Telegram group.
@split_bot keeps a running tab for your group:
- Someone pays for something and records it with
/split. - The bot tracks who owes whom across all splits.
/tabshows net balances — mutual debts cancel automatically./settlerecords payments to clear debts.
It runs in Telegram groups only. If you PM the bot, it will explain that it needs to be added to a group.
Add @split_bot to a group chat.
Each participant sends once:
/register
When you pay for something, record who owes what:
/split dinner
- @ernest $14
- @kenneth $14
You (the sender) are the payer by default. To specify someone else:
/split dinner paid by @justin
- @ernest $14
- @kenneth $14
/tab
Example output:
💰 Group Tab
━━━━━━━━━━━━
Kenneth owes Justin — $14
Kenneth owes Ernest — $14
Total outstanding: $28
Clear your full debt with someone:
/settle @ernest
Or record a partial payment:
/settle @ernest $10
| Command | What it does |
|---|---|
/register |
Join the group |
/split |
Record a shared expense |
/tab |
Show who owes whom (net balances) |
/tab history |
Show recent split/settle transactions |
/settle @name |
Clear your full debt with someone |
/settle @name $10 |
Record a partial payment |
/remove @name |
Remove a participant |
/help |
Show commands and examples |
Balances are cumulative and net. Every /split and /settle adds to the ledger, and /tab always shows the current net across all transactions.
Example:
- Justin pays for lunch: Ernest owes Justin $14, Kenneth owes Justin $14
- Ernest pays for dinner: Justin owes Ernest $14, Kenneth owes Ernest $14
/tabnow shows: Justin and Ernest are even. Kenneth owes Justin $14, Kenneth owes Ernest $14.
Mutual debts cancel automatically — no manual netting needed.
- Python 3.11+
- A Telegram bot token from @BotFather
- A publicly reachable URL for the webhook
pip install -e ".[dev]"
cp .env.example .env # fill in TELEGRAM_BOT_TOKEN, WEBHOOK_SECRET, PUBLIC_BASE_URL
uvicorn app.main:app --host 0.0.0.0 --port 8080cp .env.example .env # fill in secrets
docker compose up --buildThe bot serves on host port 8789.
pytest # all tests
pytest -k split # split-specific
pytest -k settle # settle-specific| Variable | Description | Default |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Bot token from BotFather | (required) |
WEBHOOK_SECRET |
Secret for webhook verification | (required) |
PUBLIC_BASE_URL |
Public URL where the bot is reachable | https://split.yourdomain.com |
DATABASE_PATH |
SQLite database file path | /data/split.sqlite3 |
TIMEZONE |
Timezone for timestamps | Asia/Singapore |
The bot auto-registers its webhook with Telegram on startup using PUBLIC_BASE_URL.