π BillingWatch
April 4, 2026 Β· View on GitHub
π BillingWatch β Self-Hosted Stripe Billing Anomaly Detector
Catch billing bugs, dunning failures, and fraud before they hit your churn metrics β entirely on your own machine.
BillingWatch listens to your Stripe webhook stream and runs 7 real-time anomaly detectors against every event. Duplicate charges, revenue drops, fraud spikes, silent subscription lapses β detected and alerted in seconds. No cloud subscription. No SaaS fees. No data leaving your server.
π€ Who Is This For?
- SaaS founders who want billing QA without paying for another tool
- Indie developers using Stripe who've been burned by silent billing failures
- Privacy-conscious teams who don't want their revenue data on someone else's server
- DevOps engineers who need webhook observability without a full APM stack
β¨ What It Detects
| Detector | What It Catches | Severity |
|---|---|---|
charge_failure_spike | Failure rate > 15% over 1 hour β gateway issue or card BIN attack | π΄ High |
duplicate_charge | Same customer charged twice within 5 min β idempotency bug | π¨ Critical |
fraud_spike | Dispute/chargeback rate exceeds threshold β active fraud campaign | π¨ Critical |
negative_invoice | Invoice total < 0 β broken promo stacking or discount bug | π‘ Medium |
revenue_drop | MRR > 15% below 7-day rolling average β silent churn or billing break | π΄ High |
silent_lapse | Active subscription with no successful payment in period | π‘ Medium |
webhook_lag | Events arriving > 10 min late β Stripe delivery degradation | π’ Low |
When a detector fires, BillingWatch sends alerts via email and/or outbound webhook.
π Why Not Just Use [Datadog / Baremetrics / Stripe Radar]?
| BillingWatch | Datadog | Baremetrics | Stripe Radar | |
|---|---|---|---|---|
| Cost | Free (self-hosted) | 5+/mo | 29+/mo | Built-in (limited) |
| Your data leaves your server? | β Never | β Yes | β Yes | β Yes |
| Custom anomaly logic | β Full control | Partial | β | β |
| Stripe-specific detectors | β 7 built-in | β General | β Metrics only | β Fraud only |
| Self-hostable | β Yes | β | β | β |
| Alert destinations | Email + webhook | Many | Dashboard only |
BillingWatch is for makers who want billing QA (not analytics) with zero SaaS lock-in.
π Quick Start
β‘ One-Click Deploy on Railway
No local setup required. Railway will prompt for your STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET on deploy.
βοΈ One-Click Deploy on Render
Free tier available. Render will read render.yaml automatically and prompt for env vars on first deploy.
Requirements
- Python 3.9+
- A Stripe account (test mode is fine)
- Stripe CLI (optional β for local webhook forwarding)
Install
git clone https://github.com/rmbell09-lang/BillingWatch.git
cd BillingWatch
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Configure
cp .env.example .env
Minimum config for local dev:
STRIPE_SECRET_KEY=sk_test_PLACEHOLDER
STRIPE_WEBHOOK_SECRET=dev
APP_ENV=development
LOG_LEVEL=DEBUG
PORT=8000
Note:
STRIPE_WEBHOOK_SECRET=devbypasses signature verification. Never use in production.
Run
source .venv/bin/activate
STRIPE_WEBHOOK_SECRET=dev uvicorn src.api.main:app --reload --port 8000
Verify
curl http://localhost:8000/health
# {"status": "ok"}
curl http://localhost:8000/webhooks/detectors
# Lists all 7 registered detectors
Send a Test Event
curl -s -X POST localhost:8000/webhooks/stripe \
-H 'Content-Type: application/json' \
-H 'Stripe-Signature: dev' \
-d '{
"id": "evt_test_001",
"type": "charge.failed",
"created": 1709599200,
"data": {"object": {"id": "ch_001", "customer": "cus_001", "amount": 2999}}
}'
Or with Stripe CLI for real test events:
stripe listen --forward-to localhost:8000/webhooks/stripe
stripe trigger charge.failed
π‘ API Reference
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Health check |
/docs | GET | Interactive Swagger UI |
/webhooks/stripe | POST | Stripe event ingestion |
/webhooks/alerts | GET | Recent anomaly alerts |
/webhooks/detectors | GET | Registered detectors list |
/metrics | GET | total_events, events_by_type, uptime_seconds, detector_count |
/metrics?window_hours=N | GET | Rolling window metrics (0.1β168h) |
/metrics/detectors | GET | Per-detector alert counts + severity |
/metrics/recent-events | GET | Most recent webhook events |
ποΈ Architecture
Stripe Webhooks
β
βΌ
FastAPI (port 8000)
β
ββββ Signature Validation (Stripe-Signature header)
β
ββββ Event Store (SQLite / PostgreSQL)
β
ββββ Detector Pipeline (parallel evaluation)
β
ββββ charge_failure_spike
ββββ duplicate_charge
ββββ fraud_spike
ββββ negative_invoice
ββββ revenue_drop
ββββ silent_lapse
ββββ webhook_lag
β
βΌ
Alert Dispatch
ββββ Email (SMTP)
ββββ Outbound Webhook
Stack: Python 3.9+ Β· FastAPI Β· SQLite (dev) / PostgreSQL (prod) Β· Redis Β· APScheduler Β· Stripe SDK
π§ͺ Running Tests
source .venv/bin/activate
pytest tests/ -v
# Detector unit tests only
pytest tests/test_detectors/ -v
# With coverage
pytest tests/ --cov=src --cov-report=term-missing
π§ Adding a Custom Detector
Extend BaseDetector from src/detectors/base.py:
from .base import Alert, BaseDetector
class MyDetector(BaseDetector):
name = "my_detector"
def process_event(self, event: dict):
if event.get("type") == "some.stripe.event":
return [Alert(
detector=self.name,
severity="medium",
title="Something happened",
message="Details here"
)]
return []
Register it in src/api/main.py startup. Done.
π Production Deployment
See docs/production-setup.md for:
- Stripe live key setup via macOS Keychain
- Cloudflare Tunnel for webhook exposure (no open ports)
- PostgreSQL + Redis configuration
- Pre-launch security checklist
Never put live Stripe keys in .env files. Use Keychain or a secrets manager.
π Project Structure
BillingWatch/
βββ src/
β βββ api/ # FastAPI app + routes
β βββ detectors/ # 7 anomaly detectors + BaseDetector
β βββ storage/ # SQLite/Postgres event persistence
β βββ workers/ # Async processing + APScheduler
β βββ alerting/ # Email + webhook alert delivery
β βββ models/ # SQLAlchemy models + Pydantic schemas
β βββ stripe_client.py # Stripe SDK wrapper
βββ tests/ # Unit + E2E tests
βββ docs/ # Setup guides + spec
βββ Dockerfile
βββ docker-compose.yml
βββ README.md
πΊοΈ Roadmap
v1.1 (In Progress)
- π§ Email Digest β daily/weekly anomaly summary (endpoint live, SMTP config needed)
- βοΈ Render.com 1-Click Deploy β
render.yaml+ deploy button β - π Webhook Event Explorer UI β searchable, filterable event log
v1.2 (Planned)
- π Grafana Dashboard β pre-built anomaly trend dashboard
- π Slack/Discord Alerts β native integrations
- π§ͺ Test Mode Replay β replay historical events without live webhooks
π Related Projects & Alternatives
BillingWatch fills the gap between expensive SaaS platforms and doing nothing:
| Tool | Type | Cost | Why BillingWatch Instead |
|---|---|---|---|
| Datadog | Full observability | $5+/mo | General-purpose APM, no Stripe-specific detectors |
| Baremetrics | SaaS analytics | $29+/mo | Analytics dashboards, not real-time anomaly alerts |
| Stripe Radar | Fraud detection | Built-in | Card fraud only β no dunning failures, duplicate charges, or webhook lag |
| Sentry | Error monitoring | $26+/mo | Code errors, not billing events |
| ChartMogul | Revenue analytics | $100+/mo | Historical charts, not real-time detection |
| Lago | Open-source billing | Self-hosted | Full billing system β BillingWatch monitors Stripe, not replaces it |
BillingWatch is free, self-hosted, and purpose-built for Stripe billing QA. One webhook endpoint. Seven detectors. Zero SaaS fees.
Also useful for: stripe monitoring Β· stripe webhook monitoring Β· billing anomaly detection Β· SaaS billing monitoring Β· self-hosted stripe monitor Β· payment failure alerts Β· subscription billing QA Β· chargeback detection Β· dunning failure detection Β· webhook observability Β· fastapi stripe webhooks
π οΈ More Dev Tools
Built by the same maker β if you're interested in algorithmic trading:
TradeSight β AI Paper Trading Strategy Lab β β Python trading bot with overnight strategy tournaments, RSI confluence, and Alpaca integration.
License
MIT β see LICENSE
Built by an indie maker who got burned by a silent dunning failure. Stripe is great β but it doesn't tell you when things go wrong until it's too late.