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
- End-of-cycle parity demo (Stripe Test Clocks)
- Replay API β
POST /v1/replay
with dry-run/apply; watermark/cursor semantics - Shadow Mode β test-environment pushes with deterministic idempotency keys
- /metrics + Prometheus + Grafana dashboard
- ALERTS.md + RECONCILIATION.md runbook
git clone https://github.com/geminimir/stripemeter && cd stripemeter
cp .env.example .env && docker compose up -d && pnpm -r build && 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
- 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.
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.
- SaaS teams on Stripe usage-based pricing
- Engineers who need correct usage totals and early drift detection
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)
(Optional preflight: bash scripts/preflight.sh
)
pnpm i -w
cp .env.example .env
docker compose up -d
pnpm -r build
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
# 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.
- p95 ingest latency: ~10β25 ms
- Re-aggregation of 10k late events: β€ 2 s
- Duplicate events inside 24 h idempotency window: 0 double-counts
- Exact-once effect: idempotency window (duplicates wonβt double-count)
- Late events handled via watermarks + re-aggregation
- Delta writes to Stripe (no over-reporting)
- Health endpoints + structured logs +
/metrics
- Prometheus scrape + Grafana dashboard + alert recipes
- Replay via API for safe reprocessing
- Shadow Mode for safe test pushes
- 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
Put a tiny config in examples/config/stripemeter.config.ts
to map metric β counter
and choose a watermarkWindowSeconds
.
Shadow Mode lets you post usage to Stripeβs test environment in parallel without affecting live invoices.
- Set
STRIPE_TEST_SECRET_KEY
in your environment (in addition toSTRIPE_SECRET_KEY
). - Mark a price mapping with
shadow=true
and 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=true
butSTRIPE_TEST_SECRET_KEY
is missing, pushes are skipped with warnings.
- 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.
- 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
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.
βββββββββββββββ ββββββββββββ ββββββββββββββββ
β Clients ββββββΆβ Ingest ββββββΆβ Events β
β (SDK/HTTP) β β API β β (Postgres) β
βββββββββββββββ ββββββββββββ ββββββββββββββββ
β β
βΌ βΌ
ββββββββββββ ββββββββββββββββ
β Queue ββββββΆβ Aggregator β
β (Redis) β β Worker β
ββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ
β Counters β
β(Redis + PG) β
ββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββ
βΌ βΌ βΌ
ββββββββββββ ββββββββββββ ββββββββββββ
β Stripe β β Alerts β β Customer β
β Writer β β & Caps β β Widget β
ββββββββββββ ββββββββββββ ββββββββββββ
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
Get StripeMeter running in under 5 minutes
# 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
Click to expand manual installation steps
- Prerequisites: Node.js 20+, pnpm 8+, Docker
- Install:
pnpm install
- Configure: Copy
.env.example
to.env
and add your Stripe keys - Infrastructure:
docker compose up -d
- Database:
pnpm db:migrate
- Start:
pnpm dev
- API:
http://localhost:3000
(with Swagger docs at/docs
) - Admin Dashboard:
http://localhost:3001
- Customer Widget Demo:
http://localhost:3002
Experience StripeMeter in action with our realistic SaaS demo:
cd demo/cloudapi-saas
./demo-start.sh
The demo showcases:
- Real-time usage tracking with live cost updates
- Multiple pricing tiers (Free, Pro, Enterprise)
- Interactive API testing with immediate billing feedback
- Usage simulation tools for different traffic patterns
- Complete billing transparency that customers love
Perfect for understanding how StripeMeter integrates with your SaaS application!
Every usage event is stored with a deterministic idempotency key. Events are never deleted or modified - corrections are made through adjustments.
Pre-computed aggregations (sum/max/last) by tenant, metric, customer, and period. Updated in near-real-time by the aggregator worker.
Each counter maintains a watermark timestamp. Events arriving within the lateness window (default 48h) trigger re-aggregation. Later events become adjustments.
The writer tracks pushed_total
per subscription item and only sends the delta to Stripe, ensuring idempotent updates even after retries.
Hourly comparison of local totals vs Stripe reported usage. Differences beyond epsilon (0.5%) trigger investigation and suggested adjustments.
Test and optimize your pricing strategy before going live
The StripeMeter pricing simulator helps you validate billing logic, compare pricing models, and ensure customers are never surprised by their bills.
import { InvoiceSimulator } from '@stripemeter/pricing-lib';
const simulator = new InvoiceSimulator();
// Compare tiered vs volume pricing for 25,000 API calls
const tieredPrice = simulator.simulate({
customerId: 'test',
periodStart: '2024-01-01',
periodEnd: '2024-02-01',
usageItems: [{
metric: 'api_calls',
quantity: 25000,
priceConfig: {
model: 'tiered',
currency: 'USD',
tiers: [
{ upTo: 10000, unitPrice: 0.01 },
{ upTo: 50000, unitPrice: 0.008 },
{ upTo: null, unitPrice: 0.005 }
]
}
}]
});
console.log(`Tiered pricing: $${tieredPrice.total}`); // $220
- Simulator Getting Started - Complete guide with examples
- Pricing Scenarios - Real-world use cases and comparisons
- Example Code - Runnable examples for all pricing models
β
Validate pricing accuracy - Test before customers see bills
β
Compare pricing models - Tiered vs Volume vs Graduated
β
Optimize revenue - Find the best pricing for your segments
β
Handle edge cases - Test zero usage, tier boundaries, credits
β
Enterprise scenarios - Multi-metric billing with commitments
Node.js SDK
import { createClient } from '@stripemeter/sdk-node';
const client = createClient({
apiUrl: 'http://localhost:3000',
tenantId: 'your-tenant-id',
customerId: 'cus_ABC123'
});
// Track a single event
await client.track({
metric: 'api_calls',
customerRef: 'cus_ABC123',
quantity: 100,
meta: { endpoint: '/v1/search', region: 'us-east-1' }
});
// Get live usage and cost projection
const usage = await client.getUsage('cus_ABC123');
const projection = await client.getProjection('cus_ABC123');
console.log(`Current usage: ${usage.metrics[0].current}`);
console.log(`Projected cost: $${projection.total}`);
Python SDK
from stripemeter import StripeMeterClient
client = StripeMeterClient(
api_url="http://localhost:3000",
tenant_id="your-tenant-id",
customer_id="cus_ABC123"
)
# Track usage
client.track(
metric="api_calls",
customer_ref="cus_ABC123",
quantity=100,
meta={"endpoint": "/v1/search", "region": "us-east-1"}
)
# Get projections
projection = client.get_projection("cus_ABC123")
print(f"Projected cost: ${projection.total}")
REST API
# Ingest usage events
curl -X POST http://localhost:3000/v1/events/ingest \
-H "Content-Type: application/json" \
-d '{
"events": [{
"tenantId": "your-tenant-id",
"metric": "api_calls",
"customerRef": "cus_ABC123",
"quantity": 100,
"ts": "2025-01-16T14:30:00Z"
}]
}'
# Get cost projection
curl -X POST http://localhost:3000/v1/usage/projection \
-H "Content-Type: application/json" \
-d '{"tenantId": "your-tenant-id", "customerRef": "cus_ABC123"}'
<!-- Add to your customer dashboard -->
<div id="usage-widget"></div>
<script src="https://cdn.stripemeter.io/widget/v1/stripemeter-widget.umd.js"></script>
<script>
StripeMeterWidget.initStripeMeterWidget('usage-widget', {
apiUrl: 'https://api.stripemeter.io',
tenantId: 'your-tenant-id',
customerId: 'cus_ABC123',
theme: 'light' // or 'dark'
});
</script>
StripeMeter is built by the community, for the community.
- Found a bug? Open an issue
- Have an idea? Start a discussion
- Improve docs - Even fixing typos helps!
- Add tests - Help us improve reliability
- Design improvements - Make StripeMeter more beautiful
- New features - Check our roadmap
- Fork the repo and create your branch:
git checkout -b my-amazing-feature
- Make your changes and add tests if needed
- Run the tests:
pnpm test
- Commit with a clear message:
git commit -m "Add amazing feature"
- Push and create a PR - we'll review it quickly!
We maintain high code quality standards:
# Run all tests
pnpm test
# Type checking
pnpm typecheck
# Linting
pnpm lint
# End-to-end tests
pnpm test:e2e
# Production deployment
docker compose -f docker-compose.prod.yml up -d
# With monitoring stack
docker compose -f docker-compose.prod.yml --profile monitoring up -d
# Apply all manifests
kubectl apply -k infra/k8s/
# Or use Helm
helm install stripemeter ./charts/stripemeter
Production SLOs:
- Ingest latency p99 β€ 200ms
- Projection staleness β€ 60s
- Reconciliation accuracy β₯ 99.5%
- Uptime β₯ 99.9%
Built-in Observability:
- Prometheus metrics
- Structured logging
- Distributed tracing
- Health check endpoints
- Alerts: see ops/ALERTS.md and the Reconciliation Runbook
StripeMeter is MIT licensed. Use it, modify it, distribute it - we believe in open source!
Built with β€οΈ by the open-source community. Special thanks to:
- Stripe for the amazing payments platform
- All our contributors
If StripeMeter helps your business, please give us a star!
Star on GitHub β’ Documentation β’ Community
Made with β€οΈ by developers who believe in billing transparency