# Analyze and query meter usage

Learn how to query and analyze meter usage data.

Use the Meter Usage Analytics API to query and analyze your customers’ meter usage data. This enables you to build custom usage dashboards, generate reports, and determine consumption patterns across your meters.

This API is available in public preview.  to request access to this API.

## Query usage data

The Meter Usage Analytics API  returns aggregated usage data for a customer within a specified time interval. You can query for data by time periods, filter by meter dimensions, and query across multiple meters simultaneously.

> The API parameters were updated in the 2025-09-30.preview release. See the [changelog](https://docs.stripe.com/changelog/clover/2025-09-30/update-meter-usage-fields.md) to understand how the request and response shapes changed.

### Fetch usage for a single meter

Retrieve usage data for a specific customer and meter over a time range:

```curl
curl -G https://api.stripe.com/v1/billing/analytics/meter_usage \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d starts_at=1735689600 \
  -d ends_at=1738368000 \
  -d customer={{CUSTOMER_ID}} \
  -d "meters[0][meter]={{METER_ID}}" \
  -d value_grouping_window=day \
  --data-urlencode "timezone=America/New_York"
```

### Fetch usage for a meter filtered and grouped by meter dimension

Query usage data that’s filtered by premium tier and grouped by model:

```curl
curl -G https://api.stripe.com/v1/billing/analytics/meter_usage \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d starts_at=1735689600 \
  -d ends_at=1738368000 \
  -d customer={{CUSTOMER_ID}} \
  -d "meters[0][meter]={{METER_ID}}" \
  -d "meters[0][dimension_group_by_keys][0]=model" \
  -d "meters[0][dimension_filters][tier]=premium" \
  -d value_grouping_window=day
```

### Fetch usage for a meter filtered by tenant

Query usage data that’s filtered by premium tier and grouped by model:

```curl
curl -G https://api.stripe.com/v1/billing/analytics/meter_usage \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d starts_at=1735689600 \
  -d ends_at=1738368000 \
  -d customer={{CUSTOMER_ID}} \
  -d "meters[0][meter]={{METER_ID}}" \
  -d "meters[0][tenant_filters][user_id]=a8238bf39a1" \
  -d value_grouping_window=day
```

### Fetch usage across multiple meters

Query usage across multiple meters with different filters and groupings:

```curl
curl -G https://api.stripe.com/v1/billing/analytics/meter_usage \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d starts_at=1735689600 \
  -d ends_at=1738368000 \
  -d customer={{CUSTOMER_ID}} \
  -d "meters[0][meter]={{METER_ID_1}}" \
  -d "meters[0][dimension_group_by_keys][0]=model" \
  -d "meters[0][dimension_group_by_keys][1]=tier" \
  -d "meters[1][meter]={{METER_ID_2}}" \
  -d "meters[1][dimension_filters][region]=us-east" \
  -d value_grouping_window=day
```

### Build usage dashboards

You can use the API data to create visualizations, such as stacked charts that show usage across different dimensions. The following example demonstrates how you can structure data for a chart that shows API usage by model:

```curl
curl -G https://api.stripe.com/v1/billing/analytics/meter_usage \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d starts_at=1735689600 \
  -d ends_at=1738368000 \
  -d customer={{CUSTOMER_ID}} \
  -d "meters[0][meter]={{METER_ID}}" \
  -d "meters[0][dimension_group_by_keys][0]=model" \
  -d value_grouping_window=day
```

An example response to this request looks like:

**View response**

```json
{
  "data": [
    {
      "starts_at": 1735689600,
      "ends_at": 1735776000,
      "value": 1500,
      "meter": "mtr_1234567890",
      "dimensions": {
        "model": "gpt-4"
      }
    },
    {
      "starts_at": 1735689600,
      "ends_at": 1735776000,
      "value": 800,
      "meter": "mtr_1234567890",
      "dimensions": {
        "model": "gpt-3.5-turbo"
      }
    },
    {
      "starts_at": 1735776000,
      "ends_at": 1735862400,
      "value": 2100,
      "meter": "mtr_1234567890",
      "dimensions": {
        "model": "gpt-4"
      }
    },
    {
      "starts_at": 1735776000,
      "ends_at": 1735862400,
      "value": 950,
      "meter": "mtr_1234567890",
      "dimensions": {
        "model": "gpt-3.5-turbo"
      }
    }
  ]
}
```

Use this example code to pull data from the API in your back end and display it to users as a stacked bar chart in your front end.

**Your back end**

```javascript
// Step 1: Extract the data from the Stripe API response
const data = stripeApiResponse.data;

// Step 2: Create a dictionary to store the processed data
const processedData = {};

// Step 3: Iterate through the data and organize it by date and model
data.forEach(point => {
  const date = new Date(point.bucket_start_time * 1000).toISOString().split('T')[0];
  const model = point.dimensions.model;
  const value = point.bucket_value;

  if (!processedData[date]) {
    processedData[date] = {};
  }

  processedData[date][model] = value;
});

// Step 4: Create a list of unique models and sort them
const models = [...new Set(data.map(point => point.dimensions.model))].sort();

// Step 5: Prepare the data for charting
const chartData = [];
Object.keys(processedData).sort().forEach(date => {
  const dataPoint = { date };
  let cumulativeValue = 0;

  models.forEach(model => {
    const value = processedData[date][model] || 0;
    dataPoint[`${model}_start`] = cumulativeValue;
    cumulativeValue += value;
    dataPoint[`${model}_end`] = cumulativeValue;
    dataPoint[model] = value; // For simple stacked charts
  });

  chartData.push(dataPoint);
});

// Return chart data for front end chart library usage
return chartData;
```

**Your front end**

```javascript
// Step 1: Fetch usage chart data from your back end
const chartData = await fetch('/api/customer_usage/:customer_id').then(r => r.json());

// Step 2: Extract unique models from the chart data
const models = Object.keys(chartData[0]).filter(key =>
  key !== 'date' && !key.endsWith('_start') && !key.endsWith('_end')
);

// Step 3: Use the chart data to create your stacked bar chart
// Example using D3 or Recharts:
createStackedChart({
  data: chartData.map(point => ({
    date: point.date,
    'gpt-4': point['gpt-4'] || 0,
    'gpt-3.5-turbo': point['gpt-3.5-turbo'] || 0
  })),
  stackKeys: models,
  xKey: 'date',
  title: 'Daily API Usage by Model'
});
```

### Rate limits

The Meter Usage Analytics API has its own rate limit of 100 requests per second per account, which is separate from the Stripe overall API rate limits. If you exceed this limit, the API returns a `429 Too Many Requests` status code.

### Event timestamp granularity

The Meter Usage Analytics API truncates event timestamps to the nearest 15 minutes. For example, an event with `event_timestamp` of `08:42:15` is stored in our analytics database with a timestamp of `08:30:00`.

## Best practices

### Handle data freshness

Usage data might have a slight delay. You can use the `data_refreshed_at` field in the response to understand data freshness. Also consider this latency when building real-time dashboards or alerts.

### Customize your queries

Follow these best practices:

- Use appropriate `value_grouping_window` values to balance granularity with performance.
- Apply `dimension_filters` to reduce data volume when you only need specific segments.
- Query multiple meters in a single request when analyzing related usage patterns.

### Data size limits

To prevent overly large responses, the following limits apply per meter:

- A maximum of 5 `meters`
- A maximum of 2 `dimension_group_by_keys`
- A maximum of 10 `dimension_filters`
- A maximum of 3 `tenant_filters`

### Handle errors

The API returns standard HTTP status codes and structured error responses:

```json
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_time_range",
    "message": "Param start_time should not be greater than end_time"
  }
}
```
