Open-source web app for splitting restaurant bills in real time. Upload a receipt, extract line items with OCR, share a link/QR with the group, and let each participant claim items and mark their share as paid.
- Receipt OCR for JPEG/PNG uploads using Google Gemini.
- Shared ticket URLs valid for short-lived group sessions.
- Real-time updates with WebSockets plus Redis pub/sub for multi-worker deployments.
- Item claiming, item sharing, manual item editing/deletion and cent-level rounding.
- Tip calculation and per-person payment tracking.
- Browser-local ticket history and reusable participant groups.
- Multilingual UI: Spanish, English, Portuguese and Catalan.
This repository is designed to be safe to publish as OSS:
- No real API keys, database passwords or admin secrets are committed.
SECRET_KEYhas no application default; admin cleanup is disabled until configured.- Production mode validates strong secrets, explicit trusted hosts and non-wildcard CORS.
- Uploads are restricted to JPEG/PNG and size-limited with
MAX_UPLOAD_BYTES(default 5 MiB). - OCR calls use the uploaded file MIME type and run off the FastAPI event loop.
- User-controlled names in delete confirmations are rendered as text, not HTML.
Anyone with a ticket URL can collaboratively edit that ticket. Treat ticket links as bearer links and do not use the app for sensitive financial records.
- Python 3.12+
- PostgreSQL
- Redis
- Google Gemini API key for OCR (
GEMINI_API_KEY)
git clone https://github.com/ablott976/splitbill-oss.git
cd splitbill-oss
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# edit .env and set SECRET_KEY / database / Redis / optional GEMINI_API_KEY
uvicorn app.main:app --reloadOpen http://localhost:8000.
Generate a local secret with:
openssl rand -base64 32cp .env.example .env
# edit SECRET_KEY and POSTGRES_PASSWORD
cd docker
docker compose up --buildHealth check:
curl http://localhost:8000/healthENVIRONMENT:developmentorproduction.DATABASE_URL: async SQLAlchemy PostgreSQL URL.REDIS_URL: Redis URL for pub/sub.SECRET_KEY: admin cleanup secret; required for cleanup and validated in production.GEMINI_API_KEY: optional at startup, required for OCR.ALLOWED_ORIGINS: comma-separated CORS origins. Wildcard is rejected in production.TRUSTED_HOSTS: comma-separated hostnames accepted by TrustedHostMiddleware. Wildcard is rejected in production.MAX_UPLOAD_BYTES: upload limit in bytes, default 5 MiB.
pip install -r requirements.txt
pytest -qPOST /api/tickets— create a ticket.GET /api/tickets/{token}— fetch current ticket state.POST /api/tickets/{token}/image— upload receipt image for OCR.POST /api/tickets/{token}/upload— HTMX upload endpoint.PATCH /api/tickets/{token}/tip— update tip percentage.POST /api/tickets/{token}/items— add an item.PUT /api/tickets/{token}/items/{item_id}— edit an item.DELETE /api/tickets/{token}/items/{item_id}— delete an item.POST /api/admin/cleanup— cleanup expired tickets, protected byX-Secret-Key.GET /health— health check.WS /ws/{token}— real-time ticket updates.
MIT