---
title: "Profit and loss statement"
method: GET
path: "/companies/{companyId}/reports/pl"
tags: ["Reports"]
---

# Profit and loss statement

`GET /companies/{companyId}/reports/pl`

## Request

- Base URL: `https://api.medianfi.com/api/v1`
- URL: `https://api.medianfi.com/api/v1/companies/{companyId}/reports/pl`
- Auth: HTTP bearer

P&L over a date range. When `startDate` and `endDate` are omitted the latest posted month is returned (backward-compatible with pre-date-range clients); `allTime=true` spans the first through the last posted month. `comparePeriod` optionally returns a side-by-side comparison column; `prior-period` shifts back by the range length (snapped to full months when month-aligned), `prior-year` shifts both dates back 12 months.

## Query parameters

- `entityId` string, uuid
- `reportingScopeId` string, uuid
- `scopeAsOf` string, date
- `startDate` string, date
- `endDate` string, date
- `allTime` 'true'
- `comparePeriod` 'none' | 'prior-period' | 'prior-year'
- `granularity` 'month' | 'quarter' | 'year'
- `classId` string
- `groupBy` 'class'
- `tagId` union
  - string
  - string[]
- `month` string

## Response `200`

P&L payload. Includes legacy numeric/boolean self-check fields and additive `checks` execution evidence for arithmetic and monthly-cache reconciliation. `isConsistent: true` alone does not prove all checks ran. When a comparison is requested, an optional `comparison` object with the same shape plus `mode`, `startDate`, `endDate`, `period` and `hasData` is included on the payload.

- object
  - `success` boolean
  - `data` object: Compatibility fields plus explicit check evidence for P&L/cash flow. isConsistent remains boolean: false for any executed failure, true otherwise (including skipped checks). It is not proof that all checks ran. Legacy differences remain integers; skipped differences retain zero. Inspect checks for execution, signed differences, applicability and per-check tolerances.
    - `configuredBasis` 'cash' | 'accrual' | 'unknown', required
    - `configuredBasisSource` 'statement_basis' | 'tax_settings' | 'company' | 'missing' | 'unavailable', required
    - `reportBasis` 'accrual' | 'cash', required
    - `fiscalYearEnd` string, nullable: companies.fiscal_year_end (MM-DD); null when not confirmed (#2019).
    - `fiscalYearReview` union: True when companies.fiscal_year_end is set and is not 12-31, or tax_settings.fiscal_year_end (month) is set and is not 12. Non-calendar fiscal years are not supported yet, so the statement is still calendar-year and must be reviewed. It is "unknown" when the company or tax-settings fiscal year end could not be read, never a silent false (#2019).
      - boolean
      - 'unknown'
    - `fiscalYearReviewReason` string, nullable: Why fiscalYearReview is raised, naming the field that raised it; null when not raised (#2019).
    - `cashBasis` CashBasisSummary: The `cashBasis` block of a statement whose `reportBasis` is `cash`. Present only then; an accrual statement has no such key. Money is integer ledger cents. Cash net income over the scope equals `accrualNetIncomeCents - timingMovementCents`, so the difference from accrual can be re-derived by hand. The view is not a GAAP statement; `basisNotice` says so and clients print it with the statement.
      - `policyId` 'cash-basis-v1', required
      - `policyVersion` integer, required: Revision of the rules under this policy id.
      - `reviewedBy` string, required: Reviewer of the policy the statement was calculated under.
      - `throughDate` string, date, required: The cash view was built from inception through this date.
      - `scope` CashBasisScope, required: What a cash-basis statement or refusal answers for. `range` (P&L, cash flow, income-statement drill-down) is blocked by a refusal dated inside `startDate`..`endDate`; `as_of` (balance sheet, trial balance, balance-sheet drill-down) by any refusal dated on or before `endDate`.
        - `kind` 'range' | 'as_of', required
        - `entityId` string, nullable, required: Null when the request named no entity.
        - `startDate` string, date, nullable, required: Null on `as_of`, and when the request carried no explicit start.
        - `endDate` string, date, nullable, required: Range end or as-of date. Null only when the request carried no explicit date.
      - `droppedEntryCount` integer, required: Entries left out of the cash view because they only move amounts between income or expense and a receivable, payable, deferred-revenue or accrued account. Whole view, inception through `throughDate`.
      - `retargetedLineCount` integer, required: Receivable or payable settlement lines moved onto the income or expense accounts of the invoice or bill they settle. Whole view, inception through `throughDate`.
      - `retargetedCents` integer, required: Sum of the retargeted settlement lines. Whole view, inception through `throughDate`.
      - `accrualNetIncomeCents` integer, required: Accrual net income over the scope (revenue minus expense, closing entries excluded).
      - `timingMovementCents` integer, required: Change over the scope in the debit-positive balance of the receivable, payable, deferred-revenue and accrued accounts, on the accrual ledger.
      - `evidence` object, required: Completeness figures over the scope. They have no basis effect.
        - `uncategorizedIncomeCents` integer, required
        - `uncategorizedExpenseCents` integer, required
        - `suspenseBalanceCents` integer, required: Balance of suspense and ask-my-client accounts at the scope's end, debit positive.
      - `reviewItemCount` integer, required: Review items dated inside the scope, including those beyond the cap on `reviewItems`.
      - `reviewItems` object[], required: Kept income or expense lines with no cash, card or clearing line behind them, earliest first. They are identical on both bases and listed for review. No memo or description text.
        - `kind` 'pnl_against_equity_or_suspense', required
        - `entryId` string, required
        - `entryDate` string, date, required
        - `accountCode` string, required: Code of the income or expense account.
        - `amountCents` integer, required: Ledger cents of that line.
      - `basisNotice` 'Cash basis. Not a GAAP statement: revenue is recognized when cash is received, not when performance obligations are satisfied (ASC 606).', required: Fixed wording that the view is not a GAAP statement. Clients print it with the statement instead of composing their own.
    - `isConsistent` boolean
    - `differenceCents` integer: P&L only. Revenue minus expenses minus net income.
    - `cacheDifferenceCents` integer: P&L primary only. Largest signed journal-minus-cache discrepancy; zero if skipped.
    - `differenceFromBalanceSheetCents` integer: Cash flow only. Ending cash minus monthly-balance cash; zero if skipped.
    - `checks` ReportChecks, required (unresolved $ref)
    - `ledgerRevision` string, nullable: Opaque token of the posted ledger state the report was read under (#1166). It changes whenever any journal entry or line of the company (with `entityId`, of that entity and of entries with no entity) is inserted, updated, voided or deleted, backdated or not. Two reads with equal tokens saw the same ledger. Null when the ledger moved on both attempts of the read, so a client combining pages or statements must treat the result as unproven and retry. Not a credential; not ordered.
    - `startDate` string, date, nullable
    - `endDate` string, date, nullable
    - `revenue` object[]: Operating revenue rows. Other income is reported in `otherIncome`, below operating income (#964,
    - `otherIncome` object[]: Non-operating income rows (interest, FX gains; detail type `other_income`), `reportSection` `other_income`.
    - `totalRevenue` number: Operating revenue; excludes other income.
    - `totalRevenueCents` integer
    - `totalCogs` number
    - `totalOpex` number
    - `totalExpenses` number
    - `operatingIncome` number: totalRevenue − totalExpenses.
    - `operatingIncomeCents` integer
    - `totalOtherIncome` number
    - `totalOtherIncomeCents` integer
    - `netIncome` number: operatingIncome + totalOtherIncome.
    - `netIncomeCents` integer
    - `comparison` ProfitAndLossComparison: Prior-period / prior-year comparison block attached to the P&L payload when `comparePeriod` is supplied. Mirrors the main-period shape plus a `mode`, range dates, and `hasData` flag. `reportBasis` is that of the statement it is attached to: `cash` only under a statement requested with `basis=cash` on the accountant report routes. `configuredBasis` and `configuredBasisSource` are inherited from the primary period and are not re-resolved on the comparison's own date (#2911).
      - `configuredBasis` 'cash' | 'accrual' | 'unknown', required
      - `configuredBasisSource` 'statement_basis' | 'tax_settings' | 'company' | 'missing' | 'unavailable', required
      - `reportBasis` 'accrual' | 'cash', required
      - `currency` string, nullable: ISO currency of the comparison figures; the same authority as the statement it is attached to (#3434).
      - `minorUnitExponent` integer, nullable: Minor-unit exponent of the comparison figures (2), null with currency (#3434).
      - `fiscalYearEnd` string, nullable: companies.fiscal_year_end (MM-DD); null when not confirmed (#2019).
      - `fiscalYearReview` union: True when companies.fiscal_year_end is set and not 12-31, or tax_settings.fiscal_year_end is set and not 12; statements are still calendar-year and need review; "unknown" when the fiscal year end could not be read (#2019).
        - boolean
        - 'unknown'
      - `fiscalYearReviewReason` string, nullable: Why fiscalYearReview is raised, naming the field (companies.fiscal_year_end or tax_settings.fiscal_year_end); null when not raised (#2019).
      - `mode` 'none' | 'prior-period' | 'prior-year'
      - `period` string
      - `startDate` string, date
      - `endDate` string, date
      - `hasData` boolean
      - `revenue` object[]
      - `cogs` object[]
      - `expenses` object
      - `otherIncome` object[]
      - `totalRevenue` number
      - `totalCogs` number
      - `totalOpex` number
      - `totalExpenses` number
      - `operatingIncome` number
      - `totalOtherIncome` number
      - `netIncome` number
      - `differenceCents` integer
      - `isConsistent` boolean
      - `checks` ReportChecks, required (unresolved $ref)
    - `classFilter` ReportClassDescriptor
      - `classId` string, nullable, required: Null represents the explicit Unassigned class bucket.
      - `className` string, required
      - `isUnassigned` boolean, required
    - `tagFilter` object: Present when the P&L was filtered by tagId.
      - `tagIds` string[]
    - `classGroups` ProfitAndLossClassGroup[]
      - `classId` string, nullable, required: Null represents the explicit Unassigned class bucket.
      - `className` string, required
      - `isUnassigned` boolean, required
      - `period` string
      - `startDate` string, date
      - `endDate` string, date
      - `revenue` object[]
      - `cogs` object[]
      - `expenses` object
      - `otherIncome` object[]
      - `totalRevenue` number
      - `totalCogs` number
      - `totalOpex` number
      - `totalExpenses` number
      - `operatingIncome` number
      - `totalOtherIncome` number
      - `netIncome` number
      - `differenceCents` integer
      - `isConsistent` boolean
      - `hasData` boolean
    - `classReconciliation` ProfitAndLossClassReconciliation: Reconciles summed class groups to the unfiltered P&L totals for the same company, period, and basis.
      - `totalRevenueCents` object
      - `totalCogsCents` object
      - `totalOpexCents` object
      - `totalExpensesCents` object
      - `netIncomeCents` object
      - `isConsistent` boolean

## Other responses

- `400`: Request failed validation
- `401`: Authentication required
- `404`: Active accounting class filter not found
- `422`: Explicit financial scope is required, or the resolved consolidated report is not yet available

---

[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)
