Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.unprice.dev/llms.txt

Use this file to discover all available pages before exploring further.

Unprice meters usage within billing periods. That means usage is always interpreted relative to the current billing cycle, whether you bill monthly, yearly, or on a custom reset schedule. The most important design decision is this: meters are for usage entitlements. Some features need a stream of events and an aggregation rule. Others are simply granted access and do not need a meter at all.

1. Core Concepts: Events vs. Meters vs. Features

These three terms work together, but they are not interchangeable:
TermWhat it isWhat it answers
EventAn immutable record of activity sent from your application”What happened?”
MeterA period-scoped rule that aggregates usage events for a usage entitlement”How much usage happened this billing period?”
FeatureA customer-facing capability in your product”What is the customer paying for or limited on?”

Events

Events are the raw, granular data points your application sends to Unprice.
  • They are append-only records of activity.
  • They should describe what happened at the moment it happened.
  • They are the input to usage metering.
Examples:
  • api.request_made
  • ai.tokens_generated
  • storage.snapshot_taken

Meters

Meters are the rules that turn a stream of events into a number for the current billing period.
  • A meter is only relevant for usage entitlements.
  • A meter decides how incoming events should be aggregated during the active billing cycle.
  • The result is what Unprice uses for billing, limits, and reporting on usage-based features.
Examples:
  • “Count every API request this month”
  • “Sum all bandwidth transferred this month”
  • “Track the highest storage watermark reported this month”

Features

Features are the actual capabilities you sell, limit, or expose to customers.
  • A feature might be a metered capability, like API requests.
  • A feature might also be simple access, like SSO or priority support.
  • A feature can exist without any meter if it is not usage-based.
Examples:
  • pro-api-access
  • database-storage
  • priority-support
Not every entitlement has a meter. Usage entitlements need events plus an aggregation method. Non-usage entitlements such as flat access or fixed package access can exist without any aggregation rule.

2. Supported Aggregation Methods

Aggregation methods apply to usage entitlements only. Every meter evaluates usage inside the current billing period and resets automatically when that period ends.
MethodWhat it does during the periodGood for
sumAdds the values of a field across all events in the periodBandwidth, tokens, transferred GB
countCounts how many matching events were received in the periodAPI calls, jobs run, emails sent
maxKeeps the highest value reported in the periodPeak storage, peak active users
lastUses the most recent value reported before billing closes the periodActive seats at period end, latest balance snapshot

sum

Use sum when each event contributes a numeric amount to the period total.
  • Best for values that accumulate naturally.
  • Common examples are tokens, bytes, seconds, or credits consumed.
  • The total resets at the end of the billing period.

count

Use count when the important signal is the number of events, not the numeric value inside each event.
  • Best for request-style or action-style metrics.
  • Common examples are API calls, export jobs, or webhook deliveries.
  • The count resets at the end of the billing period.

max

Use max when you care about the highest reported value reached during the period.
  • Best for high-watermark billing.
  • Common examples are storage, peak concurrent users, or largest queue depth.
  • The recorded maximum resets at the end of the billing period.

last

Use last when you care about the most recent reported value before the invoice or reset boundary.
  • Best for end-of-period state.
  • Common examples are active seats, enabled workspaces, or the final storage total at billing time.
  • The stored value resets with the next billing period after that period closes.

3. Handling “Stateful” Metrics (The “Fast Cache, Slow Truth” Pattern)

Some usage is naturally event-shaped. Other usage is really a snapshot of a changing state. Treating those two categories the same is one of the fastest ways to create billing drift.

Streaming metrics

Streaming metrics are actions that happen one event at a time. Examples:
  • API calls
  • tokens generated
  • emails sent
  • files processed
For these metrics, report usage directly from the request path as the action happens.
const { result, error } = await unprice.customers.reportUsage({
  customerId: "cus_1234567890",
  featureSlug: "api-requests",
  usage: 1,
  idempotenceKey: request.id,
  metadata: {
    route: "/v1/chat/completions",
    method: "POST"
  }
});

if (error) {
  throw error;
}

if (!result?.allowed) {
  return new Response("Usage limit reached", { status: 429 });
}
If the feature is truly “one event equals one unit,” configure the meter with count. If each event carries a variable amount, use sum.

Stateful metrics

Stateful metrics represent a current total that lives in your own database or storage system. Examples:
  • rows stored
  • active users
  • provisioned seats
  • bytes stored
For these metrics, the anti-pattern is sending create/delete deltas like +1 on insert and -1 on delete. Why this causes problems:
  • retries can double-apply a change
  • dropped network requests can lose a decrement
  • race conditions can reorder updates
  • backfills and imports can skip historical events
  • deletes are often harder to observe reliably than creates
Instead, use the Fast Cache, Slow Truth pattern.

Real-time enforcement: Fast Cache

Use your own application or cache layer to enforce hard limits immediately.
  • Keep the hot path in systems you control, such as Redis or your primary application database.
  • Decide whether to allow or block the request before doing expensive work.
  • Treat this as the fast operational check, not the source of billing truth.
Example: if you allow at most 10 active projects on a plan, check that constraint inside your app before creating project 11.

Accurate billing: Slow Truth

Run a background job on a schedule, query the authoritative total from your database, and report that absolute total to Unprice as a snapshot event.
  • Run hourly or daily, depending on how quickly the metric changes.
  • Send the full current value, not a delta.
  • Configure the meter as max if you bill on the highest watermark reached during the period.
  • Configure the meter as last if you bill on the latest value at period close.
async function syncActiveSeats(customerId: string) {
  const row = await db.query<
    { active_seats: number }
  >(
    `
      SELECT COUNT(*)::int AS active_seats
      FROM seats
      WHERE customer_id = $1
        AND revoked_at IS NULL
    `,
    [customerId]
  );

  const activeSeats = row[0]?.active_seats ?? 0;

  await unprice.customers.reportUsage({
    customerId,
    featureSlug: "active-seats",
    usage: activeSeats,
    idempotenceKey: `active-seats:${customerId}:${new Date().toISOString().slice(0, 13)}`,
    metadata: {
      source: "cron",
      metricType: "snapshot"
    }
  });
}
This same pattern works for storage totals too:
SELECT SUM(bytes_used) AS total_bytes
FROM files
WHERE customer_id = $1;
Use max when you care about the highest watermark during the month. Use last when you care about the value that exists at the moment billing closes the period.

4. How to Handle “Lifetime” Limits (e.g., Lifetime Free Trials)

Sometimes the business rule you want is “never reset this allowance.” Treat that as an entitlement or grant configuration decision, not as a different metering period. Recommended pattern:
  • Create a normal usage feature for the activity you want to track.
  • Use a standard usage meter for that feature.
  • Configure the customer’s grant or entitlement so it does not expire and does not reset.
  • Let the grant carry the long-lived allowance while the meter continues to process usage events normally.
Example:
  • You want to give every free customer 10,000 API calls total.
  • Keep the feature as api-requests.
  • Meter the activity as normal usage.
  • Create a non-expiring grant with a limit of 10,000.
This keeps your billing architecture consistent:
  • events still describe activity
  • meters still aggregate usage
  • entitlements and grants still define what the customer is allowed to consume

Best Practices

  • Use meters only for usage entitlements.
  • Use count or sum for streaming activity reported directly from the request path.
  • Use scheduled snapshot events for stateful resources.
  • Use max for high-watermark billing and last for end-of-period state billing.
  • Enforce hard operational limits in your own app or cache layer first.
  • Model long-lived allowances as grant or entitlement rules rather than inventing a separate metering model.
Next steps:
  • Read Entitlements to understand how features become customer access rules.
  • Read Report Usage for the SDK contract and request shape.