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

# Billing → Records: the usage record export console

> Walk the Billing → Records dashboard surface end to end — the shared-window filter strip, the voice CDR and per-message export panels, the per-record row fields, and how the page reconciles the live usage feed against the wallet ledger. The operator-friendly companion to the CDR export API guide.

<Note>
  **Operator-facing surface.** This guide walks the **Billing → Records**
  dashboard page (`/billing/records`). For the API the page reads from —
  `GET /usage/cdr` and `GET /usage/cdr/export.csv` — see
  [CDR usage export for billing reconciliation](/guides/cdr-usage-export-billing-reconciliation).
  The dashboard and the API expose the same usage records; the page is the
  faster path for an operator who wants to filter, eyeball, and download CSV
  without leaving the console.
</Note>

# Billing → Records: the usage record export console

Open **Billing → Records** (`/billing/records`) and you land on the single
page built for one job: turn a month of calls and messages into two CSV files
finance can reconcile line-for-line against the wallet ledger. The page pairs
a live usage feed with two export panels — one per-call (voice CDR), one
per-message — over one shared filter window, so the records you see in the
table are the records you download.

This is the **dashboard walkthrough**. For the request/Response contract, the
keyset-cursor drain loop, the CSV column order, and the per-bucket
reconciliation script, read the
[API-focused guide](/guides/cdr-usage-export-billing-reconciliation). This
guide assumes you are an operator in the console, not at a terminal.

<RoleGate roles="owner,admin,billing" />

## 1. What the page is

`/billing/records` is the shared-window CSV export hub. It unifies the two
billing-reconciliation surfaces — **voice CDR** (one row per call) and
**messaging usage** (one row per message) — that previously lived as separate
exports, and sits them over one filter strip so both exports honor the same
window, the same channel scope, and the same status slice. Set the filters
once; both panels and the live table read the same coverage.

The page exists so a finance operator can answer "what did we spend this
month, broken down to the record" in one click rather than one script. The
role gate matches the API: **owner, admin, or billing**. If you can open the
page you can export its data; if you cannot, the API is equally gated.

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/zeelaltd/docs/guides/billing-records-export-console.png" alt="Billing → Records page: the shared filter strip, the live usage table, and the two export cards." />
</Frame>

## 2. The shared-window filter strip

Every control in the filter card at the top of the page applies to the live
table **and** both export panels at once. Change one filter and all three
surfaces re-scope to the same window — there is no per-panel filter drift.

The controls, left to right:

* **Window (7d / 30d / 90d)** — a preset "last N days" range picker in the
  page header. The default is **30d**. The window resolves to an inclusive
  `from` and an exclusive `to` (now) in UTC, so the live table and the CSV
  export see the same rows for the same window.
* **Direction** — `All` (both legs), `Inbound`, or `Outbound`. Applies to
  both call and message records.
* **Channel** — `All channels`, or one of `SMS`, `MMS`, `WhatsApp`, `Voice`,
  `Email`, `RCS`. Calls carry the synthetic `Voice` channel, so selecting it
  scopes the table to the call arm.
* **Record kinds** — toggle chips for `Calls` and `Messages`. Leave both off
  for both record kinds; toggle one to drain a single kind (the server-side
  resolver drops the disabled arm rather than over-fetching).
* **Status** — a free-form text field with suggestions (`delivered`, `sent`,
  `queued`, `failed`, `undelivered`, `bounced`, `expired`, `answered`,
  `completed`). One key spans both record kinds; an unrecognized token
  matches nothing but never errors the request.
* **Phone (CDR export only)** — an E.164 phone number. This filter reaches
  **only the voice CDR export card** — the unified message-export schema has
  no phone bound, so the field would silently no-op there. The page labels
  it accordingly so a scoped export never silently drops to "all numbers."
* **Pricing** — `All records (priced + unpriced)` or `Priced only`. The
  default keeps rows whose price was never rated so the feed never looks like
  "no usage" when a rating hiccup left a NULL price. Switch to `Priced only`
  to restrict to billed rows.

A scope note under the filter card states which controls reach which surface:
the phone filter is CDR-only, and every other filter applies to the table and
both export cards.

## 3. Voice panel — call records (voice CDR)

The **Call records (voice CDR)** export card streams one row per call, priced
with the settled per-minute rate the wallet was charged at call close. It
drives the voice export endpoint with the shared window and the direction,
status, and phone filters from the strip above.

Pick the direction at the strip — `All`, `Inbound`, or `Outbound` — and the
card exports that leg. Each row in the exported CSV carries:

* **Direction** — inbound or outbound.
* **From** — the calling party address.
* **To** — the called party address.
* **Duration** — the billed call duration.
* **Price** — the per-call settled price the wallet was charged.
* **Currency** — the currency the price is denominated in.
* **Country** — the destination country the rate card billed the call against.

Click **Export call records** to download the CSV. The file is named
`usage-cdr-records-<timestamp>.csv`. Up to 100,000 rows per pull; the card
priced each row at the per-minute rate the wallet ledger saw at close — the
export never re-rates.

## 4. Messaging panel — message records

The **Message records (SMS / WhatsApp / …)** export card streams one row per
message across every channel in the account — SMS, MMS, WhatsApp, Email, RCS,
and the rest — priced with the per-message rate the wallet was charged at
send time. It drives the message export endpoint with the shared window and
the channel and status filters from the strip.

Each row in the exported CSV carries:

* **Direction** — inbound or outbound.
* **From** / **To** — the sender and recipient addresses.
* **Channel** — the channel the message rode on (SMS, WhatsApp, Email, RCS,
  …).
* **Segments** — the billable segment count the message was rated on (the
  unit the carrier bills — one long SMS may be two or three segments).
* **Price** — the per-message settled price the wallet was charged.
* **Currency** — the currency the price is denominated in.
* **Status** — the delivery status at export time.

Click **Export message records** to download the CSV. The file is named
`usage-messages-records-<timestamp>.csv`. Up to 10,000 rows per pull;
channel-scope the export by setting a channel in the filter strip above
before you export — the message-export schema has no phone bound, so the
phone filter does not reach this card.

## 5. How the page reconciles

The live table above both export cards subscribes to the same usage feed the
CDR API exposes — the records you see in the table are the records that land
in the CSV. Each row carries its resolved price inline, so per-record
reconciliation against the wallet ledger is exact, not an estimate.

The table keyset-paginates (a server-validated `(timestamp, id)` cursor) with
a **Load more records** affordance; a **Load more** click fetches the next
page over the same window without resetting the filter. A **Export CSV** link
in the table header drives the unified usage-CDR export — the same filter set
in one pass — so the table and the export never disagree on which rows match.

This is where the dashboard and the API divide: the dashboard is
**operator-friendly** — filter, eyeball, download, repeat. For a
finance-grade close that pages the whole month, drains a 50,000-row cap, and
matches rows against an invoice line-for-line, the
[CDR export API](/guides/cdr-usage-export-billing-reconciliation) is the path.
The dashboard readings aggregate and round by design; the CSV the page
downloads carries the same per-record prices the API returns.

## 6. Role gate

The page is gated to **owner, admin, or billing** — the same roles the CDR
export API requires. The gate matches every sibling billing surface so a
finance operator never hits a 403 halfway through a reconciliation sweep. If
you can open `/billing/records` you can read and export the feed; the API is
equally gated.

## 7. Cross-links

* **[CDR usage export for billing reconciliation](/guides/cdr-usage-export-billing-reconciliation)**
  — the API-focused guide for `GET /usage/cdr` and
  `GET /usage/cdr/export.csv`: keyset-cursor pagination, the CSV column order,
  the rate limit and row cap, and the worked month-end reconciliation script.
  Read it when the dashboard's 100,000-row voice cap or 10,000-row message
  cap is too small, or when a warehouse sync needs the JSON drain.
* **[Revenue recognition: read deferred vs recognized schedules](/guides/billing-revenue-recognition)**
  — the downstream cost-center walkthrough for turning the records this page
  exports into a recognized-vs-deferred schedule per contract.
* **[Read the cost-intelligence dashboards](/guides/cost-intelligence)** —
  the **Billable usage records** panel on the cost-intelligence surface
  aggregates the same per-record feed this console exports into carrier-parity
  counters by SMS, MMS, and voice. Read it when the reconciliation question is
  "what does a carrier bill us for" rather than "which records sum to this
  invoice line."


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.