Insider Preview
This feature is in Insider Preview and subject to change. It is available exclusively to select Aviate customers and partners. Join the waitlist →
Note
Beta. Revenue Recognition is an Insider Preview (beta) feature. Its behavior, API and screens can change between releases. The amounts, identifiers and screens on this page are examples, some of them produced with sample data. Always check revenue figures against your own invoices before you use them to close a month, and send your feedback through Kill Bill support.

Introduction

The Aviate Revenue Recognition module manages when revenue is recognized from the invoices that Kill Bill generates. It spreads each invoiced amount over the period in which the service is delivered, and tracks how much of it has been recognized and how much is still deferred. Finance teams get visibility into recognized vs. deferred revenue through monthly accounting periods that they can close and reopen.

Your accounting policy remains the responsibility of your finance team. Using this module does not by itself make your accounting compliant with a revenue standard such as ASC 606 or IFRS 15.

Key capabilities include:

  • Automatic revenue schedules — every eligible invoice item gets a schedule that spreads its amount over the item’s service period

  • Daily recognition — a background process recognizes revenue as each day of service is delivered

  • Accounting periods — monthly periods that are created automatically and can be closed, reopened and reported on

  • Contract-aware allocation — revenue allocated across the subscriptions of a contract using relative standalone selling prices

  • Reports — period summaries, a period-by-period waterfall of recognized and deferred revenue, revenue by plan and recognition rate

  • Schedule lookups — schedules and their daily entries by invoice item, account, subscription, plan, currency or contract

Key Concepts

Revenue Schedules and Entries

When Kill Bill generates an invoice, Aviate creates one revenue schedule for each eligible invoice item. The schedule records the invoice, invoice item, account, subscription, plan and phase it came from, together with its currency, total amount, service period and recognition method. It also keeps running recognized and deferred amounts. At creation, the full amount is deferred.

Each schedule is split into dated revenue entries. An entry is recognized once its date is reached. When the full amount of a schedule has been recognized, the schedule is closed.

Recognition Methods

The recognition method depends only on the type of the invoice item. In this release it cannot be set per plan, product or customer.

Invoice item type Recognition method How the amount is spread

Recurring

Straight-line

Evenly, one entry per day of the service period

Usage

Straight-line

Evenly, one entry per day of the item’s service period

Fixed (for example a setup fee)

Immediate

One entry for the full amount on the service start date

External charge

Immediate

One entry for the full amount on the service start date

Items with a zero or negative amount, and other item types such as taxes and credits, do not get a schedule. Each invoice item has at most one schedule.

For straight-line schedules:

  • The service period runs from the item’s start date up to, but not including, its end date. A 1 January to 1 February period covers the 31 days of January.

  • The daily amount is the total divided by the number of days, rounded to nine decimal places. Monthly amounts therefore follow the number of days in each month.

  • The last day takes any rounding difference, so the entries always add up exactly to the schedule total.

  • When a contract allocation applies (see Contract Revenue Allocation), the schedule total is the allocated amount instead of the invoice item amount.

For example, an annual subscription of $1,200.00 for the period from 1 January 2026 to 1 January 2027 (365 days) gives about $3.29 per day:

Month Days Recognized

January 2026

31

$101.92

February 2026

28

$92.05

April 2026

30

$98.63

Full year

365

$1,200.00

Monthly amounts are rounded to the cent, so the sum of the twelve rounded months can differ from the total by one cent.

A $500 one-time setup fee is recognized in full on its service start date.

Accounting Periods

An accounting period groups revenue entries by calendar month. The system identifies each period by a name in the format YYYY-MM (for example, 2026-04). The system assigns each revenue entry to the accounting period corresponding to the month of its date. For example, the system assigns an entry dated 2026-04-17 to the period 2026-04.

A period is either open or closed:

  • Open — the daily recognition process recognizes the period’s entries as their dates are reached.

  • Closed — the daily recognition process no longer recognizes the period’s remaining entries, and the date and user that closed it are recorded. A closed period can be reopened, which makes it open again.

Periods are created automatically, one per calendar month, as invoices are generated. You can also create a period ahead of time. Close a period at month-end once its revenue has been recognized.

Note
Note: Closing a period does not block billing. Kill Bill still accepts invoices, credits, adjustments and payments dated in a closed period. See Invoice Adjustments, Credits and Cancellations.

Contract Revenue Allocation

When a contract covers several subscriptions (for example a subscription, an implementation service and a support plan), Aviate allocates the contract’s transaction price across them in proportion to their standalone selling prices (SSP):

  1. Each subscription in the contract (a contract term) is treated as a performance obligation.

  2. The SSP for each term is looked up from the SSPs you configure for its plan, phase and currency.

  3. The transaction price is allocated across the terms in proportion to their SSPs.

  4. Each allocated amount is recognized using the recognition method of its invoice items.

See Contract Revenue Allocation for details.

Getting Started with Revenue Recognition

Installing the Plugin

Install the Aviate plugin as described in the How to Install the Aviate Plugin guide.

Enabling Revenue Recognition

Revenue recognition is disabled by default. To enable it, start Kill Bill with the following system property:

com.killbill.billing.plugin.aviate.enableRevenueRecognition=true

The following properties control revenue recognition:

Property Default Description

com.killbill.billing.plugin.aviate.enableRevenueRecognition

false

Set to true to create revenue schedules for new invoices and to start the daily recognition process.

com.killbill.billing.plugin.aviate.revenueRecognition.delaySeconds

86400 (one day)

How often the recognition process runs, in seconds.

Revenue schedules are created as invoices are generated. Enable the feature before you start billing the customers whose revenue you want to track.

For details on setting configuration properties, refer to the Kill Bill Configuration Guide.

Using Revenue Recognition APIs

Full API documentation is available at our API documentation.

All revenue recognition endpoints are under ${KB_URL}/plugins/aviate-plugin/v1/revenue. Every request needs your Aviate token (Authorization: Bearer …​) and your tenant’s Kill Bill API key and secret. Parameters are passed in the query string. Send POST requests with Content-Type: application/json and an empty JSON body ({}).

Using Revenue Recognition in Aviate

Insider Preview participants get access to the Revenue Recognition screens in Aviate. The screenshots below were taken with sample data: plans, amounts, accounts and email addresses are examples. The layout can change during the preview.

Screen What it shows

Dashboard

Recognized and deferred revenue, recent accounting periods, and the plans with the most revenue

Waterfall

Recognized and deferred revenue per accounting period, filtered by period range and currency

Periods

Accounting periods, with their status and the close and reopen actions

Schedules

One row per revenue schedule, filtered by method, period, account, plan or dates. Open a schedule to see its invoice, invoice item, item type, method, service period and entries

By Plan

Total, recognized and deferred revenue per plan

Rates

The share of revenue already recognized, per method (straight line or immediate)

SSP

Standalone selling prices per plan, phase and currency, with their source and validity dates

Allocations

Contract allocations: number of terms, transaction price and allocation method

Accounting Periods Screen

Accounting periods screen
  • A period is either Open or Closed.

  • An open period whose end date has passed is flagged Overdue. This is a reminder to close it, not a separate status.

  • The Close action is offered on the oldest open period whose end date has passed, so months are closed in order.

  • The Reopen action is offered on closed periods.

  • Closed By shows who closed the period.

Recognition Rates Screen

Recognition rates screen

This screen compares straight-line and immediate revenue: number of schedules, total, recognized and deferred amounts, and the average number of days since invoicing.

How Revenue Is Recognized

Schedule Creation

When Kill Bill generates an invoice, Aviate creates a revenue schedule for each eligible invoice item and generates its entries (see Recognition Methods). It also creates the monthly accounting periods those entries fall into, if they do not exist yet. Creating a schedule does not recognize any revenue.

Daily Recognition

A background process runs at the configured interval, once a day by default. Each run:

  • Recognizes every unrecognized entry dated on or before the current date (UTC) in an open period, including entries dated today.

  • Updates each affected schedule’s recognized and deferred amounts.

  • Closes a schedule once its full amount has been recognized.

Revenue belongs to the accounting period of its service date, not to the date the process ran. Revenue for April recognized by a run in May stays in April.

Recognizing Revenue for a Specific Month

In production, regular runs recognize revenue for each day of the month as it passes. Once a run executes on or after the last day of the month, the system has processed all revenue entries for that month.

The month-end workflow is:

  1. Wait for a recognition run on or after the last day of the month.

  2. Review the month with the period summary and the waterfall report.

  3. Close the period.

See Closing a Period for the steps.

Running Recognition On Demand

The triggerRevenueRecognition endpoint runs recognition immediately, up to a date that you choose:

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/triggerRevenueRecognition?recognitionDate=2026-04-30" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'
Parameter Required Description

recognitionDate

Yes

Recognize entries dated on or before this date (YYYY-MM-DD)

A successful request returns 204 No Content. A missing recognitionDate is rejected with recognitionDate is required.

The run works like a daily run, except that it uses recognitionDate instead of the current date:

  • It recognizes every unrecognized entry dated on or before recognitionDate in an open period, and updates and closes schedules in the same way.

  • It applies to all accounts of the tenant. It cannot be limited to an account, a contract or a single month.

  • A recognitionDate in the future recognizes revenue for service that has not been delivered yet.

  • Recognized entries cannot be reverted. Reopening a period does not change entries that were already recognized.

  • Do not run it at the same time as the scheduled recognition run.

Managing Accounting Periods

Creating a Period

Periods are created automatically, but you can create one ahead of time. All three parameters are required. The name must be unique, and the end date cannot be before the start date. A successful request returns 201 Created.

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods?periodName=2026-05&startDate=2026-05-01&endDate=2026-05-31" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'
Note
Note: Revenue entries are assigned to periods by name. Use the YYYY-MM format with the first and last day of the month. A period with any other name receives no revenue entries.

Listing Periods

Add closed=true or closed=false to list only closed or only open periods.

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods?closed=false" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

To view a single period, use GET /v1/revenue/periods/{name}, for example /v1/revenue/periods/2026-04.

Each period includes:

Field Description

periodName

The period name, for example 2026-04

startDate, endDate

The first and last day of the period

closed

true if the period is closed

closedDate, closedBy

When and by whom the period was closed. Empty for open periods.

Viewing a Period Summary

The period summary returns the recognized amount, the deferred (not yet recognized) amount and the number of entries in the period, for all currencies combined:

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods/2026-04/summary" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

For one row per currency, use currencySummary instead:

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods/2026-04/currencySummary" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

If you bill in more than one currency, use the currency summary. The plain summary adds amounts in different currencies together.

Closing a Period

To close a month:

  1. Check that a recognition run has taken place on or after the last day of the month.

  2. Review the period summary and the waterfall report for that month.

  3. Close the period. A successful close returns 204 No Content.

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods/2026-01/close" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'

The close is rejected if the period does not exist, is already closed, or still contains unrecognized revenue entries. In the last case the error reports how many entries remain, for example Cannot close period 2026-01: 12 unrecognized entries remain.

If the close is still rejected after a recognition run has taken place on or after the last day of the month, review the remaining entries (see Invoice Adjustments, Credits and Cancellations). You can then override this check with force=true:

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods/2026-01/close?force=true" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'

Closing a period does not block new invoices, credits or adjustments for that month. See Invoice Adjustments, Credits and Cancellations.

Reopening a Period

In exceptional cases, a closed period can be reopened for corrections. A successful reopen returns 204 No Content. The request is rejected if the period does not exist or is not closed.

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/periods/2026-01/reopen" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'

Reopening clears the closed date and closed-by user. Entries in the period that were not yet recognized become eligible again, and the next recognition run can pick them up. Entries that were already recognized are not changed.

Revenue Reports

Revenue Waterfall

The waterfall report shows recognized and deferred revenue for each accounting period, with one row per period and currency:

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/reports/waterfall?startPeriod=2026-01&endPeriod=2026-06&currency=USD" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

All parameters are optional:

Parameter Description

startPeriod

First period to include (YYYY-MM, inclusive)

endPeriod

Last period to include (YYYY-MM, inclusive)

currency

Only include revenue in this currency, for example USD

Each row contains the accounting period, the currency, the recognized amount, the deferred (not yet recognized) amount and the number of entries. The report is returned as JSON, so you can load it into a spreadsheet or another reporting tool.

Revenue by Plan

Total, recognized and deferred amounts and the number of schedules for each plan, across the whole tenant. Takes no parameters.

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/reports/by-plan" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

Recognition Rate

For each recognition method (straight-line or immediate): total amount, recognized amount, the share recognized so far and the number of schedules, across the whole tenant. Takes no parameters.

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/reports/recognition-rate" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

How Reports Are Calculated

Reports are built from two different sources. Their figures can differ after adjustments, credits or cancellations.

Report Built from Currency handling

Period summary

Revenue entries in the period

All currencies added together

Period currency summary

Revenue entries in the period

One row per currency

Revenue waterfall

Revenue entries, by period

One row per period and currency

Revenue by plan

Schedule totals

All currencies added together

Recognition rate

Schedule totals, by recognition method

All currencies added together

In entry-based reports, "deferred" is the total of entries not yet recognized.

Contract Revenue Allocation

When a contract covers several subscriptions, Aviate uses standalone selling prices (SSP) to allocate the contract’s transaction price across them.

How Allocation Works

Each subscription in the contract is a contract term. Consider a contract with three subscriptions whose first invoice totals $15,000:

  • Enterprise subscription: $10,000/year (SSP: $10,000)

  • Implementation services: $3,000 one-time (SSP: $5,000)

  • Premium support: $2,000/year (SSP: $2,000)

  • Transaction price: $15,000

Using relative SSP allocation:

Contract term SSP SSP % Allocated Revenue

Subscription

$10,000

58.8%

$8,823.53

Implementation

$5,000

29.4%

$4,411.76

Support

$2,000

11.8%

$1,764.71

The implementation fee ($3,000 charged) receives an allocation of $4,411.76 because relative-SSP allocation distributes the total transaction price proportionally. Any rounding difference is assigned to the last term, so the allocations add up exactly to the transaction price.

The following rules apply:

  • When allocation happens. A contract is allocated automatically when its first invoice is generated. The transaction price is the total of that invoice’s positive charges for the contract’s subscriptions. Once a contract has allocations, later invoices do not recalculate them, so later changes to SSPs do not affect it.

  • Which SSP is used. For each term, Aviate uses the most recent SSP for the term’s plan, phase and currency that is in effect on the allocation date.

  • Missing SSPs. If a term has no SSP in effect, its SSP is taken as an equal share of the transaction price (the transaction price divided by the number of terms).

  • How allocations are used. Once a contract term has an allocation, Aviate uses the allocated amount as the total of every revenue schedule created for that subscription’s invoice items, instead of the invoice item amount.

  • Allocating explicitly. You can run the allocation yourself with a transaction price of your choice (see below). Doing so replaces any existing allocation for the contract’s terms. Schedules that already exist are not recalculated.

  • Subscriptions without a contract. Subscriptions that are not part of a contract, such as self-service sign-ups, get revenue schedules and daily recognition, but no allocation.

We recommend setting explicit SSPs for every plan and phase used in contracts, so that allocations are consistent and auditable.

Setting Standalone Selling Prices

SSPs are set per plan, phase and currency, with a validity period. You can manage them on the SSP screen in Aviate, or through the API:

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/ssp?planName=implementation-services&phaseName=implementation-services-fixedterm&currency=USD&amount=5000.00&effectiveDate=2026-01-01" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'
Parameter Required Description

planName

Yes

Kill Bill plan name

phaseName

Yes

Kill Bill phase name of the plan

currency

Yes

Currency of the SSP, for example USD

amount

Yes

Standalone selling price

effectiveDate

Yes

First day the SSP applies (YYYY-MM-DD)

expirationDate

No

Last day the SSP applies. Leave empty for no end date.

source

No

Free-text label for where the price comes from. Defaults to LIST_PRICE.

A successful request returns 201 Created. To list all SSPs, use GET /v1/revenue/ssp. To delete one, use DELETE /v1/revenue/ssp/{id}. Deleting an SSP removes it permanently and does not change allocations that were already made.

Allocating a Contract Explicitly

currency and transactionPrice are required. The response lists the resulting allocation for each contract term.

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/contracts/${CONTRACT_ID}/allocations?currency=USD&transactionPrice=15000.00" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{}'

To view a contract’s allocations without changing them, send a GET request to the same path. For each term, the result shows the plan, phase, list price, SSP, SSP ratio, allocated amount, transaction price, currency and allocation method.

Viewing Revenue Details

By Account, Subscription or Plan

List revenue schedules with any combination of these filters:

Parameter Description

accountId

Schedules of one account

subscriptionId

Schedules of one subscription

planName

Schedules for one plan

currency

Schedules in one currency

closed

true for closed schedules, false for open ones

servicePeriodStart

Schedules whose service period starts on or after this date (YYYY-MM-DD)

offset, limit

Paging. limit defaults to and cannot exceed 1000.

Results are returned newest first.

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/schedules?accountId=${ACCOUNT_ID}&closed=false&limit=50" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

By Contract

Contract allocations and the revenue schedules of a contract are available through two calls. The contract ID is a UUID.

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/contracts/${CONTRACT_ID}/allocations" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/contracts/${CONTRACT_ID}/schedules" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

By Invoice Item or Schedule

Get the schedule of an invoice item, using its Kill Bill invoice item ID:

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/${INVOICE_ITEM_ID}/schedule" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

Get a schedule by its ID. Schedule IDs are numbers and are returned in the schedule details.

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/schedules/${SCHEDULE_ID}" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

List the revenue entries of a schedule, showing each entry’s date, amount, accounting period and whether it has been recognized:

curl "${KB_URL}/plugins/aviate-plugin/v1/revenue/${SCHEDULE_ID}/entriesPerSchedule" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}"

Business Rules and Constraints

Recognition

  • Recognition follows the service dates on the invoice item, not the invoice date or the payment date. Revenue is recognized whether or not the invoice has been paid.

  • Revenue is always assigned to calendar months. Custom fiscal calendars (for example 4-4-5 periods) are not supported.

Closed Periods

  • Closing a period does not block billing. Kill Bill still accepts invoices, credits, adjustments and payments dated in a closed period.

  • If a new invoice item has service dates in a closed period, Aviate does not create its revenue entries. If you expect back-dated invoices, reopen the affected period before the invoice is generated.

Data You Cannot Edit

Revenue schedules and entries are derived from invoices. You cannot create, edit or delete them directly.

Invoice Adjustments, Credits and Cancellations

Adjustments, credits and cancellations can change revenue schedules. How these changes affect recognized and deferred revenue, and how they interact with closed periods, is still being finalized in this preview. During the preview, review revenue for any month that contains an adjustment, a credit or a mid-period cancellation before you close it. If you are testing this module, tell us which treatment your accounting policy requires.

Not Included in This Preview

  • Accounting journal entries, or an export to an ERP or general ledger

  • A recognition method set per plan or per product

  • Equal monthly amounts with prorated first and last months. Straight-line revenue is calculated per day

  • Editing or reversing a revenue entry by hand. Schedules are created from invoices

  • Approval of a schedule before recognition

  • Blocking invoices, credits or adjustments in a closed period

Examples

Monthly Subscription

A customer is invoiced $31.00 for a monthly plan covering 2026-01-01 to 2026-02-01.

  • Aviate creates a straight-line schedule with a total of $31.00, all deferred.

  • The service period is 31 days, so Aviate creates 31 entries of $1.00, dated 2026-01-01 to 2026-01-31, all in period 2026-01.

  • After the run on 2026-01-10, $10.00 is recognized and $21.00 is deferred.

  • After the run on 2026-01-31, the full $31.00 is recognized and the schedule is closed.

Quarterly Subscription Spanning Three Months

A customer is invoiced $90.00 for a quarterly plan covering 2026-01-01 to 2026-04-01, which is 90 days. The daily amount is $1.00:

Period Days Revenue

2026-01

31

$31.00

2026-02

28

$28.00

2026-03

31

$31.00

Total

90

$90.00

At the end of January, $31.00 is recognized and $59.00 is still deferred.

Rounding

A customer is invoiced $100.00 for 2026-04-01 to 2026-05-01 (30 days). Each of the first 29 entries is $3.333333333 (100 รท 30, rounded to nine decimals). The last entry, on 2026-04-30, is $3.333333343, so that the 30 entries add up to exactly $100.00.

One-Time Setup Fee

A customer is invoiced a fixed $250.00 setup fee with a service start date of 2026-04-15. Aviate creates an immediate schedule with one entry of $250.00 in period 2026-04. The first run on or after 2026-04-15 recognizes the full amount and closes the schedule.

Month-End Close

On 2026-05-02, the finance team closes April:

  1. The daily run on 2026-04-30 or later has recognized all April entries.

  2. GET /v1/revenue/periods/2026-04/summary shows the recognized total for April with a deferred amount of 0.

  3. POST /v1/revenue/periods/2026-04/close returns 204 No Content.

  4. GET /v1/revenue/periods?closed=true now lists 2026-04 with the closing date and user.

If unrecognized entries had remained in April, step 3 would have been rejected with Cannot close period 2026-04: N unrecognized entries remain. After reviewing them, the team could close the month with force=true.