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 →

Introduction

The Aviate Revenue Recognition module provides tools for managing when and how revenue is recognized from your subscriptions and contracts. It supports the standard accounting practices defined by ASC 606 (Revenue from Contracts with Customers), and it gives finance teams visibility into recognized vs. deferred revenue through managed accounting periods.

Key capabilities include:

  • Accounting periods — monthly periods that can be opened, closed, and reported on

  • Revenue schedules — automatic recognition of revenue across the term of a contract

  • Contract-aware allocation — revenue allocated across multiple performance obligations using relative standalone selling prices

  • Waterfall reports — period-by-period view of recognized and deferred revenue

Key Concepts

Accounting Periods

An accounting period represents a calendar month during which revenue recognition entries are recorded. Each period follows a simple lifecycle:

  • OPEN — entries can be added or modified

  • CLOSED — entries are frozen; no changes allowed

  • REOPENED — a closed period has been reopened by an administrator (for corrections)

Periods are auto-created monthly (named 2026-01, 2026-02, etc.) as invoices are generated. They can be explicitly closed at month-end to freeze the financials.

Revenue Recognition Schedules

When an invoice is generated, the system creates recognition entries that spread the revenue across the appropriate periods. For example:

  • A $1,200 annual subscription generates $100/month recognition entries across 12 periods

  • A $500 one-time setup fee is recognized immediately (or spread, depending on your rules)

  • Usage revenue is recognized in the period it was consumed

Contract Revenue Allocation (ASC 606)

When a contract includes multiple performance obligations (e.g., a subscription + setup + support), revenue is allocated proportionally based on standalone selling prices (SSP). This ensures compliance with ASC 606:

  1. Identify the performance obligations in the contract

  2. Determine the standalone selling price (SSP) for each obligation

  3. Allocate the total transaction price proportionally

  4. Recognize revenue as each obligation is satisfied

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

To enable revenue recognition, start Kill Bill with the following system property:

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

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.

Managing Accounting Periods

Listing Periods

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

Response:

[
  { "name": "2026-01", "status": "CLOSED", "totalRecognized": 45230.00 },
  { "name": "2026-02", "status": "OPEN",   "totalRecognized": 38100.00 }
]

Closing a Period

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}"

The system validates that all invoices in the period have recognition entries before allowing the close. If unrecognized entries exist, the close is rejected with a list of the affected invoices.

Reopening a Period (Admin Only)

In exceptional cases, a closed period can be reopened for corrections:

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 '{ "reason": "Correcting misclassified setup fee" }'
Note
Note: Reopening a period requires administrator privileges and creates an audit trail entry.

Revenue Waterfall Report

The waterfall report shows recognized revenue by period across all contracts:

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

Response:

{
  "periods": ["2026-01", "2026-02", "2026-03", "2026-04", "2026-05", "2026-06"],
  "rows": [
    {
      "contractId": "ctr-001",
      "contractName": "Acme Corp -- Enterprise",
      "totalValue": 12000.00,
      "recognized": [1000.00, 1000.00, 1000.00, 1000.00, 1000.00, 1000.00],
      "deferred": 6000.00
    },
    {
      "contractId": "ctr-002",
      "contractName": "Beta Inc -- Standard",
      "totalValue": 2400.00,
      "recognized": [200.00, 200.00, 200.00, 200.00, 200.00, 200.00],
      "deferred": 1200.00
    }
  ],
  "totals": {
    "recognized": [1200.00, 1200.00, 1200.00, 1200.00, 1200.00, 1200.00],
    "deferred": 7200.00
  }
}

This report is suitable for board-level financial reporting and can be exported for use in external accounting systems.

Contract Revenue Allocation

When contracts have multiple performance obligations, Aviate uses standalone selling prices (SSP) to allocate revenue per ASC 606.

How Allocation Works

Consider a contract with three components:

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

  • Total contract price: $15,000

Using relative SSP allocation:

Obligation SSP SSP % Allocated Revenue

Subscription

$10,000

58.8%

$8,824

Implementation

$5,000

29.4%

$4,412

Support

$2,000

11.8%

$1,765

Note that the implementation fee ($3,000 charged) receives an allocation of $4,412 because the SSP-based allocation distributes the total contract price proportionally. This is the standard ASC 606 treatment for contracts where any individual obligation is discounted.

The allocation is computed once at contract inception and frozen — subsequent changes to SSPs do not retroactively affect existing contracts.

Setting Standalone Selling Prices

SSPs can be configured at the product offering level:

curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/revenue/standalonePrices" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -H "X-Killbill-ApiKey: ${API_KEY}" \
  -H "X-Killbill-ApiSecret: ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{
    "productOfferingId": "po-impl",
    "standaloneSellingPrice": 5000.00,
    "currency": "USD",
    "effectiveDate": "2026-01-01"
  }'

SSP Fallback Order

If no explicit SSP is set, the system uses the following fallback order:

  1. The configured standalone selling price for the product offering

  2. The list price of the product offering (from the pricing tower)

  3. The contract line item price (as a last resort)

We recommend setting explicit SSPs for all product offerings to ensure consistent and auditable allocations.

Viewing Revenue Details

By Account

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

By Contract

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

Response:

{
  "contractId": "ctr-001",
  "totalValue": 15000.00,
  "totalRecognized": 8823.53,
  "totalDeferred": 6176.47,
  "obligations": [
    {
      "name": "Enterprise Subscription",
      "allocatedRevenue": 8824.00,
      "recognized": 5149.33,
      "deferred": 3674.67,
      "recognitionPattern": "STRAIGHT_LINE",
      "termMonths": 12
    },
    {
      "name": "Implementation Services",
      "allocatedRevenue": 4412.00,
      "recognized": 4412.00,
      "deferred": 0.00,
      "recognitionPattern": "POINT_IN_TIME"
    }
  ]
}