Stripemeter
Stripe-native usage metering with real-time cost projections, exactly-once processing, and invoice parity guarantees.
Install / Use
/learn @geminimir/StripemeterREADME
StripeMeter — pre-invoice parity for Stripe usage billing
v0.4.0: Production-readiness pack
See v0.4.0 Release Notes and Operator Runbook.
Open in Codespaces · 5-min Quickstart · Run the Parity Demo · Try the Stripe Test Clocks Demo
What’s new in v0.4.0
- End-of-cycle parity demo (Stripe Test Clocks)
- Replay API —
POST /v1/replaywith dry-run/apply; watermark/cursor semantics - Shadow Mode — test-environment pushes with deterministic idempotency keys
- /metrics + Prometheus + Grafana dashboard
- ALERTS.md + RECONCILIATION.md runbook
Try in 5 minutes → Verify in 30 seconds
git clone https://github.com/geminimir/stripemeter && cd stripemeter
cp .env.example .env && docker compose up -d && pnpm -r build
pnpm db:migrate && pnpm dev
curl -fsS http://localhost:3000/health/ready | jq . || true
TENANT_ID=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid) bash examples/api-calls/send.sh
curl -fsS http://localhost:3000/metrics | head -n 30 # duplicate counted once
What StripeMeter isn't
- Not a pricing or entitlement layer (use a pricing stack like Autumn; StripeMeter ensures usage numbers are correct).
- Not a data warehouse.
- Throughput targets: laptop p95 ingest ≤ 25 ms, late-event replay (10k) ≤ 2 s. Scale with queue/workers for higher volumes.
What it is
A small service you run next to your app: it dedupes retries, handles late events with watermarks, keeps running counters, and pushes only the delta to Stripe so totals stay correct. A reconciliation loop + metrics catch drift before invoice close.
Who it’s for
- SaaS teams on Stripe usage-based pricing
- Engineers who need correct usage totals and early drift detection
What it is / isn’t
It is
- A metering pipeline: ingest → dedupe → aggregate → reconcile
- A correctness guard for Stripe usage billing (no surprise invoices)
- Operator-ready:
/health,/metrics, drift tolerance, runbooks
It isn’t
- A payment processor or replacement for Stripe Billing
- A pricing engine/UI (those are optional extras; core is correctness)
Quickstart
(Optional preflight: bash scripts/preflight.sh)
pnpm i -w
cp .env.example .env
docker compose up -d
pnpm -r build
pnpm db:migrate
pnpm dev
After services are up:
- Readiness:
GET http://localhost:3000/health/ready - Metrics:
GET http://localhost:3000/metrics - List events:
curl -s "http://localhost:3000/v1/events?tenantId=your-tenant-id&limit=10" | jq
Verify it worked (30-sec demo)
# 1) Health (should be healthy or degraded)
curl -fsS http://localhost:3000/health/ready | jq . || true
# 2) Idempotency demo: send the SAME event twice (counts once)
# TENANT_ID will be generated if unset
TENANT_ID=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid) bash examples/api-calls/send.sh
# 3) Check metrics (should reflect one accepted ingest)
curl -fsS http://localhost:3000/metrics | head -n 30
If this clarified drift/idempotency, please ⭐ the repo and open an issue with what you tried — it guides the roadmap.
Micro-proof numbers (optional quick check)
- p95 ingest latency: ~10–25 ms
- Re-aggregation of 10k late events: ≤ 2 s
- Duplicate events inside 24 h idempotency window: 0 double-counts
Production checklist
- [x] Exact-once effect: idempotency window (duplicates won’t double-count)
- [x] Late events handled via watermarks + re-aggregation
- [x] Delta writes to Stripe (no over-reporting)
- [x] Health endpoints + structured logs +
/metrics - [x] Prometheus scrape + Grafana dashboard + alert recipes
- [x] Replay via API for safe reprocessing
- [x] Shadow Mode for safe test pushes
- [x] Triage & repair runbook with copy-paste commands
Reproduce locally:
# p95 for POST /v1/events/ingest (100 concurrent for 30s)
npx autocannon -m POST -H 'content-type: application/json' \
-b '{"events":[{"tenantId":"your-tenant-id","metric":"api_calls","customerRef":"c1","quantity":1,"ts":"2025-01-01T00:00:00Z"}]}' \
http://localhost:3000/v1/events/ingest
# Spot-check metrics after a short send
curl -s http://localhost:3000/metrics | grep -E "http_request_duration|process_" || true
Configure metrics (optional)
Put a tiny config in examples/config/stripemeter.config.ts to map metric → counter and choose a watermarkWindowSeconds.
Shadow Mode
Shadow Mode lets you post usage to Stripe’s test environment in parallel without affecting live invoices.
- Set
STRIPE_TEST_SECRET_KEYin your environment (in addition toSTRIPE_SECRET_KEY). - Mark a price mapping with
shadow=trueand provideshadowStripeAccount,shadowPriceId, and optionallyshadowSubscriptionItemId. - The writer routes these to the Stripe test client and uses deterministic idempotency keys.
- Live invoices remain unaffected; live write logs are not updated for shadow pushes.
- Metrics:
shadow_usage_posts_total,shadow_usage_post_failures_total. - Guardrails: if
shadow=truebutSTRIPE_TEST_SECRET_KEYis missing, pushes are skipped with warnings.
Pick your case (examples)
- API calls:
bash examples/api-calls/verify.sh - Seats:
bash examples/seats/verify.sh
Each script checks health, sends a duplicate event with an explicit idempotency key, and prints the first lines of /metrics so you can see it counted once.
StripeMeter is a Stripe-native usage metering system focused on correctness and operability. Built by developers who believe customers should be able to verify what they’re billed for.
Why StripeMeter?
- Correct usage totals via idempotent ingest and late-event handling
- Pre-invoice parity within ε, monitored by alerts; see the runbook
- Fresh counters and delta pushes to Stripe to avoid over-reporting
- Operator-grade: health, metrics, dashboards, and alert recipes
What Makes StripeMeter Special
Unlike other billing solutions, StripeMeter is designed around three core principles:
- Transparency First: Customers should never be surprised by their bill
- Developer Experience: Building usage-based pricing should be delightful
- Community Driven: Built by the community, for the community
Adopters wanted (2 slots this week).
If you run Stripe usage-based pricing, I’ll pair for 30 minutes to wire one meter in staging or set up a nightly replay. You’ll get priority on your must-have knobs and a thank-you in the next release notes.
→ Open a discussion: “Staging adopter” or DM via the repo email.
Architecture
┌─────────────┐ ┌──────────┐ ┌──────────────┐
│ Clients │────▶│ Ingest │────▶│ Events │
│ (SDK/HTTP) │ │ API │ │ (Postgres) │
└─────────────┘ └──────────┘ └──────────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────────┐
│ Queue │────▶│ Aggregator │
│ (Redis) │ │ Worker │
└──────────┘ └──────────────┘
│
▼
┌──────────────┐
│ Counters │
│(Redis + PG) │
└──────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Stripe │ │ Alerts │ │ Customer │
│ Writer │ │ & Caps │ │ Widget │
└──────────┘ └──────────┘ └──────────┘
Project Structure
stripemeter/
├── packages/
│ ├── core/ # Shared types, schemas, utilities
│ ├── database/ # Database layer (Drizzle ORM + Redis)
│ ├── pricing-lib/ # Pricing calculation engine
│ ├── sdk-node/ # Node.js SDK
│ └── sdk-python/ # Python SDK
├── apps/
│ ├── api/ # REST API (Fastify)
│ ├── workers/ # Background workers (BullMQ)
│ ├── admin-ui/ # Admin dashboard (React)
│ └── customer-widget/ # Embeddable widget (React)
└── infra/ # Infrastructure configs
Quick Start
Get StripeMeter running in under 5 minutes
One-Command Setup
# Clone and setup everything automatically
git clone https://github.com/geminimir/stripemeter.git
cd stripemeter && ./scripts/setup.sh
That's it! The setup script will:
- Check prerequisites (Node.js 20+, pnpm, Docker)
- Install dependencies
- Start infrastructure services
- Run database migrations
- Create example configuration
Manual Setup (if you prefer)
<details> <summary>Click to expand manual installation steps</summary>- **Prerequisites
