---
title: "Posted revenue by revenue GL account over completed months"
method: GET
path: "/companies/{companyId}/metrics/revenue-by-product"
tags: ["Overview"]
---

# Posted revenue by revenue GL account over completed months

`GET /companies/{companyId}/metrics/revenue-by-product`

## Request

- Base URL: `https://api.medianfi.com/api/v1`
- URL: `https://api.medianfi.com/api/v1/companies/{companyId}/metrics/revenue-by-product`
- Auth: HTTP bearer

Posted operating revenue for the selected entity over the resolved completed-month window (#2414, #2637). The chart of accounts carries the products (#3211): a product is an operating, credit-normal, non-contra revenue GL account, whether or not it carries a product key (J-364 keys name products for Stripe routing only). `rows` are those accounts with non-zero revenue, labelled by account name, and `total` ("Product revenue") is their sum. `unattributedRevenue` is 4999 Uncategorized Income only, and `mappingComplete` is always true. Refunds and discounts (contra or debit-normal revenue accounts) are `refundsAndDiscounts`, signed, and never a product. The tie-out holds exactly (J-367): total + unattributedRevenue + refundsAndDiscounts = operatingRevenue, the P&L operating revenue (Revenue accounts excluding other income and 4999) for the same entity and months. Amounts are exact minor units; no percentages are published. A window month with no posted books is available:false insufficient_history with the missing months named. The current partial month is never included. `eligibility` carries the company-level card visibility over the last 12 completed months (see RevenueByProductEligibility); it does not change the selected window's rows or census.

## Query parameters

- `entityId` string, uuid, required
- `months` 1 | 3 | 6 | 12

## Response `200`

Revenue-by-product metric envelope

- RevenueByProductMetricResponse
  - `success` true, required
  - `data` RevenueByProductMetric, required
    - `available` boolean, required
    - `value` RevenueByProductValue
      - `total` ExactMoney, required: Exact money value: signed integer minor units as a string (never a float), with explicit currency and minor-unit exponent.
        - `amountMinor` string, required: Signed integer minor units, e.g. "80000" = $800.00 at exponent 2.
        - `currency` string, required
        - `minorUnitExponent` integer, required
      - `rows` RevenueByProductRow[], required: Product accounts (operating, non-contra revenue accounts, tagged or not) with non-zero posted revenue in the window. A product account's net can be negative.
        - `key` string, required: "gl:<glAccountId>". Rows are sorted by minor units descending, then label.
        - `label` string, required: The product account's name.
        - `glAccountId` string, required
        - `money` ExactMoney, required: Exact money value: signed integer minor units as a string (never a float), with explicit currency and minor-unit exponent.
          - `amountMinor` string, required: Signed integer minor units, e.g. "80000" = $800.00 at exponent 2.
          - `currency` string, required
          - `minorUnitExponent` integer, required
      - `unattributedRevenue` ExactMoney, required: Exact money value: signed integer minor units as a string (never a float), with explicit currency and minor-unit exponent.
        - `amountMinor` string, required: Signed integer minor units, e.g. "80000" = $800.00 at exponent 2.
        - `currency` string, required
        - `minorUnitExponent` integer, required
      - `refundsAndDiscounts` ExactMoney, required: Exact money value: signed integer minor units as a string (never a float), with explicit currency and minor-unit exponent.
        - `amountMinor` string, required: Signed integer minor units, e.g. "80000" = $800.00 at exponent 2.
        - `currency` string, required
        - `minorUnitExponent` integer, required
      - `operatingRevenue` ExactMoney, required: Exact money value: signed integer minor units as a string (never a float), with explicit currency and minor-unit exponent.
        - `amountMinor` string, required: Signed integer minor units, e.g. "80000" = $800.00 at exponent 2.
        - `currency` string, required
        - `minorUnitExponent` integer, required
      - `mappingComplete` boolean, required: Always true since
    - `reason` 'insufficient_history' | 'failed' | 'mixed_currency' | 'entity_scope_unavailable' | 'incomplete_provenance' | 'truncated': Present only when available is false; public-safe.
    - `diagnostic` object
      - `missingMonths` string[], required: Window months with no posted-books evidence.
    - `authority` RevenueByProductAuthority
      - `companyId` string, uuid, required
      - `entityId` string, uuid, required
      - `basis` 'posted_revenue_by_gl_account', required
      - `asOf` string, date-time, required
      - `startMonth` string, required
      - `endMonth` string, required
      - `monthKeys` string[], required
    - `completeness` MetricCompleteness, required: Coverage assertion for a per-metric value/authority contract. An available metric carries all three booleans as true.
      - `windowComplete` boolean, required
      - `sourceComplete` boolean, required
      - `provenanceComplete` boolean, required
      - `historyCompleteFrom` string
      - `booksAsOf` string
      - `sourceGeneration` string
    - `eligibility` RevenueByProductEligibility: Home card visibility (#2414) is decided at company level rather than per selected window (read per entity, like the rows). It stays visible when at least two non-contra operating revenue accounts have posted activity over the last 12 completed months, including generic accounts that still need attribution. revenueAccountCount separately reports how many of those accounts are explicitly tagged as products. Refunds and non-operating income do not count. Lookback months the posted books do not cover carry no lines and are simply not counted; they never make eligibility unavailable. Present on both available and unavailable branches; absent only when the eligibility read itself could not be made.
      - `eligible` boolean, required: True when at least two non-contra operating revenue accounts have posted activity, so incomplete mapping remains visible.
      - `revenueAccountCount` integer, required: Distinct explicitly tagged product accounts with nonzero posted activity in the lookback.
      - `minimumRevenueAccounts` 2, required
      - `authority` object, required
        - `startMonth` string, required
        - `endMonth` string, required: The last completed month; the current partial month is never counted.
        - `monthKeys` string[], required: The 12 lookback months, ascending.
        - `coveredMonthKeys` string[], required: Lookback months the posted books cover (the months actually counted), ascending.

## Other responses

- `401`: Authentication required
- `403`: Insufficient permissions or not a company member
- `404`: The revenue-by-product service is not wired in this deployment. This is the documented fail-closed default for the whole /metrics subtree, and the state a not-yet-deployed environment returns — a generated client needs this branch, it is not an error condition.
- `422`: Request failed validation
- `503`: The legal-entity scope authority could not be read

---

[API](https://skmtc.dev/medianfi/apis/median-api.md) · [All operations](https://skmtc.dev/medianfi/apis/median-api/llms.txt) · [OpenAPI document](https://skmtc.dev/medianfi/apis/median-api/revisions/20090ea32b0d?raw)
