Skip to content
tl-openmeter-local-dev logo

OpenMeter Local Dev Setup

tl-openmeter-local-dev

Set up and troubleshoot OpenMeter for local development with Docker, ngrok, Stripe app, and webhook configuration. Covers self-hosted vs Cloud differences, catalog sync, environment-aware webhook handling, and OpenMeter Apps (Stripe, Sandbox). Use when setting up OpenMeter locally, configuring ng...

SKILL.md

Full skill instructions

<!-- Copyright (c) 2026 Todd Levy. Licensed under MIT. SPDX-License-Identifier: MIT -->

OpenMeter Local Dev Setup

Run OpenMeter locally with full metering, billing, and webhook support. Covers the gotchas that differ between self-hosted (Docker) and Cloud (staging/​production).

When to Use

  • "Set up OpenMeter locally"
  • "Configure ngrok for webhooks"
  • "Debug catalog sync errors"
  • "Why is my webhook 500ing?"
  • "Install the Stripe app in OpenMeter"
  • "What works locally vs staging?"
  • When user mentions OpenMeter + Docker, local dev, or webhook issues

Suite

This skill is part of the tl-openmeter suite:

SkillPurpose
tl-openmeter-apiREST API reference (endpoints, schemas, gotchas)
tl-openmeter-local-devThis skill: local dev setup and troubleshooting
tl-openmeter-api-mcp-serverMCP server for calling local OpenMeter from Cursor

Resources


Step 0: Discover the User's Situation

Before proceeding, use the AskQuestion tool to determine what applies:

Question 1: Environment

  • Local development (Docker) — proceed with this skill
  • Staging or Production — redirect to tl-openmeter-api and deployment docs

Question 2: Stripe billing needed?

  • Yes → Steps 1, 2, 3, 4, 5, 6 (full setup with ngrok)
  • No → Steps 1, 4, 5 only (metering and entitlements without billing)

Question 3: Ngrok status (only if Stripe = yes)

  • Already set up → skip ngrok install in Step 3
  • Need to set it up → full Step 3
  • Paid plan with static domain → note in Step 3 about skipping URL updates

Self-Hosted vs Cloud: Critical Differences

FeatureSelf-Hosted (Local)Cloud (Staging/​Prod)
Event ingestionYesYes
Meters, features, plansYesYes
Customers, subscriptionsYesYes
Entitlement checksYesYes
Billing with Stripe AppYes (via apps.baseURL)Yes
Webhook channels via APINO ("not implemented")Yes (Svix-backed)
Webhook notificationsYes (YAML config only)Yes (API channels)
Svix signature verificationNo (plain HTTP)Yes

Key insight: Webhooks work locally via config.local.yaml static configuration. Cloud uses the POST /​api/​v1/​notification/​channels API (Svix). The catalog sync script handles this automatically.


Step 1: Start Docker Services

npm run docker:up

Verify OpenMeter is healthy:

curl http://localhost:8888/api/v1/meters

Portal UI: http://localhost:8889

Or run the verification script:

.\scripts\verify-setup.ps1

Step 2: Install Stripe App

See references/​apps.md for full details on OpenMeter Apps.

npx tsx scripts/​openmeter/​openmeter-install-stripe-app.ts

This installs Stripe and creates a billing profile.

Requires: STRIPE_SECRET_KEY in .env

Verify: curl http://localhost:8888/api/v1/apps — should show Stripe (Sandbox may also be present and is irrelevant).


Step 3: Set Up Ngrok

Required for Stripe App callbacks and Stripe webhooks locally.

  1. Install: choco install ngrok (Windows) or brew install ngrok (macOS)
  2. Auth: ngrok config add-authtoken YOUR_TOKEN
  3. Start: .\scripts\start-ngrok.ps1 or ngrok http 3001
  4. Get URL: curl http://127.0.0.1:4040/api/tunnels

Then configure (or use the helper script):

npx tsx scripts/​openmeter/​set-openmeter-webhook-url.ts

Manual config requires updating three places — see references/​REFERENCE.md for the full list.

After config changes: docker compose restart openmeter


Step 4: Run Catalog Sync

npx tsx scripts/​openmeter/​openmeter-catalog-sync.ts

Expected local output includes ⊘ Skipping webhook channel (not supported on self-hosted OpenMeter) — this is normal.

See references/​REFERENCE.md for common errors and fixes.


Step 5: Start API Server

npm run dev

For ngrok HTTP forwarding, set API_HTTP_FOR_NGROK=true in .env.


Step 6: Configure Stripe Webhooks

In Stripe Dashboard:

  1. Add endpoint: https://YOUR-NGROK-URL/webhooks/stripe
  2. Events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted
  3. Copy signing secret to .env as STRIPE_WEBHOOK_SECRET_DEV=whsec_...

Webhook Authentication

See references/​webhooks.md for full details.

ModeEnvironmentMechanism
Svix signaturesCloud (staging/​prod)SVIX_WEBHOOK_SECRET + Svix headers
x-webhook-secretSelf-hosted with secretOPENMETER_WEBHOOK_SECRET header check
Dev passthroughLocal (no secret set)Accepts all — self-hosted sends plain HTTP

Verification

Run the verification script to check all layers:

.\scripts\verify-setup.ps1

Or manually:

# OpenMeter running
curl http://localhost:8888/api/v1/meters

# Stripe App installed
curl http://localhost:8888/api/v1/apps

# Webhook endpoint responding
curl -X POST http://127.0.0.1:3001/webhooks/openmeter \
  -H "Content-Type: application/​json" \
  -d '{"type":"entitlements.balance.threshold","payload":{"customerId":"test"}}'

Troubleshooting

SymptomFix
EADDRINUSE on 3001Kill existing process on that port
OpenMeter container won't startCheck Docker logs; usually Kafka/​PG not ready
Catalog sync connection refusedOpenMeter not running — docker ps
Stripe App missing after cleanupnpx tsx scripts/​openmeter/​openmeter-install-stripe-app.ts
Ngrok URL changedUpdate .env, config.local.yaml, Stripe Dashboard; restart OpenMeter

See references/​REFERENCE.md for the full troubleshooting matrix.


References

First-Party Documentation

Development Tools

Related Skills