A Telegram Bot to track your expenses. This guide covers everything you need to self-host the bot using Docker or native Go.
-
Create a new bot using BotFather.
- Use
/newbotcommand to create a new bot. - Use
/setnamecommand to set a name for the bot. - Use
/setdescriptioncommand to set a description for the bot.
- Use
-
Set commands for the bot using
/setcommandscommand.new - Add new Wallet or Contact newtxn - Add new transaction undo - Undo last transaction contacts - List contacts balance - List Wallet Balances list - List recent transactions expense - Fetch Expense of Current month summary - Transaction summary of current month allsummary - Transaction summary based on Type, Category, Subcategory report - Transaction Report cat - List Transaction categories sync - Sync database to Google Drive help - Show Usage page -
Create a Token for the bot.
- Use
/tokencommand to get the bot token.
- Use
create-telegram-bot.mp4
By default, the application uses SQLite as its database, requiring no additional setup.
If you prefer to use PostgreSQL, follow these steps:
-
Install PostgreSQL using Homebrew:
brew update brew install postgresql brew services start postgresql
-
Create a superuser named
postgreswith passwordpostgres:psql postgres -c "CREATE USER postgres WITH SUPERUSER PASSWORD 'postgres';" -
Create a new database named
expense:psql -u postgres -c "CREATE DATABASE expense;"
If you want to back up your SQLite database to Google Drive regularly, follow these steps:
-
Create a Google Project (if not already created).
-
Create a Service account named
expense-trackerand download a service account JSON key. -
Enable the Google Drive API for your project.
-
On Google Drive:
- Create a folder named
.expense-tracker. - Share this folder with the service account (
expense-tracker@<project-id>.iam.gserviceaccount.com) and grant it "Editor" permission.
- Create a folder named
The application supports environment variable overrides for all sensitive configuration.
| Variable | Description |
|---|---|
TELEGRAM_BOT_TOKEN |
Bot token from @BotFather |
EXPENSE_BOT_TOKEN |
(Alternative) Overrides the Telegram secret in YAML |
Set these to enable AI-powered natural language processing. The bot will automatically prefer Gemini if its key is provided.
| Variable | Description |
|---|---|
GEMINI_API_KEY |
Google Gemini API key |
OPENROUTER_API_KEY |
OpenRouter API key |
These override the corresponding values in the YAML config file for production/Docker environments.
| Variable | Description |
|---|---|
EXPENSE_DB_PASS |
Database password (Postgres) |
EXPENSE_REDIS_PASS |
Redis password |
| Variable | Description |
|---|---|
ENV |
Set to production for JSON-structured logging and production Zap profile |
BASE_URL |
If set, the bot pings {BASE_URL}/healthz every 20 minutes to keep itself alive |
GOOGLE_APPLICATION_CREDENTIALS |
Path to Google service account JSON for Drive backup |
The bot reads its configuration from .configs/.expense-tracker.yaml (relative to the project root).
telegram:
user: <telegram_username>
database:
type: sqlite # or postgres
sqlite:
syncToDrive: false
disableSyncFromDrive: false
postgres:
name: expense
host: localhost
port: 5432
user: postgres
password: "" # Use EXPENSE_DB_PASS env var to override
sslmode: disable
cache:
type: map # or redis
redis:
host: localhost
port: "6379"
password: "" # Use EXPENSE_REDIS_PASS env var to override
system:
pdfGenerator: wkhtmltopdf # or chromedp
aiGenerator: gemini # or open-router-
Clone the repository:
git clone git@github.com:masudur-rahman/expense-tracker-bot.git cd expense-tracker-bot -
Update the configuration file
.configs/.expense-tracker.yaml. -
Export required environment variables:
export TELEGRAM_BOT_TOKEN=<TELEGRAM_BOT_TOKEN> export GEMINI_API_KEY=<YOUR_GEMINI_API_KEY>
-
Run the server:
make run
The Docker image supports both wkhtmltopdf and chromedp engines and is built for both AMD64 and ARM64 (Apple Silicon).
-
Write configuration file
mkdir -p $HOME/.expense-tracker/configs echo ' telegram: user: <telegram_username> database: type: sqlite cache: type: map ' > $HOME/.expense-tracker/configs/.expense-tracker.yaml
-
Run Expense Tracker Bot
docker run -d \ --name expense-tracker \ -v $HOME/.expense-tracker/configs:/app/.configs \ -v $HOME/.expense-tracker:/.expense-tracker \ -e TELEGRAM_BOT_TOKEN=<TELEGRAM_BOT_TOKEN> \ -e GEMINI_API_KEY=<GEMINI_API_KEY> \ -e ENV=production \ ghcr.io/masudur-rahman/expense-tracker-bot:latest serve
To deploy Expense Tracker Bot application in production environment, the preferred way is through Helm Chart. Checkout more here.
- First you need to add the repo for the helm chart.
helm repo add masud https://masudur-rahman.github.io/helm-charts/stable helm repo update helm search repo masud/expense-tracker-bot
- Install the chart
- For installing just with SQLite database (without Google Drive backup)
helm upgrade --install expense-tracker-bot masud/expense-tracker-bot -n demo \ --create-namespace \ --set telegram.token=<TELEGRAM_BOT_TOKEN> \ --set telegram.user=<TELEGRAM_USERNAME> - SQLite with Google Drive backup
helm upgrade --install expense-tracker-bot masud/expense-tracker-bot -n demo \ --create-namespace \ --set telegram.token=<TELEGRAM_BOT_TOKEN> \ --set telegram.user=<TELEGRAM_USERNAME> \ --set database.sqlite.syncToDrive=true \ --set-file googleCredJson=<GOOGLE-SVC-ACCOUNT-JSON-FILEPATH> - Postgres database
helm upgrade --install expense-tracker-bot masud/expense-tracker-bot -n demo \ --create-namespace \ --set telegram.token=<TELEGRAM_BOT_TOKEN> \ --set telegram.user=<TELEGRAM_USERNAME> \ --set database.type=postgres \ --set database.deploy=true # set to false if you want to use external database # --set database.postgres.user=<POSTGRES_USER> \ # --set database.postgres.password=<POSTGRES_PASSWORD> \ # --set database.postgres.db=<POSTGRES_DB> \ # --set database.postgres.host=<POSTGRES_HOST> \ # --set database.postgres.port=<POSTGRES_PORT> \ # --set database.postgres.sslmode=<POSTGRES_SSL_MODE>
- For installing just with SQLite database (without Google Drive backup)
- Install the chart
- Verify Installation
To check if
Expense Tracker Botis installed, run the following command:$ kubectl get pods -n demo -l "app.kubernetes.io/instance=expense-tracker-bot" NAME READY STATUS RESTARTS AGE expense-tracker-bot-7989d96fcc-b4smq 1/1 Running 2 (30s ago) 31s expense-tracker-bot-postgres-55dcb67965-95r7g 1/1 Running 0 31s
The bot exposes a health check endpoint:
- Endpoint:
GET /healthzon port8080 - Response: JSON with database connectivity status
- Docker: The Docker image includes a built-in
HEALTHCHECKdirective
If BASE_URL is set, the bot will ping {BASE_URL}/healthz every 20 minutes as a keep-alive mechanism.