---
title: "Keep raw events and derive every total · Agent Wranglers"
url: https://agentwranglers.se/playbook/usage-billing/metering/raw-usage-events
id: USG-3
level: Recommended
applies: payments
updated: 2026-10-22
tokens: 960
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Keep raw events and derive every total from them

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Metering](https://agentwranglers.se/playbook/usage-billing/metering.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: USG-3
- Level: Recommended
- Chapter: [Metering](https://agentwranglers.se/playbook/usage-billing/metering.md)
- Rule: Keep every raw usage event for as long as you keep the invoice it fed. Compute period totals from the events, and never keep only a running counter.
- Check: A job rebuilds last month's totals from raw events and compares them with the stored totals. They match for every customer and meter. The app's database role cannot run UPDATE or DELETE on the usage events table.
- Applies when: The project takes payments.
- How: A counter you add to cannot be checked, corrected or explained to a customer who disputes a bill. Raw events can. Sum them by customer, meter and period in a query or a scheduled job. Store the totals as a cache that can be rebuilt. Correct a mistake with a new event that has a negative or offsetting quantity, never by editing an old one. Keep the events as long as [Keep payment records for the legal period](https://agentwranglers.se/playbook/payments/invoices-and-records/payment-record-retention.md) requires for the invoice.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### SQL example

```sql
SELECT customer_id, meter, sum(quantity) AS total
FROM usage_events
WHERE occurred_at >= $1 AND occurred_at < $2
GROUP BY customer_id, meter;
```

### Python example

```python
def period_totals(db, start, end) -> dict[tuple[str, str], int]:
    rows = db.execute(
        "SELECT customer_id, meter, sum(quantity) FROM usage_events "
        "WHERE occurred_at >= %s AND occurred_at < %s GROUP BY customer_id, meter",
        (start, end),
    ).fetchall()
    return {(customer, meter): total for customer, meter, total in rows}
```

### JavaScript example

```js
export async function periodTotals(db, start, end) {
  const { rows } = await db.query(
    `SELECT customer_id, meter, sum(quantity) AS total FROM usage_events
     WHERE occurred_at >= $1 AND occurred_at < $2 GROUP BY customer_id, meter`,
    [start, end],
  )
  return new Map(rows.map(row => [`${row.customer_id}:${row.meter}`, Number(row.total)]))
}
```

## Related rules

- PAY-56 [Keep payment records for the legal period](https://agentwranglers.se/playbook/payments/invoices-and-records/payment-record-retention.md) in Payments and billing
- USG-20 [Let customers download the usage behind each invoice](https://agentwranglers.se/playbook/usage-billing/usage-on-invoices/usage-export.md) in Usage-based billing
- USG-21 [Credit back usage your own fault caused](https://agentwranglers.se/playbook/usage-billing/usage-on-invoices/usage-credit-notes.md) in Usage-based billing

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/usage-billing/metering/raw-usage-events">Agent Wranglers usage-based billing playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Meter on the server after the work succeeds](https://agentwranglers.se/playbook/usage-billing/metering/server-side-metering.md)
- Next: [Accept late events up to a fixed cut-off](https://agentwranglers.se/playbook/usage-billing/metering/late-usage-cutoff.md)
- [Metering](https://agentwranglers.se/playbook/usage-billing/metering.md)
