npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@monigo/sdk

v0.1.7

Published

Official Monigo JavaScript / TypeScript SDK — event ingestion, metering, billing, and usage for browser and Node.js

Readme

@monigo/sdk

The official JavaScript/TypeScript client library for the Monigo API. Zero external dependencies — works natively in Node.js (≥ 18), browsers, Cloudflare Workers, Bun, and Deno.

Installation

npm install @monigo/sdk

Or with other package managers:

yarn add @monigo/sdk
pnpm add @monigo/sdk
bun add @monigo/sdk

Requires Node.js 18 or later (for native fetch). For Node.js 16, see Polyfilling fetch.

Quick start

import { MonigoClient, Aggregation, BillingPeriod, PricingModel } from '@monigo/sdk'

const client = new MonigoClient({ apiKey: process.env.MONIGO_API_KEY! })

// Create a customer
const customer = await client.customers.create({
  external_id: 'user_abc123',
  name: 'Acme Corp',
  email: '[email protected]',
})

// Ingest a usage event
await client.events.ingest({
  events: [
    {
      event_name: 'api_call',
      customer_id: customer.id,
      idempotency_key: 'evt_20260201_001',
      timestamp: new Date(),
      properties: { endpoint: '/v1/data', region: 'us-east-1' },
    },
  ],
})

console.log(`Customer ${customer.id} created and event ingested`)

Tip: Use a test-mode API key (mk_test_...) during development. Test events are isolated from live data and won't trigger real charges.

Client configuration

Constructor options

const client = new MonigoClient({
  apiKey: 'mk_live_...',              // required — your Monigo API key
  baseURL: 'https://api.monigo.co',   // optional — defaults to production
  timeout: 30_000,                     // optional — request timeout in ms (default: none)
  fetch: customFetch,                  // optional — custom fetch implementation
})

Custom base URL

For self-hosted deployments or a local development server:

const client = new MonigoClient({
  apiKey: process.env.MONIGO_API_KEY!,
  baseURL: 'http://localhost:8000',
})

Polyfilling fetch

Node.js 16 does not include a built-in fetch. Pass a polyfill via the fetch option:

import fetch from 'node-fetch'

const client = new MonigoClient({
  apiKey: process.env.MONIGO_API_KEY!,
  fetch: fetch as unknown as typeof globalThis.fetch,
})

Using in tests

The fetch option makes the client fully testable without a network:

const client = new MonigoClient({
  apiKey: 'test_key',
  fetch: (_url, _init) =>
    Promise.resolve(new Response(JSON.stringify({ customer: mockCustomer }))),
})

Authentication

Every request is authenticated with a Bearer token derived from your API key:

Authorization: Bearer mk_live_...

API keys are scoped to an organisation and carry one of two prefixes:

| Prefix | Mode | Usage | |--------|------|-------| | mk_live_ | Live | Production traffic — charges and payouts are real | | mk_test_ | Test | Development / CI — events, customers, and invoices are sandboxed |

Error handling

All methods return a Promise. On a 4xx or 5xx response the SDK throws a MonigoAPIError with a typed status code, message, and optional field-level details map.

import { MonigoAPIError } from '@monigo/sdk'

try {
  const customer = await client.customers.get('cust_missing')
} catch (err) {
  if (err instanceof MonigoAPIError) {
    console.error(`API error ${err.statusCode}: ${err.message}`)
    // { statusCode: 404, message: 'customer not found' }
  }
}

Static type-narrowing guards

Instead of catching and casting, use the static guards on MonigoAPIError:

try {
  await client.subscriptions.create({ customer_id: 'c', plan_id: 'p' })
} catch (err) {
  if (MonigoAPIError.isConflict(err)) {
    // customer already has an active subscription of this plan type
  } else if (MonigoAPIError.isNotFound(err)) {
    // customer or plan not found
  } else if (MonigoAPIError.isRateLimited(err)) {
    // back off and retry
  } else if (err) {
    throw err
  }
}

| Guard | HTTP Status | When it fires | |-------|-------------|---------------| | MonigoAPIError.isNotFound(err) | 404 | Resource does not exist | | MonigoAPIError.isUnauthorized(err) | 401 | Invalid or missing API key | | MonigoAPIError.isForbidden(err) | 403 | API key lacks required scope | | MonigoAPIError.isConflict(err) | 409 | Duplicate resource (e.g. second active subscription of same plan type) | | MonigoAPIError.isRateLimited(err) | 429 | Request rate limit exceeded | | MonigoAPIError.isQuotaExceeded(err) | 402 | Organisation event quota exhausted | | MonigoAPIError.isServerError(err) | 5xx | Unexpected server-side error |

Instance flags

MonigoAPIError also exposes boolean instance properties:

catch (err) {
  if (err instanceof MonigoAPIError && err.isNotFound) {
    // same as MonigoAPIError.isNotFound(err)
  }
}

Events

The client.events service handles usage event ingestion and event replay.

Ingest events

const response = await client.events.ingest({
  events: [
    {
      event_name: 'api_call',
      customer_id: 'cust_abc',
      idempotency_key: 'evt_20260201_001',
      timestamp: new Date(),
      properties: {
        endpoint: '/v1/predict',
        region: 'us-east-1',
        tokens: 1500,
      },
    },
  ],
})

console.log('ingested:', response.ingested)
console.log('duplicates:', response.duplicates)

The server deduplicates events by idempotency_key. Sending the same key twice is safe — the second call appears in response.duplicates and won't be counted again. A single ingest call can contain up to 1,000 events.

Tip: Always supply a stable idempotency_key (e.g. a UUID or ${customer_id}_${event_type}_${timestamp}) so retries after a network error don't double-count events.

Replay events

Replay reprocesses all events in a time window through the metering pipeline. Use this to correct rollups after an outage or metric definition change.

let job = await client.events.startReplay({
  from: new Date('2026-01-01'),
  to: new Date('2026-01-31'),
  event_name: 'api_call', // omit to replay all event names
})

// Poll until complete
while (job.status === 'pending' || job.status === 'processing') {
  await new Promise(r => setTimeout(r, 5_000))
  job = await client.events.getReplay(job.id)
  console.log(`replayed ${job.events_replayed} / ${job.events_total}`)
}

Customers

// Create
const customer = await client.customers.create({
  external_id: 'user_123',
  name: 'Acme Corp',
  email: '[email protected]',
})

// List
const { customers, count } = await client.customers.list()
console.log(`${count} customers`)

// Get by Monigo ID
const customer = await client.customers.get('cust_abc')

// Update
const updated = await client.customers.update('cust_abc', {
  name: 'Acme Corp Ltd',
  email: '[email protected]',
})

// Delete
await client.customers.delete('cust_abc')

Tip: Set external_id to your own system's user ID. This lets you look up a customer by your existing identifier without storing Monigo's UUID separately.

Metrics

A metric defines what gets counted (e.g. "API calls", "GB stored") and how raw event values are aggregated.

import { Aggregation } from '@monigo/sdk'

// Count events
const metric = await client.metrics.create({
  name: 'API Calls',
  event_name: 'api_call',
  aggregation: Aggregation.Count,
})

// Sum a numeric property (e.g. tokens used)
const metric = await client.metrics.create({
  name: 'Tokens Used',
  event_name: 'completion',
  aggregation: Aggregation.Sum,
  aggregation_property: 'tokens',
})

// List / get / update / delete
const { metrics } = await client.metrics.list()
const metric = await client.metrics.get('metric_abc')
const updated = await client.metrics.update('metric_abc', { name: 'Renamed' })
await client.metrics.delete('metric_abc')

Aggregation constants

| Constant | Value | Description | |----------|-------|-------------| | Aggregation.Count | count | Count the number of matching events | | Aggregation.Sum | sum | Sum a numeric property across events | | Aggregation.Max | max | Maximum value of a property | | Aggregation.Min | minimum | Minimum value of a property | | Aggregation.Average | average | Average value of a property | | Aggregation.Unique | unique | Count distinct values of a property |

Plans

A plan combines billing period, currency, and one or more prices. Each price links a metric to a pricing model.

import { BillingPeriod, PricingModel, PlanType } from '@monigo/sdk'

// Flat rate: ₦50 per API call
const plan = await client.plans.create({
  name: 'Starter',
  currency: 'NGN',
  billing_period: BillingPeriod.Monthly,
  prices: [
    {
      metric_id: 'metric_api_calls',
      model: PricingModel.Flat,
      unit_price: '50.000000',
    },
  ],
})

// Tiered pricing
const plan = await client.plans.create({
  name: 'Growth',
  currency: 'NGN',
  billing_period: BillingPeriod.Monthly,
  prices: [
    {
      metric_id: 'metric_api_calls',
      model: PricingModel.Tiered,
      tiers: [
        { up_to: 10_000, unit_amount: '5.00' },
        { up_to: 100_000, unit_amount: '3.00' },
        { up_to: null, unit_amount: '1.50' },  // null = infinity
      ],
    },
  ],
})

// List / get / update / delete
const { plans } = await client.plans.list()
const plan = await client.plans.get('plan_abc')
const updated = await client.plans.update('plan_abc', { name: 'Renamed' })
await client.plans.delete('plan_abc')

Pricing model constants

| Constant | Value | Description | |----------|-------|-------------| | PricingModel.Flat | flat | Fixed price per unit | | PricingModel.Tiered | tiered | Graduated tiers — each unit priced at its tier | | PricingModel.Volume | volume | Whole volume priced at one tier | | PricingModel.Package | package | Price per block of N units | | PricingModel.Overage | overage | Base allowance + per-unit above threshold | | PricingModel.WeightedTiered | weighted_tiered | Average price across graduated tiers |

Plan type and billing period constants

| Constant | Value | Meaning | |----------|-------|---------| | PlanType.Collection | collection | Charge customers (default) | | PlanType.Payout | payout | Pay out to vendors | | BillingPeriod.Daily | daily | Billed every day | | BillingPeriod.Weekly | weekly | Billed every week | | BillingPeriod.Monthly | monthly | Billed every month | | BillingPeriod.Quarterly | quarterly | Billed every quarter | | BillingPeriod.Annually | annually | Billed every year |

Subscriptions

A subscription links a customer to a plan and tracks the current billing period.

import { SubscriptionStatus } from '@monigo/sdk'

// Create
const sub = await client.subscriptions.create({
  customer_id: 'cust_abc',
  plan_id: 'plan_starter',
})

// List with filters
const { subscriptions } = await client.subscriptions.list({
  customer_id: 'cust_abc',
  status: SubscriptionStatus.Active,
})

// Get
const sub = await client.subscriptions.get('sub_abc')

// Pause / resume
await client.subscriptions.updateStatus('sub_abc', SubscriptionStatus.Paused)
await client.subscriptions.updateStatus('sub_abc', SubscriptionStatus.Active)

// Cancel (soft-delete)
await client.subscriptions.delete('sub_abc')

| Status constant | Value | Meaning | |-----------------|-------|---------| | SubscriptionStatus.Active | active | Billing is running | | SubscriptionStatus.Paused | paused | Billing paused; events still accepted | | SubscriptionStatus.Canceled | canceled | Subscription ended |

Warning: A customer can hold at most one active subscription per plan type. A second active collection or payout subscription returns a 409 — catch it with MonigoAPIError.isConflict(err).

Payout accounts

Payout accounts are bank or mobile-money accounts that a customer can receive payouts to. All methods require a customerId as the first argument.

import { PayoutMethod } from '@monigo/sdk'

// Bank transfer
const account = await client.payoutAccounts.create('cust_abc', {
  account_name: 'John Driver',
  payout_method: PayoutMethod.BankTransfer,
  bank_name: 'First Bank Nigeria',
  bank_code: '011',
  account_number: '3001234567',
  currency: 'NGN',
  is_default: true,
})

// Mobile money
const account = await client.payoutAccounts.create('cust_abc', {
  account_name: 'John Driver',
  payout_method: PayoutMethod.MobileMoney,
  mobile_money_number: '+2348012345678',
  currency: 'NGN',
})

// List all accounts for a customer
const { payout_accounts } = await client.payoutAccounts.list('cust_abc')

// Get / update / delete
const acct = await client.payoutAccounts.get('cust_abc', 'acct_xyz')
await client.payoutAccounts.update('cust_abc', 'acct_xyz', { account_name: 'Jane Driver' })
await client.payoutAccounts.delete('cust_abc', 'acct_xyz')

| Method constant | Value | |-----------------|-------| | PayoutMethod.BankTransfer | bank_transfer | | PayoutMethod.MobileMoney | mobile_money |

Invoices

Invoices are generated from subscriptions and contain line items derived from the customer's usage in the billing period.

import { InvoiceStatus } from '@monigo/sdk'

// Generate a draft invoice
const invoice = await client.invoices.generate('sub_abc')
console.log(`Draft invoice ${invoice.id} — total: ${invoice.total} ${invoice.currency}`)

for (const item of invoice.line_items ?? []) {
  console.log(`  ${item.description}: qty ${item.quantity} × ${item.unit_price} = ${item.amount}`)
}

// List with filters
const { invoices } = await client.invoices.list({
  customer_id: 'cust_abc',
  status: InvoiceStatus.Draft,
})

// Get / finalize / void
const invoice = await client.invoices.get('inv_abc')
const finalized = await client.invoices.finalize('inv_abc')
const voided = await client.invoices.void('inv_abc')

| Status constant | Value | Meaning | |-----------------|-------|---------| | InvoiceStatus.Draft | draft | Not yet finalized; amounts may change | | InvoiceStatus.Finalized | finalized | Locked and ready for payment | | InvoiceStatus.Paid | paid | Payment collected | | InvoiceStatus.Void | void | Cancelled |

Note: All monetary amounts (subtotal, total, unit_price) are returned as decimal strings (e.g. "1500.00") to preserve precision across currencies.

Usage

Query aggregated usage rollups to see how much a customer has consumed in a period.

// All usage for the current period
const result = await client.usage.query()

// Filter by customer and metric
const result = await client.usage.query({
  customer_id: 'cust_abc',
  metric_id: 'metric_api_calls',
})

// Custom time window — accepts Date objects or ISO strings
const result = await client.usage.query({
  customer_id: 'cust_abc',
  from: new Date('2026-01-01'),
  to: new Date('2026-01-31'),
})

for (const rollup of result.rollups) {
  console.log(
    `customer ${rollup.customer_id} — ${rollup.aggregation}: ${rollup.value}`,
    `(period: ${rollup.period_start} → ${rollup.period_end})`
  )
}

Example programs

The SDK ships five runnable example programs under examples/:

| Program | What it demonstrates | |---------|----------------------| | examples/quickstart | End-to-end: customer → metric → plan → subscription → ingest events | | examples/metering | High-volume batch ingest with idempotency and rate-limit handling | | examples/billing | Generate, inspect, and finalize an invoice | | examples/payouts | Register payout accounts and trigger event replay | | examples/usage-report | Query rollups and print a terminal usage table |

Run any example by setting MONIGO_API_KEY and executing from the examples/ directory:

cd js-sdk/examples
npm install
MONIGO_API_KEY=mk_test_... npm run quickstart

TypeScript exports

All types and constants are exported from the root:

import {
  MonigoClient,
  MonigoAPIError,

  // Constants
  Aggregation,
  PricingModel,
  PlanType,
  BillingPeriod,
  SubscriptionStatus,
  InvoiceStatus,
  PayoutMethod,

  // Types
  type Customer,
  type CreateCustomerRequest,
  type UpdateCustomerRequest,
  type ListCustomersResponse,
  type Metric,
  type CreateMetricRequest,
  type Plan,
  type CreatePlanRequest,
  type CreatePriceRequest,
  type PriceTier,
  type Subscription,
  type CreateSubscriptionRequest,
  type ListSubscriptionsParams,
  type PayoutAccount,
  type CreatePayoutAccountRequest,
  type Invoice,
  type InvoiceLineItem,
  type ListInvoicesParams,
  type IngestEvent,
  type IngestRequest,
  type IngestResponse,
  type EventReplayJob,
  type UsageRollup,
  type UsageQueryParams,
  type UsageQueryResult,
} from '@monigo/sdk'

Module format

The package ships dual-format bundles to work everywhere:

| Format | File | Used by | |--------|------|---------| | ESM | dist/monigo.js | Node.js ≥ 12 (with "type":"module"), bundlers, browsers | | CJS | dist/monigo.cjs | Node.js CommonJS (require()) | | Types | dist/index.d.ts | TypeScript consumers (both formats) |

The exports map in package.json routes each environment automatically — no manual import paths needed.

Browser / CDN usage

<script type="module">
  import { MonigoClient } from 'https://esm.sh/@monigo/sdk'

  const client = new MonigoClient({ apiKey: 'mk_test_...' })
  const { customers } = await client.customers.list()
  console.log(customers)
</script>

Warning: Never embed a live API key in frontend code. For browser usage, proxy requests through your own backend or use a restricted publishable key if supported.

Development

Prerequisites

  • Node.js ≥ 18
  • npm

Setup

cd js-sdk
npm install

Build

npm run build

Produces dist/monigo.js (ESM), dist/monigo.cjs (CJS), and dist/index.d.ts.

Run tests

npm run test:run       # run all 90 tests once
npm run test           # watch mode
npm run test:coverage  # with V8 coverage report

Type check

npm run typecheck

Publishing

The release workflow builds, tests, bumps the version, tags the commit, and publishes to npm in one command:

# Patch release (1.0.0 → 1.0.1) — bug fixes
npm run release:patch

# Minor release (1.0.0 → 1.1.0) — new features, backwards-compatible
npm run release:minor

# Major release (1.0.0 → 2.0.0) — breaking changes
npm run release:major

Each command runs:

  1. npm run build — compile TypeScript and bundle
  2. npm run test:run — run the full test suite
  3. npm version <patch|minor|major> — bump package.json and create a git tag
  4. git push --follow-tags — push the commit and tag to the remote
  5. npm publish --access public — publish to the npm registry

CI/CD

Add this GitHub Actions workflow to publish automatically on a tag push:

# .github/workflows/publish.yml
name: Publish to npm

on:
  push:
    tags:
      - 'js-sdk/v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          registry-url: 'https://registry.npmjs.org'
      - run: npm ci
        working-directory: js-sdk
      - run: npm run build
        working-directory: js-sdk
      - run: npm run test:run
        working-directory: js-sdk
      - run: npm publish --access public
        working-directory: js-sdk
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Versioning

This SDK follows Semantic Versioning:

  • Patch (x.y.Z) — bug fixes, internal improvements, no API changes
  • Minor (x.Y.0) — new methods or options, fully backwards-compatible
  • Major (X.0.0) — breaking changes to the public API surface

Changelog

1.0.0 (2026-02-22)

  • Initial release
  • Full coverage of all 9 Monigo API resource groups: Events, Customers, Metrics, Plans, Subscriptions, Payout Accounts, Invoices, Usage
  • Dual ESM + CJS build via Vite library mode
  • 90 unit tests with zero external dependencies
  • TypeScript types and constant objects for all enum values

License

MIT