# Revenue Recognition

**Revenue Recognition** answers a different question from the rest of the workspace. Everywhere else, Revenue tells you when money *moved*. Here it tells you when revenue may be *recognized* — spread across the periods it was earned in, under ASC 606, rather than booked when the invoice was issued.

---

## Overview

Open **Revenue → Revenue Recognition**, under **Operations** in the sidebar. From top to bottom the page has:

- four **summary cards** for the selected accounting period;
- a **period summary** that rolls the deferred-revenue balance forward, channel by channel;
- **Revenue trends** and a **12-month recognition forecast**;
- the **Revenue recognition schedule** table;
- the **Unscheduled revenue records** queue;
- **Close Period** and **Lock Period**, for the periods you are ready to finalize.

All amounts are in USD, as the header notes beside the **Recognition period** selector. That selector defaults to the current month's accounting period — or, if there is none, the latest one — and scopes the summary cards, the schedule table, and the unscheduled queue. The period summary has a period selector of its own, and the trends and forecast always count from the current month. An accounting period exists for each month that has at least one schedule line, so a month without one is not offered.

The **Channel** filter at the top of the workspace does not narrow this page. To look at one channel, use the schedule table's own channel filter.

The *method* each record is recognized by is not set here. Recognition policies live on the [Revenue Settings](/revenue/revenue-settings/) page, which is also where the four available methods are documented.

## Summary cards

| Card | Meaning |
|------|---------|
| **Recognized this period** | Revenue recognized on the period's schedule lines. The line beneath counts the schedule lines behind it. |
| **Deferred revenue balance** | Scheduled minus recognized across those same lines, whatever their status. Labelled *Balance sheet liability*. |
| **Partially recognized** | The amount already recognized on lines that are part-way through — some, but not all, of their scheduled amount. Labelled *In-flight and adjusted lines*. |
| **Unscheduled records** | A **count** of revenue records in the period that have no schedule line yet, with the revenue they carry beneath it as *pending schedule*. See [Unscheduled revenue records](#unscheduled-revenue-records). |

The first three cards follow the schedule table's filters as well as the period: narrow the table by search, status, channel, or method, and those cards narrow with it. **Unscheduled records** follows the queue's search and reason filters the same way. A card shows **—** when its data could not be loaded.

**Deferred revenue balance** is not the same figure as the period summary's **Closing** balance. The card is what the period's schedule lines have not yet recognized; Closing follows the payments received — see [Period summary](#period-summary).

## Period summary

The period summary panel — titled with the month it covers, such as *Jun 2026 summary* — bridges the deferred-revenue balance from the start of a month to its end. It has its own period selector (*Independent of period filter above*), so you can walk the bridge month by month without changing the rest of the page.

```d2
direction: right

records: "Revenue records\npaid out or collected\nduring the month"
schedules: "Schedule lines in the\nmonth's accounting period"
writeoffs: "Written-off records"

opening: "Opening\nbalance carried in\nfrom earlier months"
closing: "Closing\ndeferred balance"
next: "Next month's\nOpening"

opening -> closing: "start from"
records -> closing: "+ New payment"
schedules -> closing: "− Recognized"
writeoffs -> closing: "− Write-offs"
closing -> next: "carried forward"
```

The waterfall reads left to right:

- **Opening** — the deferred balance carried in from every earlier month.
- **New payment** — revenue records paid out, or else collected, during the month, at the amount their recognition schedules are built from.
- **Recognized** — everything recognized on the schedule lines of the month's accounting period.
- **Write-offs** — for written-off records, the part of their New payment amount that was never recognized.
- **Closing** — `Opening + New payment − Recognized − Write-offs`, which becomes the next month's Opening.

Below the waterfall, three sections break the month down by channel:

| Section | What it lists | Total label |
|---------|---------------|-------------|
| **Recognized revenue** | Each channel's Recognized amount for the month. | *Net recognized* |
| **Deferred revenue** | Each channel's Closing balance. | *Ending balance* |
| **Future contracted revenue** | What is still to be recognized on pending schedule lines in later accounting periods. | *Ending balance* |

Select **Download CSV** to export the three sections — one row per channel in each section, plus a total row for each — in the columns **Period**, **Section**, **Line item**, and **Amount**.

The summary needs at least one accounting period. Until the first schedule line has been generated there is none, and the panel reads *Failed to load the rollforward. Try refreshing the page.*

:::caution
**GCP cash is not reflected in the period summary or the Deferred trend.** New payment counts a record in the month of its payout date, or failing that its collected date, and GCP revenue records carry neither — Google reports a payout amount but not the date it was sent. See [GCP Revenue](/gcp-marketplace/revenue/).
:::

## Recognized vs Deferred by Channel and Period

Recognized and deferred revenue by channel is in the [period summary](#period-summary): its **Recognized revenue** and **Deferred revenue** sections list each channel, and its own month selector steps from one accounting period to the next. For the individual schedule lines behind those totals — each with its channel, billing period, and status — use the [Revenue recognition schedule](#revenue-recognition-schedule).

## Revenue trends and forecast

**Revenue trends** charts one series at a time over the **Last 3 months**, **Last 6 months**, **Last 12 months** (the default), or **Last 24 months** — the current month and the months before it. Switch series with the buttons above the chart.

| View | Each month shows | Total beneath the chart |
|------|------------------|-------------------------|
| **Recognized** | Revenue recognized on that month's schedule lines. | *Cumulative recognized* — the sum across the range. |
| **Deferred** | The deferred balance at month end — the same Closing balance the period summary computes. | *Closing deferred balance* — the last month's balance. |
| **Booked** | Revenue invoiced that month: the net revenue of revenue records, by invoice date. | *New bookings* — the sum across the range. |

**Booked** is not the Overview's **Bookings**. Bookings on the [Overview](/revenue/overview/) is contract value from entitlement terms; Booked here is invoiced revenue from revenue records, so the two will not match.

The **12-month recognition forecast** charts what is still to be recognized on **Pending** schedule lines in the current month and each of the next eleven, with the **Forecast total** beneath. Alongside, up to six upcoming accounting periods are listed with their amount and a status chip: **Pending** for the first period listed when it is open, **Forecast** for later open periods, and otherwise the period's own status.

## Revenue recognition schedule

The **Revenue recognition schedule** table lists the schedule lines behind the cards, one row per line: **Revenue record**, **Channel**, **Method**, **Billing period**, **Scheduled**, **Recognized**, and **Status**. Select a column heading to sort by it; the table starts sorted by billing period, oldest first.

Narrow it with:

- **Search** — matches the revenue record ID or the channel. It does not search customer or buyer names.
- **Status** — **Pending**, **Recognized**, **Adjustment**, or **Cancelled**.
- **Channel** — AWS, Azure, GCP, or Stripe.
- **Method** — **Straight-Line**, **Point-in-Time**, **Usage based**, or **Milestone**.

Every filter also narrows the first three summary cards.

## Unscheduled revenue records

The **Unscheduled revenue records** queue lists revenue records that have no recognition schedule line yet — records whose recognition status is empty or *Unrecognized* and whose invoice date falls in the selected period. The chip at its top reads *N records · $X at risk*: the count, and the net revenue in USD those records carry.

Work the queue with:

- **Search** — record ID, channel, buyer ID, product ID, or the channel's own record ID.
- **Reason** — why a record has no schedule yet (see the table below).
- **Sort** — **Amt (high to low)**, the default, **Amt (low to high)**, **Date (newest first)**, or **Date (oldest first)**.

Each row shows the **Revenue record**, **Channel**, **Buyer** (the buyer ID), **Amt**, and **Date** (the invoice date). The reason is a filter rather than a column: pick a reason to see the records it applies to.

| Reason | What it means |
|--------|---------------|
| **Missing service dates** | A straight-line record has no service start or end date — on the record, in its usage period, or on its entitlement. |
| **Invalid service dates** | A straight-line record's service end date is before its start date. |
| **Missing trigger date** | A point-in-time record has no trigger date, service start date, or invoice date. |
| **Missing measurement window** | A usage-based record has no dates to measure over — no service, usage, or entitlement period, and no invoice date. |
| **Invalid measurement window** | A usage-based record's measurement window ends before it starts. |
| **Missing milestone inputs** | A milestone record lacks a trigger date, an external trigger reference, or milestone amounts. |
| **Unsupported method** | The policy that applies names a method Suger cannot schedule. |
| **Policy resolution failed** | Suger could not resolve which recognition policy applies to the record. |
| **Schedule pending** | The inputs look complete; the schedule has not been generated yet. |
| **Service date lookup failed** | Suger could not look up the record's service dates. This is a lookup error, not missing data — there is nothing to fix on the record. |

## The accounting period lifecycle

An accounting period moves through three states, and it only moves forward:

```d2
direction: down

open: "OPEN\nschedules still generating,\namounts can still change"
soft: "SOFT_CLOSED\nrecognition workflow has run\nfor the period"
locked: "LOCKED\nfinal — no further change"

closefail: "Rejected\na period must be SOFT_CLOSED\nbefore it can be locked" { shape: diamond }

open -> soft: "Close Period\nstarts the recognition workflow"
open -> closefail: "Lock Period"
soft -> locked: "Lock Period\nAdmin only · reason required\nIRREVERSIBLE"

locked -> locked: "further close or lock\nattempts are rejected"
```

| Status | What it means |
|--------|----------------|
| **OPEN** | The default. Schedules for the period can still be generated and changed. |
| **SOFT_CLOSED** | **Close Period** has run the recognition workflow for that period. This is the state a period must be in before it can be locked. |
| **LOCKED** | The period is final. Nothing can reopen it, and a further close or lock attempt is rejected. |

### Close a period

1. Enter the **period** — either a month such as `2026-06`, or a period ID.
2. Optionally add a **reason**.
3. Select **Close Period**.

Closing starts the recognition workflow for that period and moves it to **SOFT_CLOSED**.

### Lock a period

:::caution
**Locking is irreversible and Admin-only.** There is no unlock. Only a user with the **Admin** role can lock a period, a **reason is required**, and the period must already be **SOFT_CLOSED** — attempting to lock an OPEN period is rejected. Close the period first, confirm the numbers, and lock only when you are certain they are final.
:::

1. Enter the **period**.
2. Enter a **reason** — locking will not proceed without one.
3. Select **Lock Period**.

## KPI calculation formulas

All amounts are in USD: recognition schedules are generated in USD, and the page reports in USD only. Every formula is the same for each channel that generates schedule lines — AWS, Azure, GCP, and Stripe. See the caution under [Period summary](#period-summary) for GCP cash.

| KPI | Formula | Calculation details |
|-----|---------|---------------------|
| Recognized this period | `Σ recognized amount` | Over the schedule lines in the selected period that match the table's search, status, channel, and method filters — every status counts unless you filter one. The line beneath is the number of those lines. |
| Deferred revenue balance | `Σ scheduled amount − Σ recognized amount` | Over the same lines, including Cancelled and Adjustment lines unless you filter them out. Derived, not stored. |
| Partially recognized | `Σ recognized amount where 0 < recognized < scheduled` | Over the same lines. |
| Unscheduled records | `count(records with no schedule line)` | Records whose recognition status is empty or Unrecognized and whose invoice date is in the selected period, narrowed by the queue's search and reason filters. |
| Pending schedule · at risk | `Σ net revenue of those records` | The card's *$X pending schedule* line and the queue's *$X at risk* chip. Net revenue as defined on the [Overview](/revenue/overview/#kpi-calculation-formulas): refunds subtracted, and voided, canceled, or written-off records count as zero. |
| Opening | `Σ (New payment − Recognized − Write-offs)` over every earlier month | The previous month's Closing, carried forward. |
| New payment | `Σ recognition basis of records whose payout date — or, without one, collected date — falls in the month` | Recognition basis = the record's USD base amount under a **Gross** reporting basis, or its collectable amount at the record's locked USD rate under **Net** — the amount its schedules are built from. The basis comes from your reporting policies in [Revenue Settings](/revenue/revenue-settings/). A record with no USD base amount counts its converted payout or collected amount instead. |
| Recognized (period summary) | `Σ recognized amount of the schedule lines in the month's accounting period` | Every status counts. Each line counts toward its record's channel. |
| Write-offs | `Σ max(0, the record's New payment amount − everything recognized on its schedule lines)` over written-off records | Placed in the month the record was last updated, or failing that its invoice month. A written-off record that never counted as a New payment writes off nothing. |
| Closing | `Opening + New payment − Recognized − Write-offs` | Computed per channel, then summed. The per-channel values are the **Deferred revenue** section. |
| Future contracted revenue | `Σ max(0, scheduled − recognized)` over Pending lines in later accounting periods | Later means accounting periods that start after the selected month. |
| Recognized trend | `Σ recognized amount per month` | Total = the sum across the range (*Cumulative recognized*). |
| Deferred trend | `Closing balance at each month end` | Total = the last month's balance (*Closing deferred balance*). |
| Booked trend | `Σ net revenue of records per invoice month` | Total = the sum across the range (*New bookings*). Invoiced revenue — not the contract value the Overview's Bookings counts. |
| 12-month recognition forecast | `Σ max(0, scheduled − recognized)` over Pending lines, per month | The current month and the next eleven. **Forecast total** is the sum; each listed upcoming period shows its month's amount. |

## Freshness

Recognition schedules are generated as each channel's revenue syncs in. A separate **recognition recovery** job runs hourly, at 17 minutes past the hour, and re-runs schedule generation for any sync that committed its records but ran out of retries before its schedules were built — so a missed generation repairs itself rather than leaving a permanent hole in the schedule.
