A partial emulation of the Metronome billing API that passes internal tests we have at HF (for the covered portion), initially created for coding exercises since one can't create a dev Metronome account on their own.
- ✅ Customer Management: Create and retrieve customers
- ✅ Contract Management: V1 and V2 contract operations (create, list, retrieve, edit)
- ✅ Credit Bridging Logic: Mirrors Metronome's behavior for recurring credits, cancel/un-cancel flows, and next-period credit creation
- ✅ Webhook Dispatch: Emits contract/payment/alert events and supports manual webhook triggering
- ✅ Usage Ingestion: Accept and store usage events
- ✅ Invoice Management: List, retrieve, void, and create invoices (manual creation for testing)
- ✅ Balance Tracking: Query customer balances
- ✅ Dashboard URLs: Generate embeddable dashboard URLs
- ✅ Webhook Verification: Verify webhook signatures
- ✅ In-Memory Storage: All data stored in memory (resets on restart)
npm install# Production mode
npm start
# Development mode (with auto-reload)
npm run devThe server will start on http://localhost:3000 by default. You can change the port by setting the PORT environment variable.
The mock can deliver Metronome-style webhooks:
-
Set
MOCK_METRONOME_WEBHOOK_TARGETto the full webhook URL. -
Optionally set
MOCK_METRONOME_WEBHOOK_PATHif you only want to provide the origin/host. -
Alternatively, register targets at runtime:
curl -X POST http://localhost:3199/webhooks/subscriptions \ -H "Content-Type: application/json" \ -d '{ "target": "http://localhost:5564/api/webhooks/metronome" }'
-
Inspect/clear subscriptions via
GET /webhooks/subscriptionsandDELETE /webhooks/subscriptions(with optional{ "target": "..." }body). -
Manually dispatch a custom event using
POST /webhooks/dispatchwith a JSON body containing the event payload ({ "type": "payment_gate.payment_status", ... }). -
Automatic events:
contract.createdandcontract.updatedfire on contract creation/edits.payment_gate.payment_statusfires when a contract edit includesadd_prepaid_balance_threshold_configuration.commit. Addmock_payment_status: "failed"to simulate failures.alerts.low_remaining_contract_credit_and_commit_balance_reachedfires when a balance (set via helper APIs) drops below the configured threshold. ConfigureMOCK_METRONOME_ALERT_CUSTOMER_BALANCE_DEPLETEDor rely onNODE_METRONOME_CONFIGto match the Hub config.
- POST /v1/customers
- GET /v1/customers/:customer_id
- POST /v1/contracts
- GET /v1/contracts/:contract_id
- POST /v1/contracts/:contract_id/edit
- GET /v2/contracts
- GET /v2/contracts/:contract_id
- POST /v2/contracts/:contract_id/edit
- POST /v2/contracts/edit
- POST /v1/usage/ingest
- POST /v1/customers/:customer_id/invoices (create invoice for mocking purposes)
- GET /v1/customers/:customer_id/invoices
- GET /v1/customers/:customer_id/invoices/:invoice_id
- POST /v1/invoices/:invoice_id/void
- GET /v1/contracts/balances
- POST /v1/dashboards/embeddable-url
- POST /webhooks/verify
- GET /webhooks/subscriptions
- POST /webhooks/subscriptions
- DELETE /webhooks/subscriptions
- POST /webhooks/dispatch
All errors follow this format:
{
"error": {
"message": "Error message",
"status": 400,
"conflicting_id": "id_123" // Optional, for 409 conflicts
}
}200- Success201- Created400- Bad Request401- Unauthorized404- Not Found409- Conflict (e.g., uniqueness key already used)500- Internal Server Error
This mock server uses in-memory storage. All data is lost when the server restarts.
The mock server does not automatically generate invoices from usage events. In a real implementation, Metronome would:
- Process usage events
- Apply credits and subscriptions
- Generate invoices at billing period boundaries
- Create external invoices in Stripe
The mock provides a basic invoice creation endpoint (POST /v1/customers/:customer_id/invoices) that allows you to fake/manually create invoices with line items.
Request body example:
{
"contract_id": "contract_123",
"type": "USAGE",
"status": "FINALIZED",
"line_items": [
{
"type": "usage",
"product_id": "prod_123",
"product_name": "API Calls",
"amount": 100.50,
"is_prorated": false
}
],
"start_timestamp": "2024-01-01T00:00:00Z",
"end_timestamp": "2024-01-31T23:59:59Z",
"due_date": "2024-02-15T00:00:00Z"
}Balances are not automatically calculated from usage and credits. The mock provides an endpoint to retrieve balances, but you may need to implement balance calculation logic if needed (or hardcode/fake it).
The webhook verification is simplified. In production, Metronome uses HMAC-SHA256 signatures. The mock verifies signatures but uses a simplified algorithm.
PORT- Server port (default: 3000)METRONOME_WEBHOOK_SECRET- Webhook secret for signature verification (default: "test-secret")MOCK_METRONOME_URL- Base URL for dashboard embeddable URLs (default: "http://localhost:3000")
If you find bugs or missing features, feel free to update the implementation locally to match the real Metronome API behavior (and open PRs if you want).
MIT