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

# MRR financials table

> Monthly recurring revenue (MRR) at the start and end of every month, its movements (new, expansion, contraction, lost, resurrecting) with their reasons, ARR, revenue churn rate, month-over-month growth, non-recurring revenue (one-off and variable, net), cash collected and refunded, and outstanding receivables at the month end. One currency per response, never converted. MRR is the monthly-normalized recurring net amount the contracts entitle to at the last second of the month (time zone of the organisation). Non-recurring revenue is net = gross − tax of the finalized invoice positions (after position discounts), by finalization month; credit notes are negative. Collected cash counts settled payments (status captured, booked, refunded, partial_refunded) by payment date; refunds count separately. The figures come from the latest calculation (`meta.asOf`).

Required permission: `analytics:read`.



## OpenAPI

````yaml assets/openapi-v2-finance.json get /api/analytics/mrr-financials
openapi: 3.0.3
info:
  title: Fynn Finanzberichte API
  version: 2026-09
  description: >-
    The finance reporting API returns the same figures as the finance pages of
    the app: MRR and its movements, Accounted MRR, cash, receivables, revenue,
    the customer base, month-end snapshots with their restatements and the Excel
    books. Every amount is an exact decimal string in one currency, never
    converted and never a float. Months are `YYYY-MM` in the time zone of the
    organisation.


    Authenticate every request with an API token of your organisation
    (`Authorization: Bearer api_...`). Reading needs `analytics:read`, taking a
    snapshot and changing the settings `analytics:write`. Every route also needs
    the finance reports to be enabled for the organisation (feature flag
    `analytics.advanced`); otherwise it answers 403 `feature-not-available`.
servers:
  - url: https://coreapi.io
    description: Production
  - url: https://preview.coreapi.io
    description: Sandbox
security:
  - ApiToken: []
tags:
  - name: Datensätze
    description: Page datasets and the MRR table.
  - name: Drill-downs und Hinweise
    description: Lines behind a cell and data-quality findings.
  - name: Snapshots
    description: Month-end snapshots and their versions.
  - name: Excel-Exporte
    description: Excel books of the finance pages.
  - name: Definitionen
    description: The versioned definitions catalogue with its changelog.
  - name: Einstellungen
    description: Organisation-wide settings of the finance figures.
paths:
  /api/analytics/mrr-financials:
    get:
      tags:
        - Datensätze
      summary: MRR financials table
      description: >-
        Monthly recurring revenue (MRR) at the start and end of every month, its
        movements (new, expansion, contraction, lost, resurrecting) with their
        reasons, ARR, revenue churn rate, month-over-month growth, non-recurring
        revenue (one-off and variable, net), cash collected and refunded, and
        outstanding receivables at the month end. One currency per response,
        never converted. MRR is the monthly-normalized recurring net amount the
        contracts entitle to at the last second of the month (time zone of the
        organisation). Non-recurring revenue is net = gross − tax of the
        finalized invoice positions (after position discounts), by finalization
        month; credit notes are negative. Collected cash counts settled payments
        (status captured, booked, refunded, partial_refunded) by payment date;
        refunds count separately. The figures come from the latest calculation
        (`meta.asOf`).


        Required permission: `analytics:read`.
      operationId: getMrrFinancials
      parameters:
        - name: from
          in: query
          description: >-
            First month (YYYY-MM, time zone of the organisation). Default: `to`
            minus 11 months.
          required: false
          schema:
            type: string
            pattern: ^\d{4}-(0[1-9]|1[0-2])$
            example: 2025-10
        - name: to
          in: query
          description: >-
            Last month (YYYY-MM). Default: the current month. At most 36 months
            per request; `from` must not be after `to`.
          required: false
          schema:
            type: string
            pattern: ^\d{4}-(0[1-9]|1[0-2])$
            example: 2026-09
        - name: currency
          in: query
          description: >-
            ISO-4217 code of one of the organisation's currencies. Default: the
            default currency.
          required: false
          schema:
            type: string
            example: EUR
        - name: scope
          in: query
          description: >-
            Level on which movements are classified. Default: the organisation
            setting (`invoice_address` unless changed).
          required: false
          schema:
            type: string
            enum:
              - subscription
              - invoice_address
              - customer
              - organisation
        - name: segmentId
          in: query
          description: Analytics segment to narrow the figures to.
          required: false
          schema:
            type: string
            format: uuid
        - name: customerIds[]
          in: query
          description: Narrow to these customers.
          required: false
          schema:
            type: array
            items:
              type: string
              format: uuid
        - name: productIds[]
          in: query
          description: >-
            Narrow to these products (MRR and non-recurring revenue; cash has no
            product).
          required: false
          schema:
            type: array
            items:
              type: string
              format: uuid
      responses:
        '200':
          description: The table.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MrrFinancialsTableView'
        '401':
          description: Missing or invalid authentication.
        '403':
          description: >-
            Missing permission `analytics:read` (`FRAMEWORK__ACCESS_DENIED`), or
            the finance reports are not enabled for the organisation (feature
            flag `analytics.advanced`, `type`
            https://fynn.dev/problems/feature-not-available).
          content:
            application/problem+json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Problem'
                  - $ref: '#/components/schemas/FeatureNotAvailableProblem'
        '422':
          description: >-
            Invalid query parameter. The body lists the offending parameters in
            `violations` (`propertyPath`, `message`, `code`).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ValidationProblem'
      security:
        - ApiToken: []
components:
  schemas:
    MrrFinancialsTableView:
      description: >-
        The MRR financials table: one value per row and month. Money values are
        objects with an exact decimal `amount` (two places) and `currency`;
        rates are exact decimal strings with six places (`"0.001600"` = 0.16 %).
        Contraction and lost are unsigned amounts (they lower MRR); reason
        amounts are signed.
      properties:
        months:
          description: >-
            Months of the range (YYYY-MM, time zone of the organisation),
            ascending. Every series is aligned with this list.
          type: array
          items:
            type: string
            example: 2026-09
        rows:
          description: >-
            Series per row key: `one_off` (Net (gross − tax, after position
            discounts) of the one-off positions of the documents finalized in
            the month: one-time prices of subscription items, manual positions,
            setup fees, and discounts without a parent position (dunning fees
            are other operating income, not revenue); credit notes and
            cancellations count negative.), `variable` (Net (gross − tax, after
            position discounts) of the usage-based positions of the documents
            finalized in the month: usage quantities, metered measurements and
            percentage prices; credit notes and cancellations count negative.),
            `mrr_bop`, `mrr_eop` (MRR at the end of the previous / this month),
            `accounted_mrr` ("Accounted MRR": the recurring invoice positions'
            shares of the month by their service period, 30/360; null for a
            snapshot copy), `billing_gap` ("Differenz Vertrag zu Rechnung":
            `mrr_eop − accounted_mrr`, its causes under `reasons.billing_gap`),
            `new`, `expansion`, `contraction`, `lost`, `resurrecting`
            (movements), `arr_eop` (MRR × 12), `revenue_churn_rate`
            ((contraction + lost) / BoP), `mom_growth` ((EoP − BoP) / BoP),
            `cash_collected` ("Zahlungseingang") and its split by the invoice
            the money pays, adding up to it: `cash_collected_this_month`
            (invoices finalized in the same month),
            `cash_collected_other_months` (invoices of other months),
            `cash_collected_unassigned` (no finalized invoice: top-ups,
            prepayments, the part above the gross of an overpaid invoice),
            `cash_collected_refund_returned` ("Erstattung zurückgekommen": a
            negative refund matched from the bank account), `cash_refunded`
            ("Zahlungsausgang": refunds, chargebacks, payouts and return debit
            fees) and its split by kind, adding up to it: `cash_refunded_refund`
            ("Erstattungen"), `cash_refunded_chargeback` ("Rücklastschriften"),
            `cash_refunded_payout` ("Auszahlungen"), `cash_refunded_return_fee`
            ("Rücklastschrift-Gebühren": the bank fee of a return debit without
            a return case, not part of the invoice; all four null for a snapshot
            copy), `cash_corrections` ("Korrekturen": refunds entered by hand
            and cancelled by a counter-entry, no money moved, outside cash in
            and out; 0 over a range that holds both entries) with
            `cash_corrections_reversed` ("storniert") and
            `cash_corrections_counter` ("Gegenbuchung", negative; all three null
            for a snapshot copy), `cash_net` (by payment date, whatever month
            the invoice belongs to), `cash_forecast` ("Rechnungsprognose
            (brutto)": gross of the invoices the billing forecast expects in the
            month; null for elapsed months), `receivables_eop` (open amounts of
            finalized invoices at the month end; months after the current one
            carry the invoices open today forward). A value is null when the
            month has no data at all.
          type: object
          additionalProperties:
            type: array
            items:
              nullable: true
              oneOf:
                - $ref: '#/components/schemas/MoneyView'
                - type: string
                  example: '0.012500'
        totals:
          description: >-
            Total column per row key: flows are summed over the range, `mrr_bop`
            is the BoP of the first month, `mrr_eop`, `accounted_mrr`,
            `billing_gap`, `arr_eop` and `receivables_eop` are the value of the
            last month, rates are null. Totals are computed from the exact
            amounts and rounded once, so they can differ by a cent from the sum
            of the rounded cells.
          type: object
          additionalProperties:
            nullable: true
            oneOf:
              - $ref: '#/components/schemas/MoneyView'
              - type: string
        reasons:
          description: >-
            Reason split of the movements: `expansion` and `contraction` (and
            `new`, `lost`, `resurrecting` for the detail view), each a map from
            reason (`price_change`, `quantity_change`, `discount_start`,
            `plan_change`, …) to a series aligned with `months`. Amounts are
            signed: contraction reasons are negative. `billing_gap`: the
            difference contract − invoice per cause (`partial_month`,
            `billing_start_later`, `not_yet_billed` (the next billing run will
            invoice it), `not_billed` (an elapsed month no run will invoice),
            `upcoming_invoice`, `trial`, `credit_or_cancellation`,
            `billed_after_end`, `period_shift`, `price_mismatch`, `unknown`);
            the causes of a month add up to the `billing_gap` cell.
          type: object
          additionalProperties:
            description: Reason => series of money values aligned with `months`.
            type: object
        meta:
          description: Calculation time, effective scope and currency, finding counts.
          allOf:
            - $ref: '#/components/schemas/FinanceMetaView'
        reasonLabels:
          description: >-
            German name of every key of `reasons`: the movement reasons (the one
            catalogue, the same names as the card "Ursachen der Bewegungen";
            every reason is its own "davon" row, added and removed products are
            not netted) and the causes of `billing_gap`. "Sonstiges" only for a
            key outside the catalogue.
          type: object
          example:
            contract_start: Vertragsbeginn
            price_change: Preisänderung
            not_billed: Nicht abgerechnet
          additionalProperties:
            type: string
      type: object
    Problem:
      type: object
      description: >-
        Error body (problem+json). `type` is the error key, e.g.
        `ANALYTICS_MRR_FINANCIALS__SNAPSHOT_MONTH_NOT_ENDED`; further keys carry
        the parameters of the error.
      properties:
        status:
          type: integer
          example: 409
        type:
          type: string
          example: ANALYTICS_MRR_FINANCIALS__SNAPSHOT_MONTH_NOT_ENDED
        title:
          type: string
          example: An error occurred
        detail:
          type: string
          description: German sentence that can be shown to the user.
      required:
        - status
        - type
        - title
        - detail
      additionalProperties: true
    FeatureNotAvailableProblem:
      type: object
      description: >-
        403 body when the finance reports are not enabled for the organisation
        (feature flag `analytics.advanced`).
      properties:
        type:
          type: string
          enum:
            - https://fynn.dev/problems/feature-not-available
        title:
          type: string
          example: Feature not available
        detail:
          type: string
          example: >-
            The requested feature is not available. Please contact customer
            support.
        featureFlags:
          type: array
          items:
            type: string
          example:
            - analytics.advanced
      required:
        - type
        - title
        - detail
        - featureFlags
      additionalProperties: true
    ValidationProblem:
      type: object
      description: '422 body: one entry per rejected field in `violations`.'
      properties:
        status:
          type: integer
          example: 422
        type:
          type: string
          example: https://tools.ietf.org/html/rfc2616#section-10
        title:
          type: string
          example: Validation Failed
        detail:
          type: string
        violations:
          type: array
          items:
            $ref: '#/components/schemas/Violation'
      required:
        - status
        - type
        - violations
      additionalProperties: true
    MoneyView:
      description: >-
        A money amount. `amount` is an exact decimal string with two decimal
        places (net, excluding VAT, unless stated otherwise); `currency` is the
        ISO-4217 code.
      properties:
        amount:
          description: >-
            Exact decimal amount with two decimal places, dot as separator.
            Negative amounts carry a leading minus.
          type: string
          example: '1234.56'
        currency:
          description: ISO-4217 currency code.
          type: string
          example: EUR
      type: object
    FinanceMetaView:
      description: >-
        Context of a finance response: calculation time, the effective scope,
        currency and month range, and the finding counts.
      properties:
        asOf:
          description: >-
            When the figures were last calculated (ISO 8601). Null when no
            calculation exists yet.
          type: string
          format: date-time
          nullable: true
        buildId:
          description: >-
            Id of the calculation the figures come from. Null when no
            calculation exists yet.
          type: string
          nullable: true
        scope:
          description: >-
            Effective movement scope: the level on which new, expansion,
            contraction, lost and resurrecting are classified.
          type: string
          enum:
            - subscription
            - invoice_address
            - customer
            - organisation
          example: invoice_address
        currency:
          description: >-
            Effective currency (ISO-4217). Amounts are never converted between
            currencies.
          type: string
          example: EUR
        from:
          description: First month of the range (YYYY-MM, time zone of the organisation).
          type: string
          example: 2025-10
        to:
          description: Last month of the range (YYYY-MM, time zone of the organisation).
          type: string
          example: 2026-09
        findings:
          description: Number of data-quality findings of the calculation.
          allOf:
            - $ref: '#/components/schemas/FindingCountsView'
        filtersNotApplied:
          description: >-
            Datasets of this response that ignore the customer, product or
            segment filter because the underlying facts have no such dimension
            (for example receivables at past month ends).
          type: array
          items:
            type: string
        notSnapshotted:
          description: >-
            MRR table rows a month-end snapshot does not hold (invoice, cash and
            forecast figures). In the snapshot view they keep their current
            values. Empty when the range has no snapshot or a segment is
            applied.
          type: array
          items:
            type: string
          example:
            - one_off
            - accounted_mrr
            - cash_collected
        projectedFrom:
          description: >-
            First month of the range after the current one (YYYY-MM): from there
            the month-end stocks (open receivables, amounts owed to customers)
            carry today's open invoices forward, a projection as of today
            ("Prognose (Stand heute)"), not a fact. Null when the range ends in
            or before the current month.
          type: string
          example: 2026-10
          nullable: true
        forecast:
          description: >-
            Completeness of the invoice forecast ("Rechnungsprognose") in the
            range: `incomplete` with the number of subscriptions whose forecast
            failed. The forecast rows then show what the other subscriptions
            bring; they are marked "unvollständig", never read as 0.
          allOf:
            - $ref: '#/components/schemas/ForecastStatusView'
        build:
          description: >-
            The latest calculation attempt, also when it failed ("Berechnung
            abgebrochen"). Null when the organisation was never calculated.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/BuildAttemptView'
        dataBuildId:
          description: >-
            Id of the calculation the figures come from (the last successful
            one). Differs from `build.buildId` when the latest attempt failed.
            Null when no calculation exists yet.
          type: string
          nullable: true
      type: object
    Violation:
      type: object
      properties:
        propertyPath:
          type: string
          example: to
        message:
          type: string
          example: Der Zeitraum darf höchstens 36 Monate umfassen.
        code:
          type: string
          example: analytics.mrr_financials.range_too_long
      required:
        - propertyPath
        - message
        - code
    FindingCountsView:
      description: Number of data-quality findings of the latest calculation per severity.
      properties:
        error:
          description: Findings that point at wrong numbers.
          type: integer
          example: 0
        warning:
          description: Findings that point at data that should be checked.
          type: integer
          example: 3
        info:
          description: Informational findings.
          type: integer
          example: 12
      type: object
    ForecastStatusView:
      description: >-
        Whether the invoice forecast of the range is complete: the billing
        forecast of a subscription can fail (finding `FORECAST_FAILED`), and
        that subscription is then missing from every forecast month. A forecast
        cell of an incomplete forecast is a lower bound, never "no invoices".
      properties:
        incomplete:
          description: >-
            True when the forecast of at least one subscription failed and the
            range contains forecast months (the current month or later).
          type: boolean
          example: false
        failedSubscriptions:
          description: >-
            Number of subscriptions whose billing forecast failed (0 when
            complete).
          type: integer
          example: 0
      type: object
    BuildAttemptView:
      description: >-
        The latest calculation attempt. When it failed, the figures still come
        from the last successful calculation (`meta.dataBuildId`, `meta.asOf`).
      properties:
        status:
          description: >-
            Outcome of the attempt: `succeeded`, or `failed` when it broke a
            consistency check and was cancelled (nothing of it was stored).
          type: string
          enum:
            - succeeded
            - failed
          example: failed
        builtAt:
          description: When the attempt started (ISO 8601).
          type: string
          format: date-time
        buildId:
          description: Id of the attempt. Equal to `meta.dataBuildId` when it succeeded.
          type: string
        failed:
          description: The broken checks; null unless `status` is `failed`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/BuildFailureView'
      type: object
    BuildFailureView:
      description: >-
        Why the latest calculation was cancelled: the consistency checks it
        broke. The rows are listed by the details metric `build_failure`.
      properties:
        invariants:
          description: >-
            Codes of the broken checks (sorted), e.g. `CASH_WITHIN_DOCUMENT`;
            `IDENTITY` for the MRR identity.
          type: array
          items:
            type: string
          example:
            - CASH_WITHIN_DOCUMENT
        rowCount:
          description: >-
            Number of rows that broke a check (complete, also above the listed
            rows).
          type: integer
          example: 5
        invoiceRowCount:
          description: >-
            Number of the listed rows that name an invoice. Equal to `rowCount`
            when every row is an invoice.
          type: integer
          example: 5
      type: object
  securitySchemes:
    ApiToken:
      type: http
      scheme: bearer
      description: >-
        API token of the organisation. Send it as Authorization: Bearer api_...
        The token is bound to exactly one organisation.

````