> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solvapay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Usage Records

> Record and query usage data — the raw data points that power billing, limits, and analytics.

Usage records are timestamped data points stored in a MongoDB timeseries collection. They are the source of truth for all usage tracking in SolvaPay — limit checks, billing calculations, and analytics dashboards all query from the same data stream.

## Record Structure

Each usage record contains:

| Field                  | Type       | Description                                          |
| ---------------------- | ---------- | ---------------------------------------------------- |
| `timestamp`            | `Date`     | When the event occurred                              |
| `metadata.providerId`  | `ObjectId` | The provider that owns this event                    |
| `metadata.meterName`   | `string`   | Which meter this record belongs to (e.g. `requests`) |
| `metadata.customerRef` | `string`   | The customer who triggered the event                 |
| `value`                | `number`   | Numeric value (defaults to `1` for counters)         |
| `properties`           | `object?`  | Arbitrary key-value tags for filtering and analysis  |

Usage records are immutable. Once recorded, they cannot be modified or deleted. MongoDB's timeseries engine automatically compresses and indexes records by metadata and time for efficient aggregation.

## Recording Usage

Usage is recorded via `UsageService.recordUsage()`, which writes to the Usage timeseries collection.

### Via SDK Endpoint

Record usage directly from your backend using the SDK API:

```bash theme={null}
# Record a single event
POST /v1/sdk/meter-events
{
  "customerRef": "cus_abc123",
  "value": 1,
  "properties": {
    "endpoint": "/api/v1/search",
    "method": "GET"
  }
}
```

```bash theme={null}
# Record events in bulk
POST /v1/sdk/meter-events/bulk
{
  "records": [
    { "customerRef": "cus_abc123", "value": 1 },
    { "customerRef": "cus_def456", "value": 1 }
  ]
}
```

### Via Usage Endpoint

The usage endpoint records generic usage events (not direct meter-name events):

```bash theme={null}
POST /v1/sdk/usages
{
  "customerRef": "cus_abc123",
  "actionType": "api_call",
  "units": 1,
  "outcome": "success",
  "productRef": "prd_P9Q0R1S2"
}
```

Use `/v1/sdk/meter-events` when you need explicit `meterName` + `value` semantics.

### Via NATS Event Bus

For internal services, usage can be published over NATS:

```typescript theme={null}
// Record a single usage record
await nats.publish('solvapay.meter.record', {
  meterName: 'requests',
  userId: 'cus_abc123',
  value: 1,
  properties: { endpoint: '/search' }
})

// Record usage in bulk
await nats.publish('solvapay.meter.recordBulk', {
  events: [
    { meterName: 'requests', userId: 'cus_abc123', value: 1 },
    { meterName: 'requests', userId: 'cus_def456', value: 1 }
  ]
})
```

### Automatic MCP Tool Tracking

Every MCP tool call through the SolvaPay proxy automatically records a usage record against the provider's `requests` meter. No SDK integration needed — the proxy records usage with the outcome as a property:

```json theme={null}
{
  "meterName": "requests",
  "customerRef": "cus_abc123",
  "value": 1,
  "properties": {
    "outcome": "success"
  }
}
```

This happens fire-and-forget so it never blocks the tool call response.

## Querying Usage

### Aggregated Usage

Query total usage for a specific meter and customer within a time range:

```bash theme={null}
GET /ui/meters/mtr_XXXXXXXX/usage?from=2025-01-01&to=2025-02-01&customerRef=cus_abc123
```

### Time-Bucketed Aggregation

Get usage broken down by time intervals for charting:

```bash theme={null}
GET /ui/meters/mtr_XXXXXXXX/usage?from=2025-01-01&to=2025-02-01&granularity=day
```

Supported granularities: `hour`, `day`, `week`, `month`.

When no `customerRef` is specified, the aggregation runs across all customers.

### Analytics Queries

The Usage timeseries powers several analytics views:

| Query                   | Description                     |
| ----------------------- | ------------------------------- |
| **Overall daily stats** | Total usage records per day     |
| **Usage by customer**   | Total usage grouped by customer |

## How Usage Powers Billing and Limits

### Limit Checking

When a customer makes a request to a protected endpoint, the system:

1. Finds the customer's active purchase for the product
2. Looks up the plan to get the `limit`
3. Resolves the plan's auto-assigned requests meter
4. Queries `UsageService.sumForMeter()` for usage from `periodStart` to now
5. Compares the total against the plan's hard cap

If usage exceeds the limit, the request is denied with a paywall response including a checkout URL.

```
Request → Find Purchase → Resolve Requests Meter
                              ↓
                    Query Usage timeseries
                    (sum from periodStart to now)
                              ↓
                    used >= limit? → Paywall
                    used < limit?  → Allow + Record Usage
```

### End-of-Period Billing

For post-paid and hybrid plans, a daily cron job:

1. Finds purchases with expired billing periods
2. Queries the Usage timeseries for total usage in the period
3. Subtracts free units from the total
4. Applies the plan's pricing (flat rate or tiered)
5. Creates a payment intent for the calculated amount

See [Billing](/plans/billing) for the full billing flow.

## Record Properties

The optional `properties` field supports arbitrary key-value pairs for filtering and analysis:

```json theme={null}
{
  "meterName": "requests",
  "customerRef": "cus_abc123",
  "value": 1,
  "properties": {
    "endpoint": "/api/v1/search",
    "method": "POST",
    "region": "us-east-1",
    "status": 200
  }
}
```

Properties are stored with the usage record and available in analytics queries. Use them to add context like API endpoints, tool names, regions, or response codes.

## Environment Isolation

Usage records are stored in environment-specific collections:

* `Usage_sandbox` — sandbox environment records
* `Usage_live` — live environment records

Records in sandbox never mix with live data. The environment is determined by the provider's configuration.

## Next Steps

* [Meters](/meters/overview) — meter definitions
* [Plans](/plans/overview) — how plans use meters for limit enforcement
* [Billing](/plans/billing) — end-of-period usage billing
