403 PRODUCT_NOT_ENABLED.How the pieces fit
- Meter — a named, countable action:
ai_tokens,api_request,storage_gb. It defines theevent_nameyour systems send and the aggregation (SUM,COUNTorLAST). A meter has no price of its own — at most adefault_pricein USD that plans can inherit. See The Meter Object. - Metered price — the meter attached to a plan: how many units are included per cycle (
credits) and what each unit beyond that costs (price_per_credit, optionally per country). A plan can carry any number of metered prices next to its flat price. See The Metered Price Object. - Subscription — created on that plan as usual. It inherits every metered price; nothing changes in Create Subscription.
- Usage events — one call per unit of work, carrying the
event_name, thesubscription_id, avalueand your ownevent_idfor idempotency. See Report Usage Event. - Renewal — at the end of the billing cycle, Yuno computes the billable quantity (
max(0, usage − credits)) and addsbillable × price_per_creditto the subscription’s renewal charge.
unit_label / plural_unit_label are what usage is displayed in.Quick start
The example builds a “Max” plan at $200/month that includes 10,000 AI tokens and bills $0.002 per token beyond that. Requests use the standardpublic-api-key / private-secret-key headers. X-Idempotency-Key is accepted on every request as elsewhere in the Yuno API, but usage events have their own dedicated dedup key — see Idempotency and timestamps.
Create the meter
event_name your systems will send (lowercase, _ and . allowed) and the aggregation. default_price is optional and must be USD; it saves you from repeating the unit price on every USD plan.201 with the meter, always ACTIVE. Keep its id — you need it to attach the meter to a plan.Attach it to a plan
meter_id, credits (included units per cycle), pricing_strategy and, unless inherited, price_per_credit.price_per_credit is omitted: the plan is USD and the meter has a default_price, so $0.002 applies and the metered price comes back with price_per_credit: null. The plan response and Retrieve Plan now carry the metered price under meters[] (an empty array on plans without meters).credits. Sending { "meters": [ ... ] } to PATCH /subscriptions/plans/{plan_id} does the same for several meters at once — atomically (one bad entry and nothing is attached) — and ignores every other plan field.Subscribe customers to the plan
plan_id. The subscription inherits the plan’s metered prices. Store the subscription id — every usage event references it.Report usage as it happens
event_id is your idempotency key; value is required for SUM and LAST meters and defaults to 1 for COUNT. The subscription must be ACTIVE, TRIALING or PAST_DUE.201 confirms the event was validated and stored:event_id) returns this same response and never counts the 1,500 tokens twice — even if the retry carries a different value, the original is kept.Choosing an aggregation
The aggregation is fixed when you create the meter and decides what a cycle’s quantity means:- SUM — consumption
- COUNT — per call
- LAST — gauge
value. Report the amount consumed by each unit of work.Pricing a meter on a plan
A metered price has three pricing knobs:credits— the units included in the plan each billing cycle. Think “allowance”: the firstcreditsunits are covered by the plan’s flat price.0bills every unit.creditsis measured in the meter’s unit (tokens, requests, GB) and resets each cycle — it is not a prepaid balance or wallet.price_per_credit— the price of each unit beyondcredits, in the plan’s base currency. On a USD plan you can omit it if the meter has adefault_price; the meter’s default then applies and the metered price is returned withprice_per_credit: null. On a non-USD plan, or when the meter has no default, it is required. The currency must always match the plan’sbase_amountcurrency.country_prices— optional per-unit prices by subscriber country (one entry per country), same shape as the plan’s owncountry_prices. A subscriber whose country is not listed paysprice_per_credit. The subscriber’s country comes from the subscription — usage events carry nocountryoraccount_id— socountry_pricesare resolved automatically per subscriber.
pricing_strategy selects how overage is rated, and each strategy carries its own config fields at attach time:
- PER_UNIT — flat rate
- PACKAGE — bundles
- TIERED — graduated
price_per_credit (or the subscriber’s country_prices entry). The default choice for tokens, requests, minutes.PER_UNIT strategies, the meter must be priced in every currency the plan supports — a plan with country_prices in currencies the metered price doesn’t cover is rejected (PLAN_METER_MISSING_CURRENCY), and every priced currency must match one the plan actually uses (PLAN_METER_BASE_CURRENCY_MISMATCH). All computed usage amounts (any strategy) round half-up to 4 decimal places.
What happens at renewal
- Quantity — events whose
occurred_atfalls in the cycle are aggregated with the meter’saggregation(SUM / COUNT / LAST). - Billable units —
max(0, quantity − credits). Unused credits do not roll over. - Amount —
billable × price_per_credit(or the subscriber’scountry_pricesentry). - Charge — the amount is added to the subscription’s renewal charge alongside the plan’s flat price. One charge, one payment, as today. A subscription with usage under its credits pays only the flat price.
Idempotency and timestamps
event_idis required and is your idempotency key. Make it unique per event — a UUID, or the id of the request/response/job it came from — and reuse it on every retry. Yuno stores the first event under that id and answers every replay with the same response, including the originalvalue(a differentvalueon the retry is discarded). Usage is never double counted, however many times you retry. A request withoutevent_idis rejected with400.- Report close to real time, but you can backdate.
occurred_atdefaults to the receive time (returned asreceived_at) and can be up to 35 days in the past; older events are rejected with400. Theoccurred_at(not the receive time) decides which billing cycle the event lands in. X-Idempotency-Keyis accepted, as on the rest of the Yuno API (same key + same body → same response), but it is optional here and not what dedupes usage —event_idis the mechanism that protects billing, and it’s the one that’s required.- One event per request. Aggregate on your side if you produce many small events (for example, sum tokens per response rather than per token) — a
SUMmeter is designed for that. - The subscription must be active.
ACTIVE,TRIALINGandPAST_DUEsubscriptions accept usage (a subscription in payment retries keeps metering); events for aPAUSED,CANCELEDorCOMPLETEDsubscription are rejected with400 SUBSCRIPTION_NOT_ACTIVEand nothing is counted.
Error handling
Validation is synchronous: a rejected event returns400 immediately (lookup failures are 400 too, never 404) and is never counted, so treat non-201 responses as “not recorded” and retry with the same event_id after fixing the request. The codes you will meet most often:
FAQ
Do I need a new plan to add usage pricing to an existing one?
Do I need a new plan to add usage pricing to an existing one?
PATCH /subscriptions/plans/{plan_id} with meters[]). The flat price and existing subscribers’ base amount are unchanged; usage beyond credits starts being billed on their next renewal.Can a plan have several meters?
Can a plan have several meters?
SUM) plus API requests (COUNT) plus storage (LAST), each with its own credits and unit price. Each meter can be attached to a given plan once.What happens if I report usage for a subscription that isn't on a plan with that meter?
What happens if I report usage for a subscription that isn't on a plan with that meter?
meters[] if usage isn’t showing up on the renewal.Can I change a meter's event_name or aggregation?
Can I change a meter's event_name or aggregation?
event_name — names stay reserved even after archiving) and archive the old one with Update Meter (status: INACTIVE). Archived meters reject new events with 400 METER_NOT_FOUND, can’t be attached to plans, and their existing metered prices are frozen; you can reactivate one at any time with status: ACTIVE.Can I remove a metered price from a plan?
Can I remove a metered price from a plan?
credits so no overage is billed.Can I price the meter in a currency other than USD?
Can I price the meter in a currency other than USD?
default_price is USD-only, but a metered price on a BRL plan takes price_per_credit in BRL (required — nothing is inherited for non-USD plans), and country_prices lets you set per-country unit prices in each country’s currency.What happens if I report usage for a paused or canceled subscription?
What happens if I report usage for a paused or canceled subscription?
400 SUBSCRIPTION_NOT_ACTIVE and nothing is counted — only ACTIVE, TRIALING and PAST_DUE subscriptions accept usage. Resume the subscription first (Resume Subscription), then report the usage; you can backdate occurred_at up to 35 days.Can I meter usage without a subscription?
Can I meter usage without a subscription?
subscription_id; usage is billed on that subscription’s renewal.