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.
Runtime order
Section titled “Runtime order”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:
- Parse
x-billing, if present. Valid reported items reserve their metric names, so extractor-generated items with the same metric are skipped. - Initialize dimensions from string metadata, then run configured
dimensionsextractors. A dimension can read frompath, use a staticvalue, fall back todefault_value, or fail normalization whenrequiredis true. - Resolve the subject. A complete ingest-level
subject_typeandsubject_idpair wins immediately. Otherwise execute the precompiledsubject.type_pathandsubject.id_pathaccessors, with each path value taking priority over its matchingdefault_typeordefault_id;requiredis checked after both fallbacks, and incomplete optional pairs are discarded. - Walk
charge_item_extractorsin configuration order. Each extractor reads itspathinto an initial quantity, skips missing optional metrics whenskip_if_missingis true, or starts from0when it relies only onquantity_expr. - Append valid
x-billing.itemsafter extractor-generated items. - Build the
itemscontext, a same-event map indexed by metric. At this point it contains every extractor and reported item with its initial quantity. - Evaluate
quantity_exprfor extractor-generated items in charge item order. When a quantity expression succeeds, Meterry writes the new quantity back to the current item and toitems[metric]['quantity']. - Evaluate extractor-attached pricing for extractor-generated items that have
amount_expr. If a same-metricx-billing.pricing_hintsentry exists, it overrides the defaultunit_price_exprvalue beforeamount_exprruns. - Finalize charge items with stable IDs, subject fields, extractor rule set ID, and version.
Ordered metric context
Section titled “Ordered metric context”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.
Decimal expressions
Section titled “Decimal expressions”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.
Expression context
Section titled “Expression context”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. |
Recommended patterns
Section titled “Recommended patterns”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']))