Pricing
HUME offers declarative JSON plans and optional Luau hooks. New here? Pick your scenario in Recipes, then read Plan extensions for field details. Luau: pricing ctx, classify ctx. API: HTTP API.
Catalog vs plan: metrics and features in the tenant catalog define what you bill;
each plan sets its own included_units, overage, and groups. Reusing api_requests on Starter and Pro does not sync quotas — Catalog vs plans explains the split.
Why Luau
Most plans work fine with declarative JSON — tiers, groups, classify routes, and SaaS billing blocks need no code. Luau is there when rules outgrow static config: progressive volume discounts, cross-metric formulas, or custom invoice line items.
- Readable logic. Luau uses a small Lua-family syntax. Product engineers can read and write pricing rules without learning a proprietary rules language or spreadsheet macros.
- One script, two hooks. The same plan manifest defines the catalog (
plan,metric,tier) and optional runtime hooks (pricing,classify) — no separate config files to keep in sync. - Sandboxed by design. Tenant scripts run in an isolated VM: no network, filesystem, or
require. Strict timeouts (2 ms for classify, 250 ms for pricing) keep usage ingest and invoice generation predictable. - Logic stays in billing. Unlike outbound webhooks on every usage event, classify and pricing run inside HUME — no extra HTTP round-trip, no callback infrastructure to operate, no race between your app and the meter.
- JSON when you can, Luau when you must. Use Plan extensions for shared quotas, JSON classify, and SaaS billing. Add Luau only when built-in math is not enough — pricing examples, classify examples.
Pricing strategies
From highest to lowest abstraction:
1. Pricing packages (recommended)
POST /pricing/packages — one declarative payload creates metrics, features, and a plan
atomically. Without pricing_lua, built-in Go logic handles invoicing and JSON classify at
ingest. Full field reference: Plan extensions.
For an entire catalog slice in one shot, use POST /pricing/bootstrap. It accepts the same
plan shapes as packages, plus a compact syntax that keeps payloads small:
priceinstead ofmonthly_pricemetricsas a map (code → {included, overage})featuresas a string array (["exports", "sso"])- metric
name/unitinferred from code when omitted (api_requests→ unitrequest)
Shared metrics are created once and reused across plans. The verbose array format still works inside bootstrap entries when you need explicit names or tiers.
2. Luau scripts
Pass pricing_lua to POST /pricing/packages (field name is historical). The
engine runs Luau (Lua-family syntax) in a restricted sandbox. JSON-only packages
skip the script and use built-in tier/proration logic at invoice time. Script errors return 400 with the compiler or runtime message.
Limits
| Compile | classify (usage) | pricing (invoice) | |
|---|---|---|---|
| Max script size | 64 KiB | ||
| Opcode budget | — | 512 (whole module) | — |
| Wall timeout | — | 2 ms | 250 ms |
| Stdlib | base, table, string, math | ||
| Globals after setup | frozen (Sandbox()) | ||
| Host API | DSL helpers | classify ctx | DSL helpers + pricing ctx |
Not available: os, io, debug, coroutine, require, network, filesystem. Runtime errors and timeouts fail the operation (usage
rejected or invoice generation fails).
Catalog builders
Define plan price, metered metrics, and entitlement features.
| Method | Returns | Purpose |
|---|---|---|
plan(code, name, opts) | plan table | Root object returned by the script |
metric(code, name, unit, opts) | metric table | Billable meter on the plan |
feature(code, name, opts) | feature table | Entitlement flag; enabled defaults to true |
tier(from, to, price) | tier table | Volume step; omit to for open-ended top tier |
plan(code, name, opts)
opts.price/opts.monthly_price— base fee, integer abstract unitsopts.metrics—list(metric(...), ...)opts.features—list(feature(...), ...)opts.pricing— optionalfunction(ctx); overrides built-in invoice mathopts.classify— optionalfunction(ctx); runs at usage ingest (see below)
Starter plan — included units + flat overage:
Tiered overage:
Invoice line builders
Used inside pricing(ctx).
| Method | Returns | Purpose |
|---|---|---|
list(...) / lines(...) | array | Build arrays; skips nil |
line(desc, amount, opts) | line table | One invoice row; amount is integer |
prorate(amount, ratio) | integer | Rounded proration — pair with ctx.window_ratio |
usage(ctx, code) / included(ctx, code) | integer | Read from ctx.usage / ctx.included |
pricing(ctx) — invoice generation
Called once per billing period overlapping the invoice window. Returned lines replace built-in fee + usage math. Examples: Luau pricing ctx → Examples. Field reference: Luau pricing ctx. Max 100 lines.
classify(ctx) — usage ingest
Runs before a usage event is committed when the user's active plan defines classify. Reroute metrics (peak/off-peak, bulk vs standard) or reject over-limit
requests with { allow = false, reason = "..." }. Examples: Luau classify ctx → Examples. Field
reference: Luau classify ctx.
3. Manual plans
POST /plans binds existing metrics by metric_id. No Luau compiler — use POST /pricing/packages for scripts. Does not create catalog entities for you.
Abstract billing units
All money-like fields are integers in abstract billing units. There is no currency field
in the API. Display labels, taxes, discounts, and FX are downstream concerns.
Monthly Tracked Users (MTU)
An MTU is any unique user that triggers at least one metering event or entitlement check in a calendar
month. HUME tracks this automatically: the first billing event for a user in a month creates a
synthetic monthly_tracked_users usage event with quantity = 1.