# Meters

:::note{title="Beta"}

API Monetization is in beta and free to try. The APIs are stable but should be
evaluated in non-production environments first. To go to production, contact
[sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
announced.

:::

Meters aggregate usage data from your API. They watch for specific event types,
extract numeric values, and sum them over configurable time windows.

## How Meters Work

A meter is configured with:

- **Event type** - Which events to process (e.g., `requests`, `tokens`)
- **Value property** - JSONPath to extract the numeric value from event data.
  Events use `$.total` as the standard value property.
- **Aggregation** - How to combine values (typically `SUM`)

When events are ingested, the meter matches events by type, extracts the
specified value, and aggregates it per customer subscription over time.

## Common Examples

### API Request Counting

Track the total number of API requests:

```json
{
  "slug": "api_requests",
  "name": "API Requests",
  "eventType": "api_requests",
  "aggregation": "SUM",
  "valueProperty": "$.total"
}
```

Each event identifies the subscription being metered, the actor that drove the
consumption, and how much to record. The `subscription` field carries the
subscription ID, the `subject` field identifies the actor, and `data.total`
carries the quantity:

```json
{
  "id": "5c10fade-1c9e-4d6c-8275-c52c36731d3c",
  "specversion": "1.0",
  "type": "api_requests",
  "source": "monetization-policy",
  "subject": "acme-prod",
  "subscription": "01KNVXHQG356VA7T7W0V9N21GH",
  "data": {
    "total": 1
  }
}
```

:::note

`subject` identifies _who_ consumed the subscription's entitlements on this
request — typically the API key's consumer name, the end-user id, or another
stable per-actor identifier. It is **not** the subscription id (use the
`subscription` field for that) and is not used to route billing. Its purpose is
to let you break down usage within a subscription so you can see which key,
user, or agent drove the consumption — a single subscription will commonly emit
events with many different `subject` values. See
[Monetization Policy](./monetization-policy.md) for how usage is recorded.

:::

### Token Usage

Track token consumption for AI applications:

```json
{
  "slug": "tokens",
  "name": "Token Usage",
  "eventType": "tokens",
  "aggregation": "SUM",
  "valueProperty": "$.total"
}
```

The meter aggregates events from the gateway; the per-request quantity comes
from the `MonetizationInboundPolicy`. Set a fixed cost per request in the
policy's `meters` option, or call
[`MonetizationInboundPolicy.setMeters`](./monetization-policy.md#dynamic-metering)
from a custom outbound policy to report a value derived from the response — for
example, the actual token count an LLM returned. An event for a request that
consumed 50 tokens looks like this:

```json
{
  "id": "a1b2c3d4-5678-4abc-8def-1234567890ab",
  "specversion": "1.0",
  "type": "tokens",
  "source": "monetization-policy",
  "subject": "acme-prod",
  "subscription": "01KNVXHQG356VA7T7W0V9N21GH",
  "data": {
    "total": 50
  }
}
```

### Data Transfer

Track bytes transferred:

```json
{
  "slug": "data_transfer",
  "name": "Data Transfer (bytes)",
  "eventType": "data_transfer",
  "aggregation": "SUM",
  "valueProperty": "$.total"
}
```

Each event reports the number of bytes transferred:

```json
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "specversion": "1.0",
  "type": "data_transfer",
  "source": "monetization-policy",
  "subject": "acme-prod",
  "subscription": "01KNVXHQG356VA7T7W0V9N21GH",
  "data": {
    "total": 4096
  }
}
```

## Naming Consistency

The meter `eventType` must match the key used in three places:

1. The meter's `slug` and `eventType`
2. The key in the monetization policy's `meters` configuration
3. The `featureKey` on the plan's entitlement

If these don't match, usage is not tracked correctly against the subscription's
entitlements.

## Creating a Meter

```shell
curl \
  https://dev.zuplo.com/v3/metering/$BUCKET_ID/meters \
  --request POST \
  --header "Authorization: Bearer $ZAPI_KEY" \
  --header "Content-Type: application/json" \
  --data @- << EOF
{
  "slug": "api_requests",
  "name": "API Requests",
  "eventType": "api_requests",
  "aggregation": "SUM",
  "valueProperty": "$.total"
}
EOF
```

## API Reference

For complete API operations (list, get, update, delete), see the
[Meters API Reference](../../api/metering-meters).
