Beetles Docs

SaaS Revenue Recognition

Modeling deferred and realized revenue for subscription-based businesses.

SaaS Revenue Recognition

In a subscription business, you often collect payment upfront for a service delivered over time. According to accounting standards (like ASC 606), you cannot recognize the full payment as revenue immediately. Instead, you move it to Deferred Revenue and "earn" it monthly.

Architecture

We use two distinct ledgers to separate the cash you've received from the revenue you've actually earned.

Implementation Flow

Setup Ledgers

Create one ledger for the liability (money owed in service) and another for the actual business income.

# Liability Ledger
curl -X POST http://localhost:8080/v1/ledgers -d '{ "name": "Deferred Subscriptions" }'

# Income Ledger
curl -X POST http://localhost:8080/v1/ledgers -d '{ "name": "Realized SaaS Revenue" }'

Record Upfront Payment

When a customer pays $1,200 for an annual plan, you debit your bank account (Asset) and credit their Deferred Revenue account (Liability).

POST /v1/transfers
curl -X POST http://localhost:8080/v1/transfers 
  -d '{
    "debit_account_id": "BANK_CASH_ID",
    "credit_account_id": "CUSTOMER_DEFERRED_ID",
    "amount": 120000,
    "code": 1000 # Code: "Subscription Payment"
  }'

Monthly Revenue Recognition

Every month, you move $100 from the customer's Deferred account to your Realized Revenue ledger.

Monthly Recognition Job
curl -X POST http://localhost:8080/v1/exchanges 
  -d '{
    "source_account_id": "CUSTOMER_DEFERRED_ID",
    "destination_ledger_id": "REALIZED_REVENUE_LEDGER_ID",
    "amount": 10000,
    "code": 2000 # Code: "Revenue Recognition"
  }'

Advanced Scenarios

1. Handling Cancellations & Refunds

If a customer cancels mid-year and is entitled to a refund, you simply reverse the flow for the remaining balance.

Refund Remaining Balance
# Refund $600 of the remaining $1,200
curl -X POST http://localhost:8080/v1/transfers \
  -d '{
    "debit_account_id": "CUSTOMER_DEFERRED_ID",
    "credit_account_id": "BANK_CASH_ID",
    "amount": 60000,
    "code": 3000 # Code: "Subscription Refund"
  }'

2. Plan Upgrades (Proration)

When a customer upgrades from a $100/mo plan to a $200/mo plan mid-month:

  1. Calculate the remaining days of the old plan.
  2. Move the unused portion back to a temporary "Credit" account.
  3. Charge the new plan amount minus the credit.

Why this matters

  1. Audit Readiness: Your balance sheet correctly shows how much service you still owe to customers.
  2. Churn Impact: If a customer cancels mid-year, the remaining balance in CUSTOMER_DEFERRED is exactly what you need to refund.
  3. Financial Clarity: You see your "Earned Revenue" month-over-month, providing a true picture of business growth regardless of when the cash hit the bank.

Automation Tip: In production, you typically trigger the "Monthly Recognition" step using a workflow engine like Temporal, ensuring that the recognition happens exactly on the subscription anniversary every month.

On this page