Self-hosted Stripe billing anomaly detector โ catch duplicate charges, fraud spikes, and silent lapses in real time.
Project description
๐ 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file billingwatch-1.0.0.tar.gz.
File metadata
- Download URL: billingwatch-1.0.0.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
667870064a7ab3c48789af4902b580a70c30b5ccc566ef59e593d354ed71bc00
|
|
| MD5 |
ef8caa3dd134d99e96bdf5792e5edc23
|
|
| BLAKE2b-256 |
5c8e7075feededb9f593d59e4ca958936ce512b9dba92c17abeae0d87e6b626b
|
File details
Details for the file billingwatch-1.0.0-py3-none-any.whl.
File metadata
- Download URL: billingwatch-1.0.0-py3-none-any.whl
- Upload date:
- Size: 9.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
43cb34575b5673d481df3e8a41c9f861fcbb26a6d7e681f21af2fa747da416cc
|
|
| MD5 |
4f1e0aa0707189d4e3be0a23d7be18cb
|
|
| BLAKE2b-256 |
72e1ad321662a95d44bae406f68ee607382da7a572569857af551a234303a1aa
|