Meter usage
Report metered usage against a subscription item and reconcile it at the end of a period.
Goal
Bill a customer for variable consumption — API calls, GB ingested, minutes streamed — by reporting usage events against a subscription item with a metered price. The platform aggregates the reports, generates an invoice line at period close, and exposes a reconciliation view so you can match what you reported against what was billed.
Prerequisites
- A sandbox or production API key
@easylabs/nodeinstalled- A Price created with
pricing_model: "metered" - A Subscription with at least one item using that price
Implementation
1. Report usage as it happens
Each event references the subscription_item_id and a quantity. Pass action: "increment" (the default) to add to the bucket, or action: "set" to overwrite the period total. Use idempotency_key to make retries safe.
import { createClient } from "@easylabs/node";
const easy = await createClient({ apiKey: process.env.EASY_API_KEY! });
await easy.reportSubscriptionUsage("sub_01HXXXXXXXXXXX", {
subscription_item_id: "si_01HXXXXXXXXXXX",
quantity: 1,
action: "increment",
timestamp: new Date().toISOString(),
idempotency_key: `evt_${eventId}`,
});For high-volume metering, batch on your side and submit in larger chunks rather than one event per API call. quantity is an integer; pre-aggregate fractional units to whole ones at the resolution you're billing.
2. Read the running total
getSubscriptionUsageSummary returns the current period's accumulated usage by item. Use as_of to view a historical snapshot or from/to to bound the window.
const { data: summary } = await easy.getSubscriptionUsageSummary(
"sub_01HXXXXXXXXXXX",
{ subscription_item_id: "si_01HXXXXXXXXXXX" },
);Surface this in your customer-facing dashboard so usage is visible before the invoice closes.
3. Reconcile at period end
When the subscription rolls over, the engine generates an invoice line for the metered totals. getSubscriptionUsageReconciliation returns the reported-vs-billed comparison for a closed period — call it from a scheduled job and alert if the deltas exceed your tolerance.
const { data: recon } = await easy.getSubscriptionUsageReconciliation(
"sub_01HXXXXXXXXXXX",
{
subscription_item_id: "si_01HXXXXXXXXXXX",
period_start: "2026-04-01T00:00:00Z",
period_end: "2026-05-01T00:00:00Z",
},
);Listen for invoice.created and invoice.finalized to know when to run reconciliation.
Tradeoffs
incrementvs.set—incrementis the default and fits event streams.setis the right call only when you have an authoritative period total (e.g. nightly batch from a data warehouse) and you can guarantee one report per period.- Latency — usage reports are not invoiced in real time. Reports flushed within the period are billed; reports backfilled after the period closes go on the next invoice (or fail to record, depending on configuration). Bound your reporting lag to less than the billing interval.
- Idempotency keys are per subscription item, not global. A retry with the same
idempotency_keyis safely deduped; reusing the key for a new event will silently drop it.