A lightweight, modular, backend‑only billing engine built with FastAPI, SQLAlchemy, and a clean service‑layer architecture. It ingests usage events, aggregates them, prices them, and generates invoices — all without any frontend or dashboard.
This project is ideal for demonstrating backend engineering skills such as:
- API design
- Background job processing
- Database modeling
- Clean architecture
- Usage metering
- Invoice generation
- Scheduling and workers
Record usage events (e.g., API calls, storage, workflows)
Daily usage aggregation (group + sum raw events)
Pricing engine (simple per‑unit pricing, easily extendable)
Invoice preview (estimate charges before billing period ends)
Invoice generation (creates real invoice records)
Clean service layer (routers → services → models)
Background‑safe aggregation (manual or scheduled)
SQLite for simplicity (swap for Postgres easily)
billing_engine/
│
├── app/
│ ├── routers/
│ │ ├── usage.py
│ │ ├── invoice.py
│ │ └── aggregator.py
│ ├── services/
│ │ ├── usage_service.py
│ │ ├── invoice_service.py
│ │ └── aggregator_service.py
│ ├── models.py
| ├── aggregator.py
| ├── pricing.py
│ ├── schemas.py
│ ├── deps.py
│ └── database.py
│
├── tests.py/
| ├── conftest.py
| ├── test_aggregator.py
| ├── test_api.py
| ├── test_invoice.py
| ├── test_usage.py
├── scheduler.py
├── main.py
├── worker.py
└── README.md
└── LICENSE.md
└── CONTRIBUITING.md
python -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windowspip install -r requirements.txtOn Windows (WSL recommended):
redis-serverStart the FastAPI server
uvicorn main:app --reloadYour API is now live at:
http://127.0.0.1:8000
Swagger UI:
http://127.0.0.1:8000/docs
In a new terminal:
rq workerIn another terminal:
python scheduler.py- This triggers daily aggregation automatically.
-
Record usage
-
POST /usage
-
Example:
- json { "customer_id": "cust_123", "metric": "api_calls", "units": 500 }
POST /aggregate/run
- This groups + sums raw usage into daily totals.
GET /invoice/preview/{customer_id}
- Returns estimated charges for the current billing period.
POST /invoice/{customer_id}
- Creates an invoice record in the database.
Usage Ingestion Raw events are stored exactly as they happen:
-
customer
-
metric
-
units
-
timestamp
-
This keeps ingestion fast and append‑only.
A background job periodically:
fetches raw events
groups them by metric + customer
sums units
writes aggregated rows
This reduces billing load and keeps invoices fast.
A simple per‑unit pricing dictionary:
PRICING = {
"api_calls": 0.0005,
"storage_gb": 0.25,
"workflows": 0.10,
}
You can easily extend this to:
tiered pricing
free allowances
per‑customer overrides
Reads aggregated usage so far and returns:
usage totals
estimated amount
billing window
No DB writes.
Reads aggregated usage, calculates the final amount, and writes an invoice row.
-
FastAPI — API framework
-
SQLAlchemy — ORM + models
-
SQLite — local development DB
-
RQ (Redis Queue) — background worker
-
Redis — job queue backend
-
Uvicorn — ASGI server
-
UsageEvent Raw usage events.
-
AggregatedUsage Daily totals per metric.
-
Invoice Final billed amounts.