# Streams usage and billing

> How streams consumption is metered, how entitlement pools are drawn down, how usage is attributed by tag, and how invoices are issued.

The **Usage & billing** screen reports what your organization consumed on the
streams product during the current cycle and compares that consumption against
the metered pools attached to your entitlement plan. It is a reporting surface:
everything on it is derived from metered counters plus the plan record. Nothing
on the screen changes your capacity — the only write it performs is issuing an
invoice.

All figures are scoped to one organization and to the streams product. Voice
invoices are filtered out of the list, so the totals here never mix modalities.

## What gets metered

ClutchCall meters three streams quantities for the current cycle. They arrive
as a single usage record per organization:

| Field              | Unit  | What it counts                                    |
| ------------------ | ----- | ------------------------------------------------- |
| `delivery_minutes` | min   | Delivery time over MoQ / QUIC, across all delivery |
| `egress_bytes`     | bytes | Bytes delivered out                               |
| `storage_bytes`    | bytes | VOD storage held                                  |

The screen renders egress and storage in GB, converting with a binary gigabyte
(`bytes / 1024 ** 3`) and rounding to one decimal place. Delivery minutes are
shown as an integer count.

A **delivery minute** is a minute of delivery as counted by the metering
pipeline for all delivery paths — the chart legend labels the whole series
`MoQ · QUIC`. There is no separate breakdown by viewer, output, or protocol on
this screen.

The header copy also mentions encoding, but this screen surfaces no separate
encoding counter. The three fields above are the only usage quantities it
reads.

## Entitlement plans and metered pools

The plan record drives the top panel. It carries:

| Field          | Shown as                                                       |
| -------------- | -------------------------------------------------------------- |
| `tier`         | The large display value, capitalised (for example `Pro`)        |
| `name`         | Subtitle, alongside the billing cycle                          |
| `billing_cycle`| Subtitle, after the plan name                                  |
| `status`       | A chip; rendered in the success colour when `active`            |

Two metered pools may be attached to the plan:

| Pool               | Drawn down by   |
| ------------------ | --------------- |
| `stream_egress_gb` | Egress          |
| `vod_storage_gb`   | VOD storage     |

Each pool reports a `limit` and a `remaining` value in GB. **The pools are
authoritative for the meters.** Used is derived from the pool, not from the raw
counters:

```
used = max(0, limit - remaining)
```

Deriving usage from `limit - remaining` means the meters reflect whatever the
entitlement layer believes it has already deducted, including any adjustments
that never appeared in the raw counters.

If an organization has no pool configured for a quantity, the meter falls back
to the raw metered counter (`egress_bytes` or `storage_bytes`) and shows a
limit of `0`, which renders as an uncapped meter.

Delivery minutes are always displayed with a limit of `0`. There is no delivery
minute pool in this plan shape — delivery minutes are reported, not drawn down.

## When a pool runs out

As a pool is consumed, `remaining` falls and the meter fills. When `remaining`
reaches zero, `used` equals `limit` and the meter reads full.

Two consequences are worth knowing before you read a full meter as "exactly at
quota":

- The derivation clamps at zero on the low side (`max(0, …)`), so a pool that
  reports more remaining than its limit never renders as negative usage.
- The meter cannot show overage. Once `remaining` is exhausted, the displayed
  used value stops at the limit even if delivery continued. The raw metered
  counters (`egress_bytes`, `storage_bytes`) keep reporting actual consumption
  for the cycle — they are the number to trust when you need to know how far
  past a pool you went.

The **Upgrade plan** button in the header does not change entitlements
in place. It opens the brand portal's billing view in a new tab, where the plan
and its pools are changed. Nothing on this screen adjusts a pool.

## Attributing consumption with tags

The **Usage by tag** panel answers "who consumed the pools this cycle". You
pick a tag key, and consumption for the cycle is grouped by the values of that
key.

The key selector is populated from every tag key present on the
organization's tagged resources. Key discovery reads the organization's
`resource_tag` rows (up to 20,000 rows), counts how many resources carry each
key, and returns the keys sorted by that count descending, then alphabetically.
The most-used key is therefore first, and the panel selects it automatically
until you choose another.

Tag key discovery is cached in the console for five minutes; changing the
selected key issues a fresh usage-by-tag query.

Because streams draws down pools rather than being rated per unit, this panel
reports **consumption**, not money. It attributes usage to `input` resources.
Do not read a tag row as a cost allocation — there is no per-unit rate applied
to it anywhere on this screen.

## Generating an invoice

**Generate invoice** issues an invoice for the current billing cycle, scoped to
the streams product, for this organization. It snapshots the cycle's metered
cost into an *issued* invoice record; the invoice list refreshes as soon as the
mutation succeeds.

The important caveat: the amount on a freshly generated streams invoice is
`₹0` until the CDR and rating pipeline has populated cost for the cycle. That
zero is a real, honest value — it means "no rated cost recorded yet", not "your
usage was free" and not "generation failed". An invoice's amount stops being
₹0 once rating has produced cost rows for the period it covers. Usage meters
filling up while the invoice reads ₹0 is the expected intermediate state.

The button is disabled while a generation is in flight, and while no
organization is resolved. If generation fails, the error surfaces as a toast
carrying the server message; no invoice row is added.

## Reading an invoice

The invoice list shows issued bills for this organization, streams only. Each
row carries:

| Column       | Source                                                              |
| ------------ | ------------------------------------------------------------------- |
| Period       | `period_start` → `period_end`                                       |
| Product      | `product`, or `all products` when the invoice is not product-scoped  |
| Issued       | `issued_at`, as a local date                                        |
| Amount       | `amount_minor`, rendered in INR as minor units ÷ 100                |
| Status       | `status`; rendered in the success colour when `paid`                |

Amounts are stored in **minor units** and formatted with Indian digit grouping.
A row reading `₹0` has `amount_minor = 0`.

## Where the numbers come from and how fresh they are

Every number on the screen comes from a metered counter in ClickHouse, from the
entitlement plan record, or from the billing router — never from a client-side
calculation other than the unit conversions described above.

| Panel                       | Refresh                                  |
| --------------------------- | ---------------------------------------- |
| Usage meters (cycle totals) | Re-fetched every 60 s                     |
| Plan and pools              | Re-fetched every 120 s                    |
| Delivery minutes chart      | Re-fetched every 120 s                    |
| Usage by tag                | On demand, when you change the tag key    |
| Tag keys                    | Cached 5 min                              |
| Invoices                    | On load, and after a successful generation |

The usage totals describe the current cycle, which the screen treats as roughly
the last 30 days. The chart requests 30 days of daily buckets.

The daily series returns **only days that had traffic**. The console fills the
gaps: it builds a continuous 30-day axis ending today and renders missing days
as real zero bars. Without that fill, a chart of sparse activity would silently
compress time and make a quiet week look like a busy one. Each bar's tooltip
gives the date and the exact delivery minutes for that day; the axis labels mark
the first, middle, and last day of the window.

## Empty states and failure states

The screen deliberately distinguishes "nothing happened" from "we could not
find out":

- **No plan attached yet** — the plan query succeeded and returned no plan. The
  status chip reads `Inactive`.
- **No delivery activity yet** — the daily series returned no rows at all.
- **No invoices yet** — no streams invoice has been issued for this
  organization.

A *failed* plan or usage fetch is treated as an outage and rendered as a loading
or error state instead. A fetch failure is never shown as "No plan attached
yet", so an empty state on this screen can always be trusted to mean the
absence of data rather than the absence of an answer.

## Related

- [Telemetry](/platform/telemetry) — the metric, CDR, and trace streams the metered counters sit alongside
- [Authentication](/concepts/authentication) — API keys and org scoping for control-plane calls
