Skip to content

geminimir/stripemeter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

StripeMeter β€” pre-invoice parity for Stripe usage billing

CI GitHub release License: MIT PRs Welcome Community Contributors

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/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

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 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 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

  • 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

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_KEY in your environment (in addition to STRIPE_SECRET_KEY).
  • Mark a price mapping with shadow=true and provide shadowStripeAccount, shadowPriceId, and optionally shadowSubscriptionItemId.
  • 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 but STRIPE_TEST_SECRET_KEY is 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:

  1. Transparency First: Customers should never be surprised by their bill
  2. Developer Experience: Building usage-based pricing should be delightful
  3. 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)

Click to expand manual installation steps
  1. Prerequisites: Node.js 20+, pnpm 8+, Docker
  2. Install: pnpm install
  3. Configure: Copy .env.example to .env and add your Stripe keys
  4. Infrastructure: docker compose up -d
  5. Database: pnpm db:migrate
  6. Start: pnpm dev

You're Ready!

  • API: http://localhost:3000 (with Swagger docs at /docs)
  • Admin Dashboard: http://localhost:3001
  • Customer Widget Demo: http://localhost:3002

Try the Interactive Demo

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!

Core Concepts

Events (Immutable Ledger)

Every usage event is stored with a deterministic idempotency key. Events are never deleted or modified - corrections are made through adjustments.

Counters (Materialized Aggregations)

Pre-computed aggregations (sum/max/last) by tenant, metric, customer, and period. Updated in near-real-time by the aggregator worker.

Watermarks (Late Event Handling)

Each counter maintains a watermark timestamp. Events arriving within the lateness window (default 48h) trigger re-aggregation. Later events become adjustments.

Delta Push (Stripe Synchronization)

The writer tracks pushed_total per subscription item and only sends the delta to Stripe, ensuring idempotent updates even after retries.

Reconciliation (Trust but Verify)

Hourly comparison of local totals vs Stripe reported usage. Differences beyond epsilon (0.5%) trigger investigation and suggested adjustments.

Pricing Simulator

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.

Quick Example

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

πŸ“– Complete Documentation

Why Use the Simulator?

βœ… 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

Usage Examples

Track Usage with SDKs

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"}'

Embed the Customer Widget

<!-- 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>

Contributing

StripeMeter is built by the community, for the community.

Ways to Contribute

  • 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

Quick Contribution Guide

  1. Fork the repo and create your branch: git checkout -b my-amazing-feature
  2. Make your changes and add tests if needed
  3. Run the tests: pnpm test
  4. Commit with a clear message: git commit -m "Add amazing feature"
  5. Push and create a PR - we'll review it quickly!

Testing & Quality

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

Deployment

One-Click Deploy

Deploy to Railway Deploy with Vercel

Docker Production

# 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

Kubernetes

# Apply all manifests
kubectl apply -k infra/k8s/

# Or use Helm
helm install stripemeter ./charts/stripemeter

Performance & Monitoring

Production SLOs:

  • Ingest latency p99 ≀ 200ms
  • Projection staleness ≀ 60s
  • Reconciliation accuracy β‰₯ 99.5%
  • Uptime β‰₯ 99.9%

Built-in Observability:

License

StripeMeter is MIT licensed. Use it, modify it, distribute it - we believe in open source!

Acknowledgments

Built with ❀️ by the open-source community. Special thanks to:


If StripeMeter helps your business, please give us a star!

Star on GitHub β€’ Documentation β€’ Community

Made with ❀️ by developers who believe in billing transparency