> This page is for version v2 (default).
> For other versions, use one of these documentation indexes:
> - v2 (default): https://docs.paid.ai/v-2/llms.txt
> - v1: https://docs.paid.ai/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.paid.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.paid.ai/_mcp/server.

# Analytics schema reference

> Every table and column you can query with the Analytics API

This page documents all 20 views available to the
[Analytics API](./overview). You can also fetch this live for your account from
`GET /schema`.

Conventions:

* **Monetary columns are cents**. Divide by 100 for display. Most are integers;
  `fact_cost.cost_amount` is fractional cents (Decimal).
* **Credits are not money and not whole numbers.** The `fact_credit_transaction`
  amount and balance columns are `Decimal(30, 6)`: a spend can be a fraction of
  a credit. Do not divide them by 100.
* **`UInt64`/`Int64` values are returned as JSON strings** (precision-safe); parse client-side.
* **`Decimal` values are returned as JSON numbers**, not strings; the 64-bit
  quoting above does not apply to them. A `Decimal` beyond 2^53 is therefore
  already rounded in the response; select `toString(col)` to get its exact
  digits as a string.
* `Nullable(...)` columns can be `null`.
* Facts join to dimensions on the `*_id` columns called out below.

## How the tables join

`dim_customer` is the hub: every fact table carries a `customer_id`. Usage
facts (`fact_signal`, `fact_cost`, `fact_delivered_value`) also carry a
`product_id` and link to each other through `trace_id` and `signal_id`.
Revenue facts chain from `fact_order` through `fact_order_line` to
`fact_invoice_line`, and `fact_payment` and `fact_usage_summary` tie back to
invoices and order lines. `fact_credit_transaction` joins to
`dim_credits_currency` for credit reporting.
Customer units (the teams, departments, or users inside a customer) are in
`dim_customer_unit`; `fact_signal` and `fact_credit_transaction` carry the unit
each row was attributed to. Spend caps on units are in `dim_customer_unit_cap`
(every version) and `dim_customer_unit_cap_current` (the cap in force now, with
its current period), and every change to a unit is in `fact_customer_unit_event`.

Common join keys:

| From                         | Column                      | To                                                  |
| ---------------------------- | --------------------------- | --------------------------------------------------- |
| any fact                     | `customer_id`               | `dim_customer.id`                                   |
| any fact                     | `product_id`                | `dim_product.id`                                    |
| `fact_signal`                | `trace_id`                  | `fact_cost.trace_id` (cost-per-signal)              |
| `fact_signal`                | `signal_id`                 | `fact_delivered_value.signal_id`                    |
| `fact_order`                 | `plan_id`                   | `dim_plan.id`                                       |
| `fact_invoice_line`          | `order_line_id`             | `fact_order_line.id` (revenue by product)           |
| `fact_payment`               | `invoice_id`                | `fact_invoice.id`                                   |
| `fact_credit_transaction`    | `credits_currency_id`       | `dim_credits_currency.id`                           |
| `fact_signal`                | `customer_unit_id`          | `dim_customer_unit.id`, with `customer_id`          |
| `fact_signal` (pending unit) | `external_customer_unit_id` | `dim_customer_unit.external_id`, with `customer_id` |
| `fact_credit_transaction`    | `external_customer_unit_id` | `dim_customer_unit.external_id`, with `customer_id` |
| `dim_customer_unit`          | `id`                        | `dim_customer_unit_ancestor.unit_id`                |
| `dim_customer_unit_cap*`     | `customer_unit_id`          | `dim_customer_unit.id`, with `customer_id`          |
| `dim_customer_unit_cap*`     | `customer_unit_id`          | `dim_customer_unit_ancestor.ancestor_id` (usage)    |
| `dim_customer_unit_cap*`     | `credits_currency_id`       | `dim_credits_currency.id`                           |
| `fact_customer_unit_event`   | `customer_unit_id`          | `dim_customer_unit.id`, with `customer_id`          |

## Dimensions

### `dim_customer`

One row per customer. Join `id` to any fact's `customer_id`. Supports hierarchy
rollups (`parent_customer_id`), segmentation (`annual_revenue`, `status`,
`churn_date`), and geography (`country`/`state`/`city`).

| Column               | Type                 | Description                                               |
| -------------------- | -------------------- | --------------------------------------------------------- |
| `id`                 | UUID                 | Internal customer UUID. Primary key.                      |
| `name`               | String               | Customer display name.                                    |
| `legal_name`         | String               | Legal entity name. May differ from display name.          |
| `email`              | String               | Primary email address.                                    |
| `external_id`        | String               | Customer ID in your external system.                      |
| `display_id`         | String               | Human-readable short id (e.g. CUST-001).                  |
| `parent_customer_id` | Nullable(UUID)       | Parent customer for hierarchy rollups. NULL if top-level. |
| `default_currency`   | String               | Default billing/reporting currency (e.g. USD).            |
| `status`             | String               | Lifecycle status (e.g. active, churned).                  |
| `churn_date`         | Nullable(DateTime64) | When the customer churned. NULL if active.                |
| `annual_revenue`     | Nullable(Int64)      | Self-reported annual revenue in whole dollars.            |
| `creation_source`    | String               | Acquisition channel/source (e.g. api, csv_import).        |
| `country`            | String               | Country from billing address.                             |
| `state`              | String               | State/region from billing address.                        |
| `city`               | String               | City from billing address.                                |
| `created_at`         | DateTime64           | When the record was created.                              |
| `updated_at`         | DateTime64           | When the record was last modified.                        |

### `dim_customer_unit`

One row per customer unit: a team, department, tenant, or user inside a
customer, arranged as a tree. Deleted and draft units stay in the table so their
history keeps a name.

Join from `fact_credit_transaction` on `customer_id` and
`external_customer_unit_id = external_id`. Join from `fact_signal` on
`customer_id` and `customer_unit_id = id`; when `customer_unit_id` is `null` (the
signal named a unit that did not exist yet), match `external_customer_unit_id =
external_id` within the same customer instead. Use `LEFT JOIN` so unassigned
usage stays in your totals: an unmatched row returns an empty `name`, not
`null`. See [usage by customer unit](./query-cookbook#customer-units) for
complete queries.

| Column          | Type             | Description                                                                                        |
| --------------- | ---------------- | -------------------------------------------------------------------------------------------------- |
| `id`            | UUID             | Customer unit UUID. Primary key.                                                                   |
| `customer_id`   | UUID             | Customer that owns the unit. Include it in every unit join.                                        |
| `parent_id`     | Nullable(UUID)   | Parent unit. `null` for the customer's root unit. Reflects the current tree.                       |
| `external_id`   | String           | Your key for the unit, unique within the customer.                                                 |
| `display_id`    | String           | Public id with the `cu_` prefix. Never empty.                                                      |
| `name`          | String           | Unit display name. Not unique, so group by `id` or `external_id`.                                  |
| `external_type` | Nullable(String) | Your label for the level, for example `department` or `team`.                                      |
| `status`        | String           | `ACTIVE`, `DELETED`, or `DRAFT`.                                                                   |
| `is_billable`   | Bool             | The unit's own current billable setting. `false` also applies to every unit below it. Not history. |
| `created_at`    | DateTime64       | When the unit was created.                                                                         |
| `updated_at`    | DateTime64       | When the unit was last modified.                                                                   |

### `dim_customer_unit_ancestor`

One row per unit and each unit above it, including the unit itself at depth 0.
Use it to total a unit together with everything below it: join the unit a fact
belongs to on `unit_id` and group by `ancestor_id`. A row counts once for every
ancestor, so report one level of the tree at a time.

| Column        | Type  | Description                                                         |
| ------------- | ----- | ------------------------------------------------------------------- |
| `customer_id` | UUID  | Customer that owns both units.                                      |
| `unit_id`     | UUID  | The unit. Join to `dim_customer_unit.id`.                           |
| `ancestor_id` | UUID  | The unit itself or a unit above it. Join to `dim_customer_unit.id`. |
| `depth`       | UInt8 | Steps from `unit_id` up to `ancestor_id`. `0` is the unit itself.   |

### `dim_customer_unit_cap`

One row per version of a spend cap on a customer unit, including versions that
were replaced or ended. A cap limits how many credits of one credits currency a
unit and every unit below it can spend per period. Changing a cap adds a
version; nothing is rewritten. For the cap that applies now, use
`dim_customer_unit_cap_current`.

Caps are spend policy: this table and `dim_customer_unit_cap_current` return
rows only to a caller that may read billing data, an API key with
`read:billing` or a dashboard user, and in a custom view only when the view has
`capsEnabled: true`. Anyone else gets no rows, not an error.

The cap in force at a time `t` is the highest `version` of the unit and credits
currency whose window covers `t`: `effective_from <= t` and `effective_until`
is `null` or after `t`.

| Column                | Type                 | Description                                                                                      |
| --------------------- | -------------------- | ------------------------------------------------------------------------------------------------ |
| `id`                  | UUID                 | Cap version UUID. Primary key.                                                                   |
| `customer_id`         | UUID                 | Customer that owns the unit.                                                                     |
| `customer_unit_id`    | UUID                 | Unit the cap sits on. Join to `dim_customer_unit.id`.                                            |
| `credits_currency_id` | UUID                 | Credits currency the cap limits. Caps on different currencies of one unit are separate limits.   |
| `amount`              | Decimal(30, 6)       | Cap per period, in credits.                                                                      |
| `frequency`           | String               | Period length. Always `MONTHLY` today.                                                           |
| `schedule_type`       | Nullable(String)     | `CALENDAR` (periods start on the 1st) or `ANCHORED` (on `anchor_day`). `null` on older versions. |
| `anchor_day`          | Nullable(UInt8)      | Day an `ANCHORED` period starts, 1 to 31; in shorter months, the last day.                       |
| `effective_from`      | DateTime64           | When this version starts (UTC).                                                                  |
| `effective_until`     | Nullable(DateTime64) | When this version ends (UTC), exclusive. `null` while open.                                      |
| `version`             | Int64                | Rank. The highest version covering an instant is the one in force.                               |
| `created_at`          | DateTime64           | When the version was written.                                                                    |
| `source`              | String               | Where it was written: `api`, `dashboard`, or `system`.                                           |

### `dim_customer_unit_cap_current`

The cap in force now on each unit and credits currency, with its current
period, resolved the same way as the customer unit cap endpoints. It has every column of
`dim_customer_unit_cap` plus:

| Column         | Type                 | Description                                                                 |
| -------------- | -------------------- | --------------------------------------------------------------------------- |
| `period_start` | Nullable(DateTime64) | Start of the current period, 00:00 UTC on the anchor day, inclusive.        |
| `period_end`   | Nullable(DateTime64) | End of the current period, exclusive. Periods are never cut short by a cap. |

Usage counted against a cap is the net `SPEND` of its credits currency by the
cap's unit and every unit below it, from `period_start` up to the earlier of
`period_end` and `effective_until`. See
[cap usage so far](./query-cookbook#spend-caps) for the query; it gives the
same figure as the cap API's `currentPeriod.used`. Caps on deleted units are
included, because they still apply to the units below until they are ended;
join `dim_customer_unit` and keep `status = 'ACTIVE'` to list only the caps the
API lists.

### `dim_product`

One row per product (also called an *agent*). Products are AI agents/services
or prepaid credit bundles. Join `id` to any fact's `product_id`.

| Column                | Type                 | Description                                                    |
| --------------------- | -------------------- | -------------------------------------------------------------- |
| `id`                  | UUID                 | Internal product UUID. Primary key.                            |
| `name`                | String               | Product display name.                                          |
| `description`         | String               | Product description.                                           |
| `external_id`         | String               | Product ID in your external system.                            |
| `display_id`          | String               | Human-readable short id (e.g. PRD-001).                        |
| `product_code`        | String               | Internal/external product code or SKU.                         |
| `type`                | String               | `agent` (AI agent/service) or `prepaidCreditBundle`.           |
| `active`              | Bool                 | Whether the product is currently active/sellable.              |
| `credits_currency_id` | Nullable(UUID)       | For `prepaidCreditBundle` products, the credits currency sold. |
| `metadata`            | String               | User-defined JSON metadata.                                    |
| `archived_at`         | Nullable(DateTime64) | When archived. NULL if active.                                 |
| `created_at`          | DateTime64           | When the product was created.                                  |
| `updated_at`          | DateTime64           | When the product was last modified.                            |

### `dim_plan`

A plan is a pricing configuration within a plan group. Plans form an
upgrade/downgrade chain via `has_next_plan`/`has_prev_plan`. Join from
`fact_order.plan_id`.

| Column              | Type       | Description                                                   |
| ------------------- | ---------- | ------------------------------------------------------------- |
| `id`                | UUID       | Plan UUID. Primary key.                                       |
| `name`              | String     | Plan display name (e.g. Free, Standard, Premium).             |
| `description`       | String     | Plan description.                                             |
| `plan_group_id`     | UUID       | Groups related plans (e.g. tiers of a pricing page).          |
| `type`              | String     | `flat` (fixed fee), `usage` (metered), or `credit` (prepaid). |
| `billing_frequency` | String     | How often billed (e.g. monthly, yearly).                      |
| `billing_type`      | String     | `Advance` (pre-pay) or `Arrears` (post-pay).                  |
| `has_next_plan`     | UInt8      | 1 if a higher-tier plan exists, else 0.                       |
| `has_prev_plan`     | UInt8      | 1 if a lower-tier plan exists, else 0.                        |
| `created_at`        | DateTime64 | When the plan was created.                                    |
| `updated_at`        | DateTime64 | When the plan was last modified.                              |

### `dim_credits_currency`

Defines the types of credits your organization uses. Join from
`fact_credit_transaction.credits_currency_id` or `dim_product.credits_currency_id`.

| Column        | Type                 | Description                                  |
| ------------- | -------------------- | -------------------------------------------- |
| `id`          | UUID                 | Credits currency UUID. Primary key.          |
| `name`        | String               | Display name (e.g. "AI Credits").            |
| `key`         | String               | Unique programmatic key (e.g. "ai_credits"). |
| `description` | String               | What this credits currency represents.       |
| `archived_at` | Nullable(DateTime64) | When archived. NULL if active.               |
| `created_at`  | DateTime64           | When created.                                |
| `updated_at`  | DateTime64           | When last modified.                          |

### `dim_organization`

Your organization. Typically one row.

| Column       | Type       | Description                     |
| ------------ | ---------- | ------------------------------- |
| `id`         | UUID       | Organization UUID. Primary key. |
| `name`       | String     | Organization display name.      |
| `created_at` | DateTime64 | When created.                   |
| `updated_at` | DateTime64 | When last modified.             |

## Usage

### `fact_signal`

One row per signal (event). This is the core usage metric. `COUNT` over time, group by
`signal_name`, `customer_id`, or `product_id`. Join `trace_id` to `fact_cost`
for cost-per-signal, or `signal_id` to `fact_delivered_value` for value
delivered.

| Column                      | Type             | Description                                                                                                                       |
| --------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `signal_id`                 | String           | Unique signal id (MongoDB ObjectID, not a UUID). Primary key.                                                                     |
| `signal_name`               | String           | Signal type name (e.g. api_call, document_processed).                                                                             |
| `product_id`                | Nullable(UUID)   | Product (agent) that generated the signal.                                                                                        |
| `customer_id`               | Nullable(UUID)   | Customer the signal is attributed to.                                                                                             |
| `trace_id`                  | Nullable(String) | OpenTelemetry trace id. Join to `fact_cost.trace_id`.                                                                             |
| `has_delivered_value`       | UInt8            | 1 if the signal has delivered-value calculations.                                                                                 |
| `data`                      | JSON             | Your free-form JSON payload. Schema varies per `signal_name`. See [querying metadata](./query-cookbook#querying-signal-metadata). |
| `created_at`                | DateTime64       | When Paid recorded the signal. For backfilled signals this is the send time.                                                      |
| `effective_timestamp`       | DateTime64       | When the usage happened: `data.historicalTimestamp` if sent, else `created_at`. Use for time-series.                              |
| `customer_unit_id`          | Nullable(UUID)   | Customer unit the signal was attributed to. `null` when no unit was named or the named unit did not exist yet.                    |
| `external_customer_unit_id` | Nullable(String) | Unit key sent with the signal. Use it to find the unit only when `customer_unit_id` is `null`.                                    |

## Cost

### `fact_cost`

One row per AI/LLM call. `SUM(cost_amount)` for total spend; group by
`vendor`, `model`, `customer_id`, or `product_id`. Includes token usage and
latency.

`cost_amount` is exact fractional cents: a single AI call usually costs a
fraction of a cent, so values look like `3.71` (= \$0.0371). Sums match the
Cost Explorer in the Paid UI.

| Column                 | Type             | Description                                                               |
| ---------------------- | ---------------- | ------------------------------------------------------------------------- |
| `cost_id`              | String           | Unique cost trace id (MongoDB ObjectID). Primary key.                     |
| `trace_id`             | String           | OpenTelemetry trace id. Join to `fact_signal.trace_id`.                   |
| `customer_id`          | Nullable(UUID)   | Customer attributed. NULL if unattributed.                                |
| `external_customer_id` | Nullable(String) | External customer id you provided.                                        |
| `product_id`           | Nullable(UUID)   | Product attributed. NULL if unattributed.                                 |
| `external_agent_id`    | Nullable(String) | External product/agent id you provided.                                   |
| `vendor`               | String           | AI provider (e.g. openai, anthropic, mistral).                            |
| `model`                | String           | Model identifier (e.g. gpt-4, claude-3-sonnet).                           |
| `trace_name`           | String           | Operation type (e.g. chat, embeddings).                                   |
| `cost_amount`          | Decimal(28, 8)   | Exact cost in cents, fractional. `SUM` and divide by 100 for total spend. |
| `cost_currency`        | String           | Currency code for `cost_amount`.                                          |
| `input_tokens`         | Int64            | Input/prompt tokens consumed. 0 if unavailable.                           |
| `output_tokens`        | Int64            | Output/completion tokens generated. 0 if unavailable.                     |
| `signal_name`          | Nullable(String) | Linked signal name, if attributed.                                        |
| `start_time`           | DateTime64       | When the call started. Use for time-series.                               |
| `end_time`             | DateTime64       | When the call completed.                                                  |
| `duration_ms`          | Int64            | Call duration in milliseconds.                                            |
| `pricing_used`         | Nullable(String) | JSON of the pricing config used. NULL on older traces.                    |

## Delivered value

### `fact_delivered_value`

The business value delivered per signal, by value type. Join `signal_id` to
`fact_signal`, or `customer_id`/`product_id` to dimensions.

Rows can be denominated in **different currencies**: organizations using
value models can configure non-USD currencies, and `delivered_value_cents`
is always in that row's `delivered_value_currency`. Never sum
`delivered_value_cents` across currencies; group by
`delivered_value_currency` (or filter to one currency) first.

| Column                     | Type             | Description                                                                                                                     |
| -------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `signal_id`                | String           | Source signal id (MongoDB ObjectID).                                                                                            |
| `signal_name`              | String           | Semantic event type name.                                                                                                       |
| `organization_id`          | String           | Organization that owns the signal.                                                                                              |
| `product_id`               | Nullable(String) | Internal product UUID.                                                                                                          |
| `customer_id`              | Nullable(String) | Internal customer UUID.                                                                                                         |
| `value_type_id`            | String           | Value type identifier (UUID for legacy rows, slug for value-model rows).                                                        |
| `value_type_name`          | String           | Display name of the value type.                                                                                                 |
| `value_type_slug`          | String           | Stable slug for the value type.                                                                                                 |
| `delivered_value_cents`    | Decimal(28, 8)   | Exact monetary value in cents, in `delivered_value_currency`. May carry fractional cents; round after aggregating, not per row. |
| `delivered_value_currency` | String           | Currency code the cents are denominated in (e.g. USD, EUR). Not always USD.                                                     |
| `unit_value`               | Float64          | Raw unit value (e.g. hours saved).                                                                                              |
| `unit`                     | String           | Unit identifier.                                                                                                                |
| `unit_category`            | String           | Unit category (e.g. duration, count).                                                                                           |
| `effective_timestamp`      | DateTime64       | Historical timestamp, else created_at.                                                                                          |
| `created_at`               | DateTime64       | When the source signal was created.                                                                                             |

## Revenue and billing

### `fact_order`

Contracts and subscriptions. One row per order. Join `customer_id` to
`dim_customer`, `plan_id` to `dim_plan`. Compare `total_billed_amount` to
`total_amount` for billing progress.

| Column                   | Type                 | Description                                       |
| ------------------------ | -------------------- | ------------------------------------------------- |
| `id`                     | UUID                 | Order UUID. Primary key.                          |
| `display_id`             | String               | Human-readable order id.                          |
| `external_id`            | String               | Order id in your external system.                 |
| `customer_id`            | UUID                 | Customer who owns the contract.                   |
| `billing_customer_id`    | Nullable(UUID)       | Bill-to customer if different from `customer_id`. |
| `plan_id`                | Nullable(UUID)       | Pricing plan. NULL if none attached.              |
| `name`                   | String               | Order display name.                               |
| `status`                 | String               | `draft` or `active`.                              |
| `currency`               | String               | ISO currency code.                                |
| `total_amount`           | Int64                | Total contract value (cents) over the full term.  |
| `order_amount`           | Int64                | Order amount (cents) before billing.              |
| `total_billed_amount`    | Int64                | Cumulative billed so far (cents, incl tax).       |
| `billed_amount_no_tax`   | Int64                | Total billed excluding tax (cents).               |
| `billed_tax`             | Int64                | Total tax billed so far (cents).                  |
| `pending_billing_amount` | Int64                | Amount not yet billed (cents).                    |
| `payment_terms`          | String               | DueOnReceipt, Net15, Net30, …                     |
| `subscription_terms`     | Int32                | Term length in billing periods.                   |
| `start_date`             | DateTime64           | Contract start date.                              |
| `end_date`               | Nullable(DateTime64) | Contract end date. NULL if open-ended.            |
| `metadata`               | String               | User-defined JSON metadata.                       |
| `created_at`             | DateTime64           | When created.                                     |
| `updated_at`             | DateTime64           | When last modified.                               |

### `fact_order_line`

Product-level order line items link products to revenue. `SUM(total_amount)`
by `product_id` for revenue-by-product. Filter `effective_until IS NULL` for
current lines only.

| Column                 | Type                 | Description                                       |
| ---------------------- | -------------------- | ------------------------------------------------- |
| `id`                   | UUID                 | Order line UUID. Primary key.                     |
| `display_id`           | String               | Human-readable line id.                           |
| `order_id`             | UUID                 | Parent order. Join to `fact_order.id`.            |
| `product_id`           | UUID                 | Product on this line. Join to `dim_product.id`.   |
| `customer_id`          | UUID                 | Customer who owns the order (denormalized).       |
| `currency`             | String               | Currency code (denormalized from order).          |
| `name`                 | String               | Line item name.                                   |
| `description`          | String               | Line item description.                            |
| `line_type`            | String               | STANDARD, PRORATION_CREDIT, or PRORATION_CHARGE.  |
| `status`               | String               | `draft` or `active`.                              |
| `total_amount`         | Int64                | Line total contract value (cents).                |
| `total_billed_amount`  | Int64                | Cumulative billed on this line (cents, incl tax). |
| `billed_amount_no_tax` | Int64                | Total billed excluding tax (cents).               |
| `billed_tax`           | Int64                | Tax billed on this line (cents).                  |
| `effective_until`      | Nullable(DateTime64) | When superseded by an amendment. NULL = current.  |
| `start_date`           | DateTime64           | Line billing start date.                          |
| `end_date`             | Nullable(DateTime64) | Line billing end date. NULL if open-ended.        |
| `created_at`           | DateTime64           | When created.                                     |
| `updated_at`           | DateTime64           | When last modified.                               |

### `fact_invoice`

One row per invoice. `SUM(total_incl_tax)` for revenue; filter `status = 'posted'`
for finalized invoices. Use `due_date` + `payment_status` for aging analysis.

| Column               | Type                 | Description                                                |
| -------------------- | -------------------- | ---------------------------------------------------------- |
| `id`                 | UUID                 | Invoice UUID. Primary key.                                 |
| `display_number`     | String               | Human-readable invoice number (e.g. INV-001).              |
| `display_id`         | String               | Short id shown in the UI.                                  |
| `customer_id`        | UUID                 | Customer billed. Join to `dim_customer.id`.                |
| `order_id`           | Nullable(UUID)       | Order this invoice belongs to. NULL for manual invoices.   |
| `status`             | String               | building, draft, pending, posted, voided, canceled, error. |
| `payment_status`     | String               | pending, paid, partiallyPaid, overdue, error.              |
| `source`             | String               | order_based or manual.                                     |
| `currency`           | String               | ISO currency code.                                         |
| `total_excl_tax`     | Int64                | Total excluding tax (cents).                               |
| `total_incl_tax`     | Int64                | Total including tax (cents). **Primary revenue metric.**   |
| `tax_amount`         | Int64                | Tax amount (cents).                                        |
| `tax_rate`           | Float64              | Tax rate as a fraction (0.2 = 20%).                        |
| `tax_exempt`         | Bool                 | Whether the invoice is tax-exempt.                         |
| `discount_amount`    | Int64                | Total discount applied (cents).                            |
| `amount_paid`        | Int64                | Amount collected (cents).                                  |
| `amount_due`         | Int64                | Outstanding amount owed (cents).                           |
| `amount_remaining`   | Int64                | Remaining balance after payments and credit notes (cents). |
| `credit_notes_total` | Int64                | Total credited back via credit notes (cents).              |
| `issue_date`         | DateTime64           | When issued. **Primary date for revenue time-series.**     |
| `posted_date`        | Nullable(DateTime64) | When finalized/posted. Use for revenue recognition.        |
| `due_date`           | Nullable(DateTime64) | Payment due date.                                          |
| `start_date`         | DateTime64           | Billing period start.                                      |
| `end_date`           | Nullable(DateTime64) | Billing period end.                                        |
| `metadata`           | String               | User-defined JSON metadata.                                |
| `created_at`         | DateTime64           | When created.                                              |
| `updated_at`         | DateTime64           | When last modified.                                        |

### `fact_invoice_line`

One row per line on an invoice. Join `order_line_id` → `fact_order_line.id` →
`dim_product.id` to break invoiced revenue down by product.

| Column                    | Type           | Description                                                                                                                                     |
| ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                      | UUID           | Invoice line UUID. Primary key.                                                                                                                 |
| `display_id`              | String         | Human-readable line id.                                                                                                                         |
| `invoice_id`              | UUID           | Parent invoice. Join to `fact_invoice.id`.                                                                                                      |
| `order_id`                | Nullable(UUID) | Order this line relates to.                                                                                                                     |
| `order_line_id`           | Nullable(UUID) | Order line this was generated from.                                                                                                             |
| `description`             | String         | Line item description.                                                                                                                          |
| `payment_status`          | String         | pending, paid, partiallyPaid, overdue, error.                                                                                                   |
| `currency`                | String         | ISO currency code.                                                                                                                              |
| `quantity`                | Int32          | Quantity billed (e.g. signals, seats, units).                                                                                                   |
| `amount_before_discount`  | Int64          | Amount before discounts (cents).                                                                                                                |
| `discount_amount`         | Int64          | Discount applied (cents).                                                                                                                       |
| `total_before_tax`        | Int64          | Total after discount, before tax (cents).                                                                                                       |
| `tax`                     | Int64          | Tax amount (cents).                                                                                                                             |
| `tax_rate`                | Float64        | Tax rate as a fraction.                                                                                                                         |
| `total_after_tax`         | Int64          | Total including tax (cents). **Primary per-line revenue metric.**                                                                               |
| `balance_amount`          | Int64          | Unpaid balance remaining (cents).                                                                                                               |
| `credited_amount`         | Int64          | Amount credited back via credit notes (cents).                                                                                                  |
| `start_date`              | DateTime64     | Billing period start.                                                                                                                           |
| `end_date`                | DateTime64     | Billing period end.                                                                                                                             |
| `created_at`              | DateTime64     | When created.                                                                                                                                   |
| `updated_at`              | DateTime64     | When last modified.                                                                                                                             |
| `order_line_attribute_id` | Nullable(UUID) | Priced attribute this line bills. Carries the pricing config. NULL for manual lines.                                                            |
| `charge_type`             | String         | How the line is charged: `oneTime`, `recurring`, `seatBased` (all fixed) or `usage` (metered). Empty for manual lines.                          |
| `billing_type`            | String         | `Advance` (pre-pay) or `Arrears` (post-pay). Empty if unknown.                                                                                  |
| `pricing_model`           | String         | `PerUnit`, `VolumePricing`, `GraduatedPricing`, `PrepaidCredits`, `BracketedPrepaidCredits`, `PercentOfTotal`, or `CostPlus`. Empty if unknown. |

### `fact_payment`

One row per payment received. `SUM(amount)` for cash collected; filter
`payment_status = 'posted'` for confirmed payments. Join `invoice_id` to
`fact_invoice.id` for reconciliation.

| Column           | Type           | Description                                                     |
| ---------------- | -------------- | --------------------------------------------------------------- |
| `id`             | UUID           | Payment UUID. Primary key.                                      |
| `display_id`     | String         | Human-readable payment id.                                      |
| `customer_id`    | UUID           | Customer who paid. Join to `dim_customer.id`.                   |
| `invoice_id`     | Nullable(UUID) | Invoice this payment is applied to.                             |
| `order_id`       | Nullable(UUID) | Order this payment is associated with.                          |
| `payment_type`   | String         | creditCard, bankTransfer, ach, cash, check.                     |
| `payment_status` | String         | draft, posted, canceled, processing, failed, requiresAction.    |
| `amount`         | Int64          | Payment amount (cents).                                         |
| `currency`       | String         | ISO currency code.                                              |
| `allocations`    | Int64          | Amount allocated to invoice lines (cents).                      |
| `balance`        | Int64          | Unallocated balance remaining (cents).                          |
| `payment_date`   | DateTime64     | When paid/received. **Primary date for cash-flow time-series.** |
| `metadata`       | String         | User-defined JSON metadata.                                     |
| `created_at`     | DateTime64     | When created.                                                   |
| `updated_at`     | DateTime64     | When last modified.                                             |

### `fact_usage_summary`

Usage per signal per billing window: one row per priced attribute of an order
line per billing window, built from the same billing record as invoicing.
Filter `status = 'billed'` and `SUM(subtotal)` by `signal_name` to see which
signals drive revenue. Compare `signals_quantity` to `included_quantity` to see
overage.

| Column                    | Type            | Description                                                                                                                                                     |
| ------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                      | UUID            | Billing window id, stable and one per attribute and window. The same id the usage cells API returns.                                                            |
| `customer_id`             | UUID            | Customer this usage is for.                                                                                                                                     |
| `order_id`                | UUID            | Order this usage is billed under.                                                                                                                               |
| `order_line_id`           | UUID            | Order line attributed. Join for usage-by-product.                                                                                                               |
| `invoice_id`              | Nullable(UUID)  | Invoice the window was billed on. NULL while collecting and for skipped windows.                                                                                |
| `signal_name`             | String          | Signal name this usage relates to.                                                                                                                              |
| `status`                  | String          | `collecting` (open), `billed` (closed onto an invoice), `skipped` (closed with nothing to bill), or `voided` (billed onto an invoice later voided or canceled). |
| `currency`                | String          | Currency code for `subtotal`.                                                                                                                                   |
| `signals_quantity`        | Int64           | Usage quantity. Once closed, the quantity the window was billed on (for meter-backed products, the meter's result); while collecting, the signals so far.       |
| `signal_count`            | Int64           | Net number of signals in the window: signals counted minus signals moved out, for example by an order amendment.                                                |
| `included_quantity`       | Nullable(Int64) | Units included free before billing. NULL if none.                                                                                                               |
| `min_quantity`            | Nullable(Int64) | Minimum billable quantity (minimum commit). NULL if none.                                                                                                       |
| `subtotal`                | Nullable(Int64) | Billed amount in cents, before discount and tax: the invoice line's amount. 0 when skipped. **NULL while collecting**; `SUM` skips NULLs.                       |
| `start_date`              | DateTime64      | Billing window start.                                                                                                                                           |
| `end_date`                | DateTime64      | Billing window end.                                                                                                                                             |
| `created_at`              | DateTime64      | When the window's first usage was recorded.                                                                                                                     |
| `updated_at`              | DateTime64      | When usage or the close last changed the window.                                                                                                                |
| `order_line_attribute_id` | UUID            | Priced attribute of the order line. With `next_billing_date`, the window's key.                                                                                 |
| `invoice_line_id`         | Nullable(UUID)  | Invoice line the window was billed on. Join to `fact_invoice_line.id`. NULL while collecting and for skipped windows.                                           |
| `next_billing_date`       | DateTime64      | Billing date that closes the window.                                                                                                                            |

A few rows from older billing share one invoice line between two windows; the
line's amount is split between them, so `SUM(subtotal)` still matches the
invoice.

**Consistency.** Billing windows and invoices are copied into the analytics
store independently. Just after a window closes, it can briefly read `billed`
with `invoice_id`, `invoice_line_id` and `subtotal` still NULL, until its
invoice arrives. A billed window whose invoice line was later deleted keeps
`invoice_id`, `invoice_line_id` and `subtotal` NULL.

## Credits

### `fact_credit_transaction`

One row per credit grant, spend, or pending grant. Filter `type = 'SPEND'` for
consumption; group by `signal_name` or `product_id` for usage breakdowns. Join
`credits_currency_id` to `dim_credits_currency`.

| Column                      | Type                 | Description                                                              |
| --------------------------- | -------------------- | ------------------------------------------------------------------------ |
| `id`                        | UUID                 | Credit transaction UUID. Primary key.                                    |
| `customer_id`               | UUID                 | Customer this transaction belongs to.                                    |
| `product_id`                | Nullable(UUID)       | Product associated. NULL for non-product grants.                         |
| `credits_currency_id`       | UUID                 | Which credits currency was used.                                         |
| `order_id`                  | Nullable(UUID)       | Order that triggered this transaction.                                   |
| `type`                      | String               | GRANT, SPEND, or PENDING_GRANT.                                          |
| `origin_code`               | String               | Always empty; origin now lives on the grant. Kept for compatibility.     |
| `amount`                    | Decimal(30, 6)       | Credit amount, fractional. Positive for grants, negative for spends.     |
| `balance_before`            | Decimal(30, 6)       | Balance before this transaction.                                         |
| `balance_after`             | Decimal(30, 6)       | Balance after this transaction.                                          |
| `signal_name`               | String               | Signal that triggered the spend. Empty if not signal-triggered.          |
| `signal_mongo_id`           | String               | Id of the triggering signal. Links to `fact_signal.signal_id`.           |
| `signal_created_at`         | Nullable(DateTime64) | When the triggering signal was created.                                  |
| `spend_group_id`            | Nullable(UUID)       | Groups related spends from the same signal.                              |
| `created_at`                | DateTime64           | When the transaction occurred.                                           |
| `external_customer_unit_id` | Nullable(String)     | Key of the customer unit the credits moved for. `null` if none.          |
| `effective_at`              | Nullable(DateTime64) | Business-effective time. Report on `coalesce(effective_at, created_at)`. |

## Customer unit history

### `fact_customer_unit_event`

One row per change to a customer unit: created, renamed, retyped, made billable
or non-billable, moved, or deleted. Rows are never changed or removed. A unit's
state at a time `t` is its last event at or before `t`; order by `version` to
replay changes in order. Who made a change and unit metadata values are not
included.

| Column                    | Type             | Description                                                                                 |
| ------------------------- | ---------------- | ------------------------------------------------------------------------------------------- |
| `id`                      | UUID             | Event UUID. Primary key.                                                                    |
| `customer_id`             | UUID             | Customer that owns the unit.                                                                |
| `customer_unit_id`        | UUID             | Unit that changed. Join to `dim_customer_unit.id`.                                          |
| `external_id`             | String           | Your key for the unit.                                                                      |
| `event_type`              | String           | `CREATED`, `UPDATED`, `MOVED`, or `DELETED`.                                                |
| `from_parent_id`          | Nullable(UUID)   | Parent before the change. `null` on `CREATED` and for a root.                               |
| `to_parent_id`            | Nullable(UUID)   | Parent after the change, on every event. `null` for a root.                                 |
| `from_parent_external_id` | Nullable(String) | Key of the parent before the change.                                                        |
| `to_parent_external_id`   | Nullable(String) | Key of the parent after the change.                                                         |
| `depth_before`            | Nullable(Int16)  | Depth before the change; the root is 1. `null` on `CREATED`.                                |
| `depth_after`             | Int16            | Depth after the change.                                                                     |
| `subtree_size`            | Nullable(Int32)  | Units carried by a move, the unit included. `MOVED` only.                                   |
| `name_before`             | Nullable(String) | Name before the change. `null` on `CREATED`.                                                |
| `name_after`              | String           | Name after the change.                                                                      |
| `external_type_before`    | Nullable(String) | Level label before the change.                                                              |
| `external_type_after`     | Nullable(String) | Level label after the change.                                                               |
| `status_before`           | Nullable(String) | `ACTIVE`, `DELETED`, or `DRAFT` before the change.                                          |
| `status_after`            | String           | Status after the change.                                                                    |
| `is_billable_before`      | Nullable(Bool)   | The unit's own billable setting before the change. `null` on `CREATED` and on older events. |
| `is_billable_after`       | Nullable(Bool)   | The unit's own billable setting after the change. `null` on older events.                   |
| `changed_fields`          | Array(String)    | What changed: `name`, `external_type`, `status`, `is_billable`, `metadata`, `parent`.       |
| `actor_type`              | String           | `user`, `api_key`, or `system` (Paid itself, for example a unit created at ingest).         |
| `source`                  | String           | `api`, `dashboard`, or `system`.                                                            |
| `created_at`              | DateTime64       | When the change was made (UTC).                                                             |
| `version`                 | Int64            | Order of the change. Sort by this, not `created_at`.                                        |

## Changelog

**October 2026: `fact_usage_summary` is built from the billing record.** It now
reads the same record invoicing uses. Before, windows closed after September 17,
2026 stayed `collecting` with no invoice, so billed revenue was undercounted.
What changes:

* **`id`** is the billing window id the usage cells API returns. It is stable,
  but it is not the id this table returned before.
* **`subtotal`** is `Nullable(Int64)`: NULL while a window is collecting, since
  the amount is decided when the window closes. Before, it showed a running
  estimate. `SUM(subtotal)` skips NULLs; use `coalesce(subtotal, 0)` where a
  number is required.
* **`status`** adds `skipped`, for a window closed with nothing to bill.
  `voided` now means the window was billed onto an invoice that was later
  voided or canceled.
* There is one row per billing window. Closed windows with no usage now
  appear, usually as `skipped`.
* **New columns**, appended after the existing ones:
  `order_line_attribute_id`, `invoice_line_id`, and `next_billing_date`.

## Related

* [Analytics API overview](./overview) for endpoints, limits, and errors.
* [Query cookbook](./query-cookbook) for ready-to-use SQL recipes.