Skip to main content

Meters

Meters define how events are aggregated into billable usage. They separate what to measure from how to price, so the same meter can be reused across different pricing configurations and customers.

What is a Meter?

A meter is a reusable configuration that specifies:
  • Which events to include — using event type filters and property filters
  • How to aggregate them — COUNT, SUM, MAX, or MIN
  • Which property to aggregate — for SUM, MAX, and MIN
Multiple pricing configurations can reference the same meter. Usage events are matched to meters, not to pricing directly.

Defining a Meter

There are two ways to define what a meter measures: Use eventTypeFilter, propertyFilters, and aggregationKey to declaratively specify which events contribute to the meter and how they’re aggregated.
{
  "displayName": "API Calls",
  "aggregationType": "COUNT",
  "eventTypeFilter": {
    "include": ["api_call"]
  }
}
{
  "displayName": "LLM Token Usage",
  "aggregationType": "SUM",
  "aggregationKey": "total_tokens",
  "eventTypeFilter": {
    "include": ["llm_usage"]
  },
  "propertyFilters": [
    { "name": "total_tokens", "exists": true },
    { "name": "model", "include": ["gpt-4", "gpt-4o"] }
  ]
}

Custom SQL

For complex metrics that can’t be expressed with structured filters, provide a raw SQL query. When sql is set, it overrides the structured fields.
{
  "displayName": "Weighted Compute Hours",
  "aggregationType": "SUM",
  "sql": "SELECT SUM(properties['cpu_hours'] * properties['instance_weight']) AS value FROM events"
}
Custom SQL queries must reference the events table and return a single row with a value column. Monk automatically injects organization, customer, and time range filtering — your query only needs to express the metric logic.

Meter Fields

FieldRequiredDescription
displayNameYesHuman-readable name shown in the UI
descriptionNoOptional description of what the meter tracks
aggregationTypeYesHow to compute usage: COUNT, SUM, MAX, MIN
eventTypeFilterNoWhich event types to include/exclude
propertyFiltersNoFilters on event properties (ANDed together)
aggregationKeyNo*Property key to aggregate on
sqlNoCustom SQL query (overrides structured fields when set)
statusactive (accepts events) or inactive (rejects new events)
codeYesUnique identifier within the org (deprecated — will be removed in a future version)
*Required for SUM, MAX, and MIN aggregation types. Omit for COUNT.

Event Type Filter

Controls which event types contribute to this meter.
{
  "eventTypeFilter": {
    "include": ["api_call", "batch_call"]
  }
}
  • include — only events with these types are counted (allowlist)
  • exclude — events with these types are skipped (blocklist)

Property Filters

Narrow down events based on their properties. Each filter is ANDed together.
{
  "propertyFilters": [
    { "name": "region", "include": ["US", "EU"] },
    { "name": "status", "exclude": ["test"] },
    { "name": "customer_tier", "exists": true }
  ]
}
FieldDescription
nameProperty key to match
existsIf true, the property must be present
includeProperty value must be one of these (allowlist)
excludeProperty value must NOT be one of these (blocklist)

Aggregation Types

COUNT

Counts the total number of matching events. No aggregationKey needed.
{
  "displayName": "API Calls",
  "aggregationType": "COUNT",
  "eventTypeFilter": { "include": ["api_call"] }
}
Use CaseExample
API callsEach request is one event
Messages sentEach message is one event
Builds triggeredEach build is one event

SUM

Sums a numeric property across all matching events.
{
  "displayName": "Token Usage",
  "aggregationType": "SUM",
  "aggregationKey": "total_tokens",
  "eventTypeFilter": { "include": ["llm_usage"] },
  "propertyFilters": [{ "name": "total_tokens", "exists": true }]
}
Use CaseAggregation Key
Token consumptiontotal_tokens
Data transferbytes_transferred
Compute hoursduration_hours
Ensure the property referenced by aggregationKey contains numeric values. Non-numeric values are ignored during aggregation.

MAX

Takes the maximum value of a property within the billing period.
{
  "displayName": "Peak Concurrent Users",
  "aggregationType": "MAX",
  "aggregationKey": "user_count",
  "eventTypeFilter": { "include": ["active_users"] },
  "propertyFilters": [{ "name": "user_count", "exists": true }]
}
Use CaseExample
Peak concurrent usersMax of periodic snapshots
High water markMax storage used during period

MIN

Takes the minimum value of a property within the billing period.
{
  "displayName": "Minimum Account Balance",
  "aggregationType": "MIN",
  "aggregationKey": "balance",
  "eventTypeFilter": { "include": ["balance_snapshot"] },
  "propertyFilters": [{ "name": "balance", "exists": true }]
}

Planning Your Meters

Before creating meters, consider:
  1. What actions are billable? — API calls, messages, compute time, storage
  2. How should usage be measured? — Per call (COUNT), per unit (SUM), peak usage (MAX)
  3. What granularity do customers need? — Broad (all API calls) vs. narrow (by endpoint or model)
Start simple. You can always create additional meters later for more granular billing.

Example: SaaS API Product

Billable ActionAggregationEvent Type FilterProperty Filters
API requestsCOUNT{ include: ["api_call"] }
LLM token usageSUM of total_tokens{ include: ["llm_usage"] }[{ name: "total_tokens", exists: true }]
Peak active usersMAX of user_count{ include: ["active_users"] }[{ name: "user_count", exists: true }]

Linking Meters to Pricing

Meters don’t have prices — they measure usage. Prices are attached separately through pricing configurations on a plan. A single meter can have different pricing for different customers or plans. For example, a meter for API calls might cost $0.001/call on the Starter plan and $0.0005/call on the Enterprise plan. See Pricing for details on pricing models.

Dimensional Pricing with Group Keys

For advanced use cases, you can configure group keys on a meter to enable dimensional pricing. Group keys specify which event properties Monk uses to break down usage for different rates.
{
  "displayName": "AI Calls",
  "aggregationType": "COUNT",
  "eventTypeFilter": { "include": ["ai_call"] },
  "groupKeys": ["region", "call_outcome"]
}
With group keys configured, you can attach a rate card to the pricing that defines different rates per dimension combination:
  • region=US, call_outcome=resolved → $2.00/call
  • region=EU, call_outcome=escalated → $7.50/call
  • Fallback → $4.00/call
See Dimensional Pricing for the full guide.

Next Steps

How Usage-Based Billing Works

See how meters fit into the full billing flow

Create Your First Meter

Step-by-step guide

Dimensional Pricing

Different rates by event attributes

Meters API

API reference

Events

How events feed meters

Pricing

Attach prices to meters