All posts
Tutorial Licensing Models

Usage-Based / Metered Software Licensing Explained

PC
PermitCore
September 16, 2026 · 6 min read

Node-locked and floating licenses both answer "how many devices/seats." Metered licensing answers a different question: "how much did this customer actually use it?" — API calls processed, documents exported, minutes of compute, anything countable. It's the model behind most modern usage-based SaaS pricing, and it plugs directly into real billing, not just a dashboard number.

The event endpoint

Your app calls one endpoint every time a billable action happens — a real request, not a wrapped SDK method (there isn't one yet; a plain HTTP POST is all you need):

POST /api/v1/meter
Content-Type: application/json

{
  "licenseKey": "PERMIT-XXXX-XXXX-XXXX-XXXX",
  "eventName": "document_exported",
  "quantity": 1,
  "meta": { "format": "pdf" }
}

quantity defaults to 1 and accepts up to 100,000 in one call (batch a day's worth of usage in one request instead of firing thousands of individual calls). meta is optional, freeform JSON, stored alongside the event for your own later analysis — it isn't used for billing itself.

Event names must be configured first

This is the one real gotcha: an event name has to be registered for your tenant before the API will record it. An unrecognized eventName returns {"recorded": false, "message": "Event name is not configured for this tenant."} — this isn't a bug, it's a deliberate guard (TenantMeterPriceConfigs) so a typo'd or fabricated event name from a compromised client can't quietly inflate a customer's usage numbers or trigger billing you never configured. Set up each event name once in the admin panel before your app starts calling it.

How usage becomes a real charge

Each configured event name maps to a Stripe metered price. When a usage event is recorded, it's aggregated and reported to Stripe against that price, and Stripe bills the customer at the end of their billing period based on total usage — the same mechanism Stripe's own metered billing uses for any product, not a custom invoicing layer PermitCore built on the side. This means your Stripe dashboard is the actual source of truth for what a customer was charged, and PermitCore's usage dashboard (aggregated per event name, with daily breakdowns) is there for your own visibility into the same numbers.

What happens to an expired or inactive license

A metered event against an inactive or expired license is rejected before it's ever recorded ({"recorded": false, "message": "License expired."}) — usage can't accrue against a license that shouldn't be billable anymore. This is the same underlying LicenseKey.IsActive/ExpiresAt state every other license type uses; metered licensing doesn't get a separate lifecycle, it's a billing mechanism layered on top of a normal license.

When metered billing makes sense

It fits naturally when your product's value scales with usage rather than seats — an API you charge per call, a data-processing tool billed per document, an AI feature billed per generation. It's a poor fit for products where usage isn't a meaningful proxy for value (a desktop tool used once a day vs. fifty times a day usually isn't fifty times more valuable) — in that case node-locked or floating licensing is the more natural model.

Previous: Feature-Based Licensing Next: Why MAC Addresses Are Bad Hardware IDs