Skip to main content
Filters are dimensions of your metering. They let you slice a single billable metric along one or more attributes and price each slice independently on your plans. One metric, many ways to cut it. No duplicated metrics, no schema changes. A filter is a key plus a list of allowed values attached to a billable metric. When you send an event, the values live inside properties, and Lago matches them against the filter definition to route usage to the right charge on the plan.

Why filters matter

You won’t nail your pricing model on version one. As your product evolves, so will the way you measure usage. Lago’s metering engine and rate engine are decorrelated, which means you can evolve your dimensions and your pricing independently, without forcing a rewrite of either:
  • Metering: What you collect and how you slice it (the filter definition on the billable metric).
  • Rating: How each slice is priced (the charge on the plan).
Most billing systems couple the two. Change how you measure, and you change how you charge. Lago keeps them separate, so your product team can add a new dimension (e.g. a new region) without waiting on pricing, and your finance team can add a new rate without waiting on engineering. The two teams iterate independently.
This is different from retroactive pricing (backdating a rate on existing usage) and different from replacing events. Filters are about adding new ways to slice an existing metric, then pricing the new slices independently.

Use cases

You’ve been ingesting events and billing customers. Now you need to evolve the measurement:
  • New region launch. You meter compute hours. Now you want to price US and EU separately.
  • New model added. You meter tokens. Now you want to split by model and charge accordingly.
  • New tier of service. You meter API calls. Now you want to separate real-time from batch.
These are dimension additions on an existing metric, not new metrics. Lago handles them natively.
You meter compute hours and launch in Europe. EU infrastructure costs more to run, so you want to charge EU customers differently without creating a second metric.
"filters": [
  {
    "key": "region",
    "values": ["us-east-1", "us-east-2", "eu-west-1", "eu-central-1"]
  }
]
On the plan, add two charges on the same compute metric — one for the US regions, one for the EU regions — each at its own rate.
You meter tokens. Different models have very different costs, so gpt-4 should not be priced the same as llama or mixtral.
"filters": [
  {
    "key": "model",
    "values": ["llama", "mixtral", "gpt-4", "claude-sonnet"]
  }
]
Each model becomes its own charge on the plan, with its own per-token rate.
You meter API calls. Real-time requests are more expensive to serve than batched ones.
"filters": [
  {
    "key": "tier",
    "values": ["realtime", "batch"]
  }
]
Filters can be combined. A gpt-4 call in Europe is not priced the same as a llama call in the US.
"filters": [
  {
    "key": "region",
    "values": ["us-east-1", "eu-west-1"]
  },
  {
    "key": "model",
    "values": ["llama", "gpt-4"]
  }
]
Each event specifies both region and model. On the plan, you can create a charge per combination — one metric, four prices, no duplicated events.

How it works

  1. Add a new filter key or value to the existing metric. The metric itself doesn’t get a new version. You are extending its dimensions.
  2. Events already in Lago pick up the new dimension, as long as they haven’t been invoiced yet.
  3. Add a new charge on the plan for the new filter value. This is a separate step in the rate engine, independent from the metric change.
  4. Invoice as usual. New dimensions appear on the next invoice. Already-invoiced periods are not touched.
The separation between steps 1–2 (metering) and step 3 (rating) is the point. You can add dimensions without committing to a new price. You can add prices without changing what you measure.

Worked example

1

Day 1

You define a metric compute_hours with a filter on region. Values: us-east-1.
2

Day 15

You send 10,000 events. They accumulate with region: us-east-1.
3

Day 20

You launch in Europe. You add eu-west-1 as a filter value on the same metric. No new metric version. No schema change.
4

Day 21

You add a new charge on the plan for region: eu-west-1 at a different rate.
5

Day 22

Customers using EU infrastructure send events with region: eu-west-1. They accumulate against the new charge. Invoices for the current billing period include both.
If you had invoiced on Day 18, the US events from that period would be locked. Any events from Day 15–17 that haven’t been invoiced yet still pick up the new logic.

What can and cannot change retroactively

The hard constraints are the metric code and the aggregation type. They must exist in your organization at the time events are ingested. Everything else is flexible.
ChangePre-invoice eventsAlready-invoiced events
New filter value on an existing metric
New filter key on an existing metric
Add an existing metric as a new charge on a plan✅ (past events with matching code are picked up)
New billable metric with a new code❌ (past events were ingested under a different code)
Price change on an existing charge✅ (see retroactive pricing)Contact CS
The single most important design decision: create the billable metric codes you might ever need at the org level on day 1, even if you don’t plan to charge on them yet. Once a code exists and events are flowing, the entire rating layer is flexible retroactively (for pre-invoice events). The constraint is the metric code, not the charge.

Dimension evolution vs retroactive pricing

These solve different problems:
Dimension evolutionRetroactive pricing
What changesWhat you measure (new filters, group keys)What you charge for existing measurements
Self-serve✅ via UI or APIPre-invoice: self-serve. Invoiced: contact CS.
Affects invoiced periodsRequires CS for corrections

Design guidance

When defining a billable metric at the start of a project:
  • Use a broad name that will absorb future dimensions (compute_events rather than compute_us_events).
  • Include dimensions you might price on even if you’re not pricing on them yet. Send region as a property even if you only have one region today — you can add the filter key and charges later, but only if the events already carry the property.
  • You can always add filters and group keys later, but you cannot retroactively apply a different metric code to past events.
Get the metric code right on day one. Evolve everything else later.

Create filters

Your company provides DevOps services and you want to charge your customers for compute capacity by the hour. In your Lago account, you create a compute billable metric that calculates the total number of hours (i.e. SUM(properties.hours)). As your customers can choose from different cloud providers and define a region, you need to filter usage records (i.e. events) according to the provider and region. On the configuration page of your billable metric, you can define two filters: provider and region, with all the necessary values (see snippet below).
  1. Create a new billable metric;
  2. Add a new filter; and
  3. Define your different filters.
Below is an example of an event including two group values for the billable metric described above:
Event including a group value
LAGO_URL="https://api.getlago.com"
API_KEY="__YOUR_API_KEY__"

curl --location --request POST "$LAGO_URL/api/v1/events" \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data-raw '{
    "event": {
      "transaction_id": "event_001",
      "external_customer_id": "customer_1234",
      "code": "compute",
      "timestamp": 1668461043,
      "properties": {
        "hours": 0.07,
        "provider": "aws",
        "region": "us-east-1"
      }
    }
  }'
And an event for the tokens metric with a model dimension:
Event with a model dimension
curl --location --request POST "$LAGO_URL/api/v1/events" \
--header "Authorization: Bearer $API_KEY" \
--header 'Content-Type: application/json' \
--data-raw '{
    "event": {
      "transaction_id": "event_002",
      "external_customer_id": "customer_1234",
      "code": "tokens",
      "timestamp": 1668461043,
      "properties": {
        "tokens": 1250,
        "model": "gpt-4"
      }
    }
  }'
Values are case-sensitive. If you don’t use the exact value when pushing events, they will not be taken into account. Following our example: the expected value is "aws" and "AWS" is an invalid value.
You can also create billable metrics with dimensions via the API.

Edit filters

You can edit billable metric filters associated with existing subscriptions. It’s important to note that making changes to these metric filters can have an impact on all plans where this billable metric is defined as a charge. Here’s an example to illustrate the impact of editing a billable metric:
From Payload A:
{
  "billable_metric": {
    "name": "gigabyte",
    "code": "gigabyte",
    "aggregation_type": "sum_agg",
    "field_name": "total",
    "filters": [
	    {
	      "key": "region",
	      "values": [
	        "usa",
	        "europe",
	      ]
	    }
    ]
  }
}

To Payload B:
{
  "billable_metric": {
    "name": "gigabyte",
    "code": "gigabyte",
    "aggregation_type": "sum_agg",
    "field_name": "total",
    "filters": [
	    {
	      "key": "region",
	      "values": [
	        "USA",
	        "europe",
	        "africa"
	      ]
	    }
    ]
  }
}
Note that each filter’s keys and values are case-sensitive. Here’s how Lago handles these changes:
  1. Since "region": "europe" remains the same between both payloads, this filter remains in the billable metric.
  2. As "region": "usa" is present in Payload A but not in Payload B, this filter is removed from the billable metric.
  3. As "region": "USA" is not present in Payload A but is present in Payload B, this filter will be created in the billable metric.
  4. Similarly, as "region": "africa" is not present in Payload A but is present in Payload B, this filter will be created in the billable metric.
When this billable metric is associated with charges, editing it will impact all plans where it is defined.
  • If an existing filter combination remains the same (case 1), Lago will retain this specific filter from the filters combination in all associated charges.
  • If an existing filter combination is removed from the billable metric (case 2), Lago will remove this specific filter from the filters combination in all associated charges.
  • If a new filter combination is created in the billable metric (case 3 and 4), Lago will not automatically add this filter in the filters combination in all associated charges; you will need to add them manually.