Skip to content

How Extraction Runs

Extractor rules do more than read JSON paths. At runtime, Meterry normalizes the event, builds charge items, evaluates ordered metric expressions, and applies extractor-attached pricing when configured.

Meterry compiles JSON paths and CEL expressions when a rule set is created, published, loaded, or first seen by the runtime cache. Event processing uses those compiled accessors and programs instead of parsing rule expressions on every event.

For each raw event, extraction runs in this order:

  1. Parse x-billing, if present. Valid reported items reserve their metric names, so extractor-generated items with the same metric are skipped.
  2. Initialize dimensions from string metadata, then run configured dimensions extractors. A dimension can read from path, use a static value, fall back to default_value, or fail normalization when required is true.
  3. Resolve the subject. A complete ingest-level subject_type and subject_id pair wins immediately. Otherwise execute the precompiled subject.type_path and subject.id_path accessors, with each path value taking priority over its matching default_type or default_id; required is checked after both fallbacks, and incomplete optional pairs are discarded.
  4. Walk charge_item_extractors in configuration order. Each extractor reads its path into an initial quantity, skips missing optional metrics when skip_if_missing is true, or starts from 0 when it relies only on quantity_expr.
  5. Append valid x-billing.items after extractor-generated items.
  6. Build the items context, a same-event map indexed by metric. At this point it contains every extractor and reported item with its initial quantity.
  7. Evaluate quantity_expr for extractor-generated items in charge item order. When a quantity expression succeeds, Meterry writes the new quantity back to the current item and to items[metric]['quantity'].
  8. Evaluate extractor-attached pricing for extractor-generated items that have amount_expr. If a same-metric x-billing.pricing_hints entry exists, it overrides the default unit_price_expr value before amount_expr runs.
  9. Finalize charge items with stable IDs, subject fields, extractor rule set ID, and version.

Because items is keyed by metric, expressions can reference other metrics from the same event:

{
"name": "billable-prompt-tokens",
"metric": "prompt_tokens",
"path": "$.usage.prompt_tokens",
"type": "number",
"unit": "token",
"quantity_expr": "dec_sub(dec(item['quantity']), dec(items['cache_read_tokens']['quantity']))"
}

The context is built before quantity_expr runs, so an expression can read another metric’s initial path-extracted quantity. If one calculated metric depends on another calculated metric, put the dependency first in charge_item_extractors, because successful quantity_expr results are written back in order.

quantity_expr, unit_price_expr, and amount_expr are CEL expressions. JSON paths only belong in subject.type_path, subject.id_path, dimension path, and charge item path; do not put $.usage.prompt_tokens inside an expression.

Decimal expressions must return a decimal string. Use the decimal helpers for money-sensitive math:

Function Use
dec(value) Convert a number or string into a decimal string.
dec_add(left, right) Add two decimal strings.
dec_sub(left, right) Subtract the right decimal string from the left one.
dec_mul(left, right) Multiply two decimal strings.
dec_div(left, right) Divide two decimal strings. The divisor cannot be zero.

Wrap literals and runtime numbers with dec(...), then compose helpers:

dec_mul(dec_div(dec(item['quantity']), dec('1000000')), dec(item['unit_price']))

This calculates quantity / 1,000,000 * unit_price, which is the common pattern for token prices quoted per 1M tokens.

If a virtual metric depends on the rated values of other items in the same event, see Analytics-Only for the control.analytics_only flag and how it controls whether a virtual revenue aggregator or supplier-cost item is debited. The full control block, including allow_voucher, is covered under Charge-Item Control.

Expressions receive this context:

Variable Meaning
dimensions Extracted labels, such as dimensions['provider'] or dimensions['model'].
item['metric'] The current charge item metric.
item['quantity'] The current charge item quantity. quantity_expr can replace it.
item['unit'] The current unit, such as token, request, call, or minute.
item['unit_price'] The current unit price. It starts at 0, then comes from pricing_hints or unit_price_expr.
item['pricing_unit'] The denominator for unit pricing. It defaults to 1; pricing hints can set it to values like 1000 or 1000000.
item['attributes'] Attributes attached to the current charge item.
items['metric_name'] Other same-event item snapshots indexed by metric.

Fixed one request per event:

dec('1')

Tiered unit price:

item['quantity'] > 200000 ? dec('0.001') : dec('0.002')

Amount formula that supports either default unit_price_expr or a same-metric x-billing.pricing_hints value:

dec_mul(dec_div(dec(item['quantity']), dec(item['pricing_unit'])), dec(item['unit_price']))