# SaaS Metering and Billing Design: [Product name]

> Design document for usage metering and billing in a software-as-a-service product: the pricing
> model, billable metrics, the usage event contract (CloudEvents 1.0.2), the metering pipeline with
> idempotent ingestion and late-event handling, entitlements and plans, rating and aggregation,
> quotas and overage, integration with the invoicing and payment systems, revenue recognition hooks,
> reconciliation, audit and operations. Tenant cost and tiering considerations follow the themes of
> the AWS Well-Architected SaaS Lens (publication of 4 April 2023). Replace every `[bracketed]`
> value and every row marked *Example*. Revenue recognition rows are a documentation format, not
> accounting advice.

<!--
Guidance: How to use this template
- Write one design per product or per billing domain. Pricing and packaging decisions come from
  product and finance; this document turns them into metrics, events, rules and controls.
- Fill section 2 (pricing model) and section 3 (billable metrics) with finance before engineering
  starts. Most billing defects are definitions, not code.
- Treat metering as a financial system: every number on an invoice must trace back to stored usage
  events, and every correction must leave an audit trail.
- Related documents: Multi-tenancy design (`architecture/multi-tenancy-design`), Payment ledger
  design (`system-design/design-payment-ledger`), Event-driven architecture design
  (`architecture/event-driven-architecture-design`), Streaming solution design
  (`architecture/streaming-solution-design`), Rate limiter design (`system-design/design-rate-limiter`).
-->

## Document control

<!-- Guidance: Identify the product, the billing systems and the people from finance who own the rules. A new billable metric, a pricing model change or a new billing system is a new major version. -->

| Field | Value |
|---|---|
| Document ID | [MTR-001] |
| Product and editions | [Product], [Editions or plans] |
| Billing system of record | [Commercial billing platform / in-house] |
| Payment processor | [Processor] |
| ERP or general ledger | [System] |
| Event format | CloudEvents 1.0.2, [JSON] structured mode |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Superseded] |
| Owner | [@billing-architect] |
| Approvers/reviewers | [@product-pricing-lead], [@revenue-accounting-lead], [@finance-systems-lead], [@security-lead], [@sre-lead] |
| Last updated | YYYY-MM-DD |
| Classification | [Internal / Confidential] |

### Approvals

| Role | Name | Decision | Date |
|---|---|---|---|
| Product pricing | [@name] | [Approve / Approve with conditions / Reject] | YYYY-MM-DD |
| Revenue accounting | [@name] | [Decision] | YYYY-MM-DD |
| Finance systems | [@name] | [Decision] | YYYY-MM-DD |
| Engineering | [@name] | [Decision] | YYYY-MM-DD |
| Security | [@name] | [Decision] | YYYY-MM-DD |

### Revision history

| Version | Date | Author | Change summary |
|---|---|---|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft |
| 1.0 | YYYY-MM-DD | [@name] | *Example:* Approved; API call and storage metrics live |
| 1.1 | YYYY-MM-DD | [@name] | *Example:* Added prepaid commitment with drawdown |

## Contents

<!-- Guidance: Keep this list aligned with the headings. -->

1. [Scope and context](#1-scope-and-context)
2. [Pricing model](#2-pricing-model)
3. [Billable metrics](#3-billable-metrics)
4. [Usage event contract](#4-usage-event-contract)
5. [Metering pipeline](#5-metering-pipeline)
6. [Entitlements and plans](#6-entitlements-and-plans)
7. [Rating and aggregation](#7-rating-and-aggregation)
8. [Quotas, limits and overage](#8-quotas-limits-and-overage)
9. [Invoicing and billing integration](#9-invoicing-and-billing-integration)
10. [Revenue recognition hooks](#10-revenue-recognition-hooks)
11. [Accuracy, reconciliation and audit](#11-accuracy-reconciliation-and-audit)
12. [Tenancy, security and privacy](#12-tenancy-security-and-privacy)
13. [Operations and service levels](#13-operations-and-service-levels)
14. [Trade-offs, decisions and risks](#14-trade-offs-decisions-and-risks)
15. [Glossary and references](#15-glossary-and-references)

## 1. Scope and context

<!-- Guidance: State what the metering and billing system must do and for whom. Questions: which plans and contract types exist? Who sells (self-serve, sales-led, marketplace)? Which systems already exist? Pitfall: designing only for self-serve card payments when most revenue comes from negotiated contracts. -->

### 1.1 Scope

| In scope | Out of scope |
|---|---|
| *Example:* Usage capture for all billable metrics across regions | Product analytics events that are not billed |
| *Example:* Entitlement checks, quotas and overage | Sales quoting and contract negotiation |
| *Example:* Rating and handover of rated usage to the billing system | Tax calculation (delegated to the billing system) |
| *Example:* Reconciliation of usage to invoices and to the ledger | Collections and dunning operations |
| [Item] | [Item] |

### 1.2 Context

| Item | Value |
|---|---|
| Tenants (paying accounts) | *Example:* 2,000, growing [40 %] per year |
| Sales channels | *Example:* Self-serve card (70 % of accounts, 20 % of revenue); sales-led annual contracts (30 % of accounts, 80 % of revenue); cloud marketplace listing planned |
| Billing periods | *Example:* Monthly in arrears for usage; annual in advance for platform fees |
| Currencies | *Example:* USD, EUR, GBP |
| Regions | *Example:* EU and US deployments; usage stays in region until aggregated |

### 1.3 Requirements

| ID | Requirement | Type |
|---|---|---|
| MTR-REQ-001 *(Example)* | Every billable action is counted exactly once on the invoice, even when producers retry | Correctness |
| MTR-REQ-002 *(Example)* | Customers see near-real-time usage (delay under [15 minutes]) in the console | Experience |
| MTR-REQ-003 *(Example)* | Quotas stop or throttle usage within [1 minute] of the limit being reached, where the plan says hard limit | Control |
| MTR-REQ-004 *(Example)* | Invoices for a period close within [3 days] after period end, including late events | Finance |
| MTR-REQ-005 *(Example)* | Every invoice line traces to stored events and rating rules for [7 years or the retention schedule] | Audit |
| MTR-REQ-006 *(Example)* | Metering outage must not block the product; events buffer and replay | Availability |
| [MTR-REQ-NNN] | [Requirement] | [Type] |

## 2. Pricing model

<!-- Guidance: Record the pricing model in precise terms that engineering can implement. Questions: what is the value metric customers understand? Which components are fixed, which vary with usage? How do commitments work? Pitfall: pricing that depends on a metric the product cannot measure reliably. -->

| Model | How the charge is computed | Use when |
|---|---|---|
| Flat fee | Fixed amount per period | Simple entry plans |
| Per seat | Unit price times active or assigned users | Value grows with people using it |
| Per unit usage | Unit price times measured quantity | Value grows with consumption |
| Graduated tiers | Each tier's units priced at that tier's rate | Encourage growth while keeping small use cheap |
| Volume tiers | All units priced at the rate of the tier reached | Simple large-volume discounts |
| Package | Price per block of units, rounded up | Usage in natural bundles |
| Prepaid commitment with drawdown | Customer prepays credits; usage draws down; overage at a contract rate | Sales-led contracts that need budget certainty |
| Hybrid | Platform fee plus usage components | Most B2B SaaS |

### 2.1 Plans

| Plan ID | Plan | Platform fee | Included usage | Usage pricing | Limit type | Billing |
|---|---|---|---|---|---|---|
| PLN-FREE *(Example)* | Free | USD 0 | 100,000 API calls | None | Hard limit | n/a |
| PLN-TEAM *(Example)* | Team | USD 500 per month | 1,000,000 API calls; 100 GB storage | Graduated tiers (section 7) | Soft limit with overage | Monthly in arrears, card |
| PLN-ENT *(Example)* | Enterprise | Contract | Per contract | Contract rate card; prepaid commitment | Soft limit, alerts | Annual commitment, monthly usage statement |
| [PLN-ID] | [Plan] | [Fee] | [Included] | [Pricing] | [Limit] | [Billing] |

## 3. Billable metrics

<!-- Guidance: Define each metric so that two engineers would compute the same number. Questions: what exactly counts, and what does not (retries, errors, internal traffic)? Which aggregation applies? Pitfall: "active users" with no definition of active, period or time zone. -->

| Metric ID | Metric | Source event type | Counts | Excludes | Aggregation | Unit and rounding | Period boundary |
|---|---|---|---|---|---|---|---|
| MET-001 *(Example)* | API calls | `com.example.api.request.completed` | Requests completed with status 2xx or 3xx; 4xx billed only where the price book says so | Health checks, internal service accounts, requests rejected by quota | Sum of count | Call; no rounding | Calendar month, UTC |
| MET-002 *(Example)* | Storage | `com.example.storage.snapshot` | Bytes stored per tenant, sampled hourly | Soft-deleted data inside the [7-day] recovery window | Average of hourly snapshots | GB-month, rounded to 2 decimals | Calendar month, UTC |
| MET-003 *(Example)* | Active seats | `com.example.seat.activity` | Distinct users with at least one sign-in in the period | Service users, support impersonation | Unique count | Seat | Calendar month, tenant time zone |
| MET-004 *(Example)* | AI tokens | `com.example.ai.inference.completed` | Input plus output tokens of completed calls | Calls that failed before generation | Sum | 1,000 tokens, rounded up per period | Calendar month, UTC |
| [MET-NNN] | [Metric] | [Event type] | [Counts] | [Excludes] | [Sum / Max / Unique / Average / Last] | [Unit] | [Boundary] |

Rules for metric definitions:

- Measure at the point where the action is complete and its outcome is known, not at request
  receipt.
- Prefer metrics the customer can verify from their own logs or console.
- State the time zone and the period boundary; an event at 23:59:59 UTC must fall in one period
  only.
- Version metric definitions. A definition change applies from a stated period and never
  re-rates closed periods silently.

## 4. Usage event contract

<!-- Guidance: Define the event that producers emit and the guarantees each side gives. Questions: who assigns the event ID? What makes two events duplicates? How are corrections expressed? Pitfall: using the arrival time instead of the event time for period assignment. -->

Usage events use the CloudEvents 1.0.2 format. CloudEvents requires the context attributes `id`,
`source`, `specversion` and `type`, and requires producers to keep the combination of `source` and
`id` unique for each distinct event; consumers may treat events with the same `source` and `id` as
duplicates. The metering pipeline uses that pair as the idempotency key.

```json
{
  "specversion": "1.0",
  "id": "4f1c2a9e-7b1d-4d8e-9a55-2f0c1e7d9b10",
  "source": "//api.example.com/regions/eu-west/gateway-07",
  "type": "com.example.api.request.completed",
  "subject": "tenant/t-10442",
  "time": "2026-10-23T09:14:07.512Z",
  "datacontenttype": "application/json",
  "dataschema": "https://schemas.example.com/usage/api-request/2",
  "data": {
    "tenantId": "t-10442",
    "subscriptionId": "sub-88310",
    "metric": "MET-001",
    "quantity": 1,
    "dimensions": { "region": "eu-west", "apiProduct": "search" },
    "statusClass": "2xx"
  }
}
```

| Field | Rule |
|---|---|
| `id` | Assigned by the producer when the billable action completes; stable across retries |
| `source` | Identifies the producing component instance; with `id` forms the idempotency key |
| `type` | Reverse-DNS event type; one type per billable action |
| `time` | Event time in UTC; decides the billing period |
| `subject` | Tenant reference, used for partitioning |
| `dataschema` | Versioned schema; a breaking change gets a new version and a new `type` or schema URI |
| `data.quantity` | Non-negative number in the metric's base unit; pre-aggregated events state the window they cover |

Corrections are new events of a correction type (for example
`com.example.usage.adjustment`) that reference the original `id` and carry a signed quantity and a
reason code. Never edit or delete a stored usage event. Register the event types in the event
catalogue described in the event-driven architecture design
(`architecture/event-driven-architecture-design`).

## 5. Metering pipeline

<!-- Guidance: Show how events travel from producers to rated usage, and where each guarantee is enforced. Questions: where are duplicates removed? How long are late events accepted? What happens when the pipeline is down? Pitfall: deduplicating only inside a short streaming window while producers can retry for hours. -->

```mermaid
flowchart LR
  P["Producers (services, gateways, jobs)"] --> B["Local buffer or outbox"]
  B --> I["Ingestion API or stream"]
  I --> V["Validate schema and tenant"]
  V --> D["Deduplicate on source and id"]
  D --> R["Raw usage store (append only)"]
  D --> A["Aggregator per tenant, metric, period"]
  A --> Q["Quota and entitlement service"]
  A --> RT["Rating engine"]
  RT --> BS["Billing system"]
  BS --> GL["General ledger"]
  V --> DLQ["Dead-letter store"]
  R --> REC["Reconciliation jobs"]
  RT --> REC
  BS --> REC
```

### 5.1 Stage responsibilities

| Stage | Responsibility | Guarantee |
|---|---|---|
| Producer buffer | Write usage to a transactional outbox or local durable buffer in the same unit of work as the action | No usage lost if the pipeline is unavailable |
| Ingestion | Accept batches; authenticate producers; return acknowledgement after durable write | At-least-once delivery |
| Validation | Check schema version, tenant existence and subscription; route failures to the dead-letter store | No silent drops |
| Deduplication | Keep a key store of `source` + `id` for at least the maximum retry and replay horizon ([35 days]) | Effectively once per key |
| Raw store | Append-only, partitioned by tenant and event date, immutable | Replay and audit |
| Aggregation | Maintain running totals per tenant, metric and period; recompute from the raw store on demand | Totals reproducible from events |
| Rating | Apply the price book version valid for the period | Deterministic charges |

### 5.2 Late and out-of-order events

| Rule | *Example* value |
|---|---|
| Events assigned to period by `time`, not arrival | Always |
| Late window during which events still join the open period | 72 hours after period end |
| Period close | Period end plus 72 hours; invoice generated after close |
| Events arriving after close | Billed in the next period as a prior-period adjustment line, with original event time kept |
| Future-dated events (more than [5 minutes] ahead of server time) | Rejected to the dead-letter store |

### 5.3 Capacity estimate

*Example:* 12,000 events per second on average gives 12,000 x 86,400 = 1,036,800,000 events per
day. At 600 bytes per event that is about 622 GB of raw usage per day, or about 246 TB for 396 days
(13 months) before compression. Consequence: pre-aggregate high-volume metrics at the producer in
one-minute windows per tenant and dimension (keeping counts exact), and keep per-request events only
where customers need line-level evidence. Size the deduplication store for the keys of the full
35-day horizon, or deduplicate pre-aggregated windows by window key instead.

## 6. Entitlements and plans

<!-- Guidance: Separate "what the customer bought" from "what the customer used". Questions: which service answers "may this tenant do this now"? How fast does an upgrade take effect? Pitfall: entitlement checks that read the billing system on every request. -->

The entitlement service holds, per tenant, the active plan, features, included quantities, limits and
contract terms. Products ask it, through a cached local client, whether a feature or quantity is
allowed. The billing system is the commercial source; changes flow to the entitlement service as
events, so the product never depends on the billing system being available.

| Entitlement ID | Type | Plan values | Enforcement point | Cache time to live |
|---|---|---|---|---|
| ENT-001 *(Example)* | Feature flag: single sign-on | Team: off; Enterprise: on | Identity service | 5 min |
| ENT-002 *(Example)* | Included API calls per month | Free: 100,000; Team: 1,000,000; Enterprise: contract | Quota service | 1 min |
| ENT-003 *(Example)* | Rate limit per second | Free: 10; Team: 100; Enterprise: 500 | API gateway | 1 min |
| ENT-004 *(Example)* | Storage limit | Free: 1 GB; Team: 500 GB; Enterprise: contract | Storage service | 15 min |
| [ENT-NNN] | [Type] | [Values] | [Point] | [TTL] |

Plan changes in the middle of a period are prorated by the billing system for fees; usage metrics
switch rate at the effective timestamp of the change, which the rating engine reads from the
subscription history. Design feature flags with the configuration service design
(`system-design/design-config-feature-flag-service`).

## 7. Rating and aggregation

<!-- Guidance: Show exactly how usage becomes money, with a worked example finance can check. Questions: which price book version applies? How are tiers applied: graduated or volume? Where does currency conversion happen? Pitfall: rating in floating point. -->

Rate with decimal arithmetic in the currency's minor units, round once per invoice line using the
rounding rule agreed with finance ([half-up to 2 decimals]), and store the price book version, the
quantities and the result with each rated line.

### 7.1 Worked example: graduated versus volume tiers

*Example* price book for MET-001 on PLN-TEAM: first 1,000,000 calls included; 1,000,001 to
10,000,000 at USD 0.20 per 1,000 calls; above 10,000,000 at USD 0.10 per 1,000 calls. Tenant
t-10442 used 14,500,000 calls in the month.

| Tier | Calls in tier | Rate | Graduated charge |
|---|---|---|---|
| 1 (included) | 1,000,000 | USD 0 | USD 0 |
| 2 | 9,000,000 | USD 0.20 per 1,000 | USD 1,800 |
| 3 | 4,500,000 | USD 0.10 per 1,000 | USD 450 |
| Total usage | 14,500,000 | | USD 2,250 |

With the platform fee of USD 500, the graduated invoice is USD 2,750. Under volume tiers, where all
billable calls take the rate of the tier reached, the 13,500,000 calls above the included amount
would cost 13,500 x USD 0.10 = USD 1,350, and the invoice would be USD 1,850 (here the included
allowance is deducted before the volume rate applies; state this in the price book). The two models differ
by USD 900 for the same usage, which is why the price book must name the tier mode explicitly.

### 7.2 Worked example: prepaid commitment with drawdown

*Example:* an Enterprise customer prepays USD 30,000 of credits for 12 months at the contract rate
card. Monthly usage rated at the contract rate card is USD 2,750 (illustrative, and not the Team
invoice of section 7.1, which includes a platform fee), so 12 months consume USD 33,000. Credits run out during the
eleventh month (10 x 2,750 = 27,500 leaves 2,500, which covers most of month 11); the remaining USD
3,000 is overage billed monthly in arrears at the contract overage rate. Send a commitment alert at
[75 %] drawdown (USD 22,500, reached during month 9) so the account team can propose a renewal or
top-up.

## 8. Quotas, limits and overage

<!-- Guidance: Decide what happens when a tenant reaches a limit, per plan. Questions: hard stop, throttle, or bill overage? How are customers warned? Pitfall: a hard stop on a production integration with no warning. -->

| Limit | Plan | Type | Warning | At limit | Overage |
|---|---|---|---|---|---|
| Monthly API calls | Free | Hard | Email and console at 80 % and 100 % | Requests rejected with HTTP 429 and a problem details body naming the limit | None; upgrade path shown |
| Monthly API calls | Team | Soft | 80 %, 100 %, 150 % | Requests continue | Graduated tier pricing |
| Request rate | All | Hard | Response headers with remaining capacity | Throttle with HTTP 429 and `Retry-After` | None |
| Monthly spend cap set by customer | Team | Customer-defined hard | 50 %, 80 %, 100 % | Usage metrics with a cap stop; others continue | None beyond the cap |
| [Limit] | [Plan] | [Type] | [Warning] | [Action] | [Overage] |

Quota decisions use the aggregator's running totals plus a local allowance per instance, so the hot
path does not call a central service for every request. Accept a small overshoot (bounded by the
allowance size) and state it in the terms. Rate limiting itself is designed with the rate limiter
design (`system-design/design-rate-limiter`).

## 9. Invoicing and billing integration

<!-- Guidance: Define the hand-off between rated usage and the billing system, and back to the ledger. Questions: does the billing system rate, or only invoice rated lines? Who owns tax? How are credit notes raised? Pitfall: two systems both applying discounts. -->

| Concern | Owner | Interface |
|---|---|---|
| Customer, subscription and price book master | Billing system | Events to entitlement service and rating engine |
| Usage rating | [Rating engine in metering / billing system] | Rated line items per tenant, metric, period |
| Taxes | Billing system with tax engine | Tax lines on invoice |
| Invoice issue and delivery | Billing system | Invoice event to product console and email |
| Payment | Payment processor via billing system | Payment status events |
| Credit notes and adjustments | Billing system, approved by finance | Adjustment events referencing invoice lines |
| Journal entries | Billing system to general ledger | Summarised journals per period |

Send rated usage as idempotent line items keyed by tenant, metric, period and price book version, so
resending after a failure cannot double-bill. Record money movements with the double-entry patterns
in the payment ledger design (`system-design/design-payment-ledger`). Marketplace sales (cloud
marketplaces) need usage reported to the marketplace's own metering interface; treat each
marketplace as another billing channel with its own reconciliation.

## 10. Revenue recognition hooks

<!-- Guidance: Give revenue accounting the data it needs; do not implement accounting policy in the metering code. Questions: which contract elements are separate performance obligations? How is usage-based consideration recognised? Pitfall: engineers deciding recognition rules without finance. -->

Revenue recognition follows the organisation's accounting policies under ASC 606 (United States
GAAP) or IFRS 15 (International Financial Reporting Standards), decided by revenue accounting. The
metering and billing design supplies the data below; it does not decide the accounting treatment.

| Hook | Data supplied | Consumer |
|---|---|---|
| Contract and performance obligation reference | Contract ID, line IDs, start and end dates, commitment amounts | Revenue system |
| Usage by period | Rated usage per tenant, metric and period, with event-time basis | Revenue system |
| Commitment drawdown | Opening balance, drawdown, expiry, overage per period | Revenue system and deferred revenue schedules |
| Credits and refunds | Adjustment events with reason codes | Revenue system |
| Period close status | Flag that a period is closed and its totals are final | Revenue and finance close |

## 11. Accuracy, reconciliation and audit

<!-- Guidance: Prove that what was used is what was billed. Questions: which counts must match at each stage? What tolerance is allowed, and who signs off? Pitfall: reconciliation that only compares totals, hiding offsetting errors. -->

| Check ID | Compare | Granularity | Tolerance | Frequency | Owner |
|---|---|---|---|---|---|
| REC-001 *(Example)* | Producer-side counters vs ingested events | Tenant, metric, hour | 0 after late window | Hourly, final at close | [@metering-lead] |
| REC-002 *(Example)* | Raw store recomputation vs aggregator totals | Tenant, metric, period | 0 | Daily and at close | [@metering-lead] |
| REC-003 *(Example)* | Aggregated quantities vs rated lines | Tenant, metric, period | 0 | At close | [@billing-architect] |
| REC-004 *(Example)* | Rated lines vs invoice lines | Invoice line | 0 | After invoicing | [@finance-systems-lead] |
| REC-005 *(Example)* | Invoices vs ledger journals | Currency, period | 0 | Monthly close | [@revenue-accounting-lead] |
| REC-006 *(Example)* | Dead-letter store backlog | Event | Empty at close, or each item dispositioned | Daily | [@metering-lead] |
| [REC-NNN] | [Compare] | [Granularity] | [Tolerance] | [Frequency] | [@owner] |

Audit rules: keep raw events, price book versions, rating outputs and adjustments for the retention
period; log every manual adjustment with requester, approver and reason; give customers a usage
export that sums to their invoice lines; and test the reconciliation jobs with seeded errors
(duplicates, late events, missing hours) before go-live.

## 12. Tenancy, security and privacy

<!-- Guidance: Protect usage data, which reveals what customers do. Questions: can one tenant's events land on another tenant's invoice? Who may change price books? Pitfall: producers allowed to set any tenant ID in usage events. -->

- Derive the tenant from the authenticated context at the producer, never from client input, and
  validate it at ingestion against the subscription. Apply the tenancy patterns of the multi-tenancy
  design (`architecture/multi-tenancy-design`).
- Authenticate producers with workload identities; only registered sources may emit each event
  type.
- Separate duties: engineers deploy rating code; finance approves price books; nobody does both for
  the same change.
- Minimise personal data in usage events: use pseudonymous user IDs for seat metrics and keep the
  mapping in the product.
- Encrypt usage stores at rest; restrict raw event access to named roles, with access logged.
- Keep usage in region where residency commitments apply and move only aggregates across regions.

## 13. Operations and service levels

<!-- Guidance: Define what is monitored and what the on-call engineer does when counts drift. Pitfall: alerting on pipeline errors but not on silent drops in volume. -->

| Indicator | Target | Alert |
|---|---|---|
| Ingestion availability | 99.95 % monthly | Burn rate over [2x] for [1 h] |
| Event-to-console freshness | 95 % of events visible within [15 min] | Freshness over [30 min] |
| Volume anomaly per tenant and metric | Within [3] standard deviations of the trailing 28-day pattern | Drop or spike outside the band |
| Dead-letter rate | Under [0.01 %] of events | Above threshold for [15 min] |
| Period close duration | Within [72 h] after period end | Close not complete at [60 h] |

Write runbooks for replay from the raw store, re-rating a period before invoicing, issuing a
correction after invoicing, and handling a producer that sent wrong quantities. Keep them with the
service runbook (`dev/runbook`).

## 14. Trade-offs, decisions and risks

<!-- Guidance: Record the main choices and what would make you revisit them. Pitfall: building an in-house billing engine when the hard part is metering. -->

| Decision | Options | Choice *(Example)* | Reason | Revisit if |
|---|---|---|---|---|
| Who rates usage | Metering service; billing platform | Billing platform for standard plans; metering rates contract rate cards | Keeps price books in one place for most plans | Billing platform cannot express contract terms |
| Event granularity | Per action; pre-aggregated windows | Pre-aggregated one-minute windows for API calls, per action for AI tokens | Volume and cost versus evidence | Customers require per-call evidence |
| Deduplication | Streaming window; persistent key store | Persistent key store, 35-day horizon | Producers may retry for days after outages | Storage cost exceeds [budget] |
| Quota enforcement | Central check per request; local allowance | Local allowance with bounded overshoot | Latency and availability | Overshoot complaints |
| Build or buy metering | In-house pipeline; usage-billing product | [Decision] | [Reason] | [Trigger] |

| ID | Risk | Mitigation | Owner |
|---|---|---|---|
| MTR-R-001 *(Example)* | Under-billing from dropped events goes unnoticed | REC-001 and volume anomaly alerts | [@metering-lead] |
| MTR-R-002 *(Example)* | Over-billing from duplicates damages trust | Idempotency on `source` + `id`; customer usage export | [@billing-architect] |
| MTR-R-003 *(Example)* | Metric definition changes re-rate closed periods | Versioned definitions effective from a stated period | [@product-pricing-lead] |
| MTR-R-004 *(Example)* | Metering outage blocks the product | Producer outbox; product does not wait on metering | [@sre-lead] |
| [MTR-R-NNN] | [Risk] | [Mitigation] | [@owner] |

## 15. Glossary and references

<!-- Guidance: Define the billing terms that finance and engineering use differently. -->

| Term | Meaning in this document |
|---|---|
| Billable metric | Precisely defined quantity that a price applies to |
| Entitlement | What a tenant is allowed to use under its plan or contract |
| Rating | Applying a price book to aggregated quantities to produce charges |
| Price book | Versioned set of prices, tiers and rules for a plan or contract |
| Drawdown | Consumption of prepaid credits by rated usage |
| Late event | Usage event that arrives after its period's normal processing time |
| Idempotency key | Value that identifies an event so that repeats are recognised; here `source` + `id` |

| Reference | Version or date checked | Use |
|---|---|---|
| CloudEvents specification, cloudevents.io and github.com/cloudevents/spec | 1.0.2 (latest release; `specversion` value "1.0") | Section 4 |
| AWS Well-Architected Framework, SaaS Lens, docs.aws.amazon.com | Publication date 4 April 2023 | Tenant cost, tiering and operations themes |
| RFC 9457, Problem Details for HTTP APIs | 2023 | Error bodies at limits |
| ASC 606 Revenue from Contracts with Customers (FASB); IFRS 15 Revenue from Contracts with Customers (IASB) | Names only | Section 10 |
| [Billing platform documentation] | [Version] | [Use] |

## Standard and licence note

Based on the CloudEvents 1.0.2 specification (Apache License 2.0) for the event envelope and on
common SaaS metering and billing practice; tenant cost and tiering themes are aligned with the AWS
Well-Architected SaaS Lens, which is cited and not reproduced. ASC 606 and IFRS 15 are named only;
no text of either standard is used, and the revenue rows are a documentation format, not accounting
advice. The structure, rules and worked examples are original to this collection. Check the current
official specifications and your accounting policies before use. AWS and AWS Well-Architected are
trademarks of their owners; this template is not affiliated with or endorsed by them. Template
licence: MIT.
