GASP

Commercial Event Ledger (CEL)

The single source of truth for all metric computation in the GASP Standard.

Every metric in this standard — revenue, retention, efficiency, operational — derives from atomic commercial events. The CEL is the governed layer where those events live. If an event is not in the CEL, it does not exist for metric purposes. If a metric cannot be traced to CEL events, it is not a governed metric.


Why the CEL Exists

SaaS companies typically compute metrics from derived tables: MRR snapshots, billing system exports, CRM rollups. These derived sources introduce drift. Two teams querying the same concept from different derived tables get different numbers. The CEL eliminates this by establishing a single event-level layer from which all metrics are computed.

The CEL is not a product. It is a conceptual standard for how commercial events should be captured, stored, and governed. Implement it in your warehouse, your lakehouse, or your operational database. The schema is the contract.


Design Principles

  1. Immutable events. Once recorded, a CEL event is never modified. Corrections are new events (e.g., a Revenue_Event of type adjustment). This preserves auditability and enables point-in-time reconstruction.

  2. No derived data upstream. The CEL contains atomic facts. MRR, ARR, NRR, and every other metric are computed from CEL events, never stored in the CEL. Derived values live downstream.

  3. Daily atomic grain. Every event has a date. The day is the smallest unit. Weekly, monthly, quarterly, and annual views are aggregations of daily events.

  4. One event, one truth. Each commercial event is recorded once. If a subscription renewal generates both a Revenue_Event and a Contract_Event, those are two distinct events — not one event with two types.

  5. Source-system agnostic. The CEL defines what to capture, not where it comes from. Events may originate in billing systems, CRMs, HRIS, or manual entries. The CEL schema is the normalization layer.


Event Classes

The CEL defines five event classes. Every commercial event in a subscription SaaS business falls into one of these.

Revenue_Event

A change in recurring revenue. This is the primary input for MRR, ARR, NRR, GRR, and revenue churn metrics.

FieldTypeDescription
event_idstringUnique identifier
event_datedateDate the event occurred
customer_idstringCustomer identifier
subscription_idstringSubscription identifier
event_typeenumnew, expansion, contraction, churn, reactivation, renewal
mrr_changedecimalChange in MRR (positive for new/expansion/reactivation, negative for contraction/churn)
currencystringISO 4217 currency code
prior_mrrdecimalMRR before this event
new_mrrdecimalMRR after this event

Cost_Event

An incurred cost attributable to a commercial function. Primary input for CAC, Gross Margin, LTV, and efficiency metrics.

FieldTypeDescription
event_idstringUnique identifier
event_datedateDate the cost was incurred
cost_centrestringDepartment or team
amountdecimalCost amount
currencystringISO 4217 currency code
cost_typeenumpersonnel, software, services, infrastructure, other
customer_idstring (nullable)Customer if directly attributable; null for shared costs
descriptionstringHuman-readable description

Contract_Event

A contractual milestone. Primary input for bookings, renewal rate, and contract-level metrics.

FieldTypeDescription
event_idstringUnique identifier
event_datedateDate of contractual action
customer_idstringCustomer identifier
subscription_idstringSubscription identifier
event_typeenumnew_contract, renewal, amendment, cancellation
contract_startdateContract start date
contract_enddateContract end date
tcvdecimalTotal contract value
acvdecimalAnnual contract value
currencystringISO 4217 currency code

Amendment_Event

A mid-term change to an existing subscription. Distinct from Contract_Event because amendments happen during a contract term, not at boundaries. Primary input for expansion/contraction classification.

FieldTypeDescription
event_idstringUnique identifier
event_datedateDate of amendment
customer_idstringCustomer identifier
subscription_idstringSubscription identifier
amendment_typeenumupgrade, downgrade, add_on, seat_change, pricing_change
mrr_changedecimalChange in MRR resulting from amendment
prior_planstringPlan/tier before amendment
new_planstringPlan/tier after amendment
prior_quantityinteger (nullable)Seat/unit count before (if applicable)
new_quantityinteger (nullable)Seat/unit count after (if applicable)

Lifecycle_State_Change

A change in customer lifecycle status. Primary input for health scores, onboarding metrics, and churn prediction.

FieldTypeDescription
event_idstringUnique identifier
event_datedateDate of state change
customer_idstringCustomer identifier
prior_statestringPrevious lifecycle state
new_statestringNew lifecycle state
state_categoryenumactivation, onboarding_complete, healthy, at_risk, churned, reactivated
triggerstringWhat caused the state change (e.g., “health score drop below 40”, “90-day inactivity”)

Example Events

These worked examples show how real-world commercial actions map to CEL events.

1. Subscription Activation

A new customer signs up for a $500/mo plan.

{
  "event_class": "Revenue_Event",
  "event_id": "rev-001",
  "event_date": "2026-02-01",
  "customer_id": "cust-1042",
  "subscription_id": "sub-2001",
  "event_type": "new",
  "mrr_change": 500.00,
  "currency": "USD",
  "prior_mrr": 0.00,
  "new_mrr": 500.00
}

2. Usage Commit Realisation

An existing customer’s usage commitment triggers an additional $200/mo.

{
  "event_class": "Revenue_Event",
  "event_id": "rev-002",
  "event_date": "2026-02-15",
  "customer_id": "cust-0783",
  "subscription_id": "sub-1450",
  "event_type": "expansion",
  "mrr_change": 200.00,
  "currency": "USD",
  "prior_mrr": 1000.00,
  "new_mrr": 1200.00
}

3. Mid-Term Expansion (Seat Add)

Customer adds 10 seats at $50/seat/mo mid-contract.

{
  "event_class": "Amendment_Event",
  "event_id": "amd-001",
  "event_date": "2026-02-10",
  "customer_id": "cust-0512",
  "subscription_id": "sub-0890",
  "amendment_type": "seat_change",
  "mrr_change": 500.00,
  "prior_plan": "Professional",
  "new_plan": "Professional",
  "prior_quantity": 20,
  "new_quantity": 30
}

4. Cross-Module Expansion

Customer on the Analytics module purchases the Automation module.

{
  "event_class": "Amendment_Event",
  "event_id": "amd-002",
  "event_date": "2026-03-01",
  "customer_id": "cust-0512",
  "subscription_id": "sub-0891",
  "amendment_type": "add_on",
  "mrr_change": 800.00,
  "prior_plan": "Analytics Pro",
  "new_plan": "Analytics Pro + Automation",
  "prior_quantity": null,
  "new_quantity": null
}

5. Reactivation

A previously churned customer returns with a new subscription.

{
  "event_class": "Revenue_Event",
  "event_id": "rev-003",
  "event_date": "2026-02-20",
  "customer_id": "cust-0291",
  "subscription_id": "sub-2050",
  "event_type": "reactivation",
  "mrr_change": 750.00,
  "currency": "USD",
  "prior_mrr": 0.00,
  "new_mrr": 750.00
}

6. Onboarding Engineering Cost

Implementation team spends 40 hours onboarding a new enterprise customer.

{
  "event_class": "Cost_Event",
  "event_id": "cost-001",
  "event_date": "2026-02-05",
  "cost_centre": "Implementation",
  "amount": 6000.00,
  "currency": "USD",
  "cost_type": "personnel",
  "customer_id": "cust-1042",
  "description": "40 hrs implementation engineering @ $150/hr"
}

7. Implementation Labour (Shared)

Marketing spend on demand generation — not attributable to a single customer.

{
  "event_class": "Cost_Event",
  "event_id": "cost-002",
  "event_date": "2026-02-28",
  "cost_centre": "Marketing",
  "amount": 45000.00,
  "currency": "USD",
  "cost_type": "services",
  "customer_id": null,
  "description": "February demand generation campaigns"
}

8. Retention Success Servicing

CS team effort to retain an at-risk account.

{
  "event_class": "Cost_Event",
  "event_id": "cost-003",
  "event_date": "2026-02-12",
  "cost_centre": "Customer Success",
  "amount": 2400.00,
  "currency": "USD",
  "cost_type": "personnel",
  "customer_id": "cust-0783",
  "description": "16 hrs success engineering for at-risk retention"
}

9. Contract Renewal

Customer renews for another 12-month term.

{
  "event_class": "Contract_Event",
  "event_id": "con-001",
  "event_date": "2026-03-01",
  "customer_id": "cust-0350",
  "subscription_id": "sub-0670",
  "event_type": "renewal",
  "contract_start": "2026-03-01",
  "contract_end": "2027-02-28",
  "tcv": 24000.00,
  "acv": 24000.00,
  "currency": "USD"
}

10. Health Score Drop

Customer’s health score deteriorates, triggering an at-risk state.

{
  "event_class": "Lifecycle_State_Change",
  "event_id": "lsc-001",
  "event_date": "2026-02-18",
  "customer_id": "cust-0783",
  "prior_state": "healthy",
  "new_state": "at_risk",
  "state_category": "at_risk",
  "trigger": "Health score dropped from 72 to 35"
}

Example SQL

A minimal warehouse implementation. This is illustrative, not normative — adapt to your warehouse dialect and tooling.

Schema

CREATE TABLE cel_revenue_events (
    event_id        VARCHAR(64) PRIMARY KEY,
    event_date      DATE NOT NULL,
    customer_id     VARCHAR(64) NOT NULL,
    subscription_id VARCHAR(64) NOT NULL,
    event_type      VARCHAR(20) NOT NULL,  -- new, expansion, contraction, churn, reactivation, renewal
    mrr_change      DECIMAL(12,2) NOT NULL,
    currency        CHAR(3) NOT NULL DEFAULT 'USD',
    prior_mrr       DECIMAL(12,2) NOT NULL,
    new_mrr         DECIMAL(12,2) NOT NULL,
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE cel_cost_events (
    event_id        VARCHAR(64) PRIMARY KEY,
    event_date      DATE NOT NULL,
    cost_centre     VARCHAR(64) NOT NULL,
    amount          DECIMAL(12,2) NOT NULL,
    currency        CHAR(3) NOT NULL DEFAULT 'USD',
    cost_type       VARCHAR(20) NOT NULL,
    customer_id     VARCHAR(64),
    description     TEXT,
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Querying: MRR at End of Month

SELECT
    DATE_TRUNC('month', event_date) AS month,
    SUM(mrr_change) AS net_mrr_change
FROM cel_revenue_events
WHERE event_date <= '2026-02-28'
GROUP BY 1
ORDER BY 1;

Querying: New MRR in February

SELECT SUM(mrr_change) AS new_mrr
FROM cel_revenue_events
WHERE event_type = 'new'
  AND event_date BETWEEN '2026-02-01' AND '2026-02-28';

Relationship to Existing Data Model

The GASP Standard defines a three-level entity hierarchy in Definitions:

EntityCEL Relationship
Customercustomer_id on all event classes. A customer churns when their last active subscription generates a churn Revenue_Event.
Subscriptionsubscription_id on Revenue_Event, Contract_Event, and Amendment_Event. MRR lives here.
LicenseNot directly in the CEL. Licenses are derived from subscriptions. Seat counts appear on Amendment_Event as prior_quantity / new_quantity.

The CEL does not replace the entity model. It records events that happen to entities. The entity model defines the nouns; the CEL defines the verbs.


Scope Boundaries

The CEL covers:

  • All recurring revenue changes (new, expansion, contraction, churn, reactivation, renewal)
  • Costs attributable to commercial functions (S&M, COGS, implementation, support)
  • Contractual milestones (new, renewal, amendment, cancellation)
  • Mid-term subscription changes
  • Customer lifecycle state transitions

The CEL does not cover:

  • Product usage events (page views, feature clicks, API calls) — these belong in a product analytics layer
  • GAAP revenue recognition events — these belong in the accounting ledger
  • HR events (hiring, termination) — unless directly costed as Cost_Event
  • Infrastructure events (deployments, incidents) — these belong in engineering observability

The CEL is scoped to the same domain as the rest of the GASP Standard: subscription-based SaaS with recurring revenue. Usage-based pricing, marketplace transactions, and services-only revenue are out of scope.


What Comes Next

The CEL provides the atomic events. The Attribution Taxonomy Layer (ATL) provides the tags that make dual-lens metrics possible — classifying each event by lifecycle stage, expansion type, and cost function. Together, CEL + ATL form the foundation for Operating (O) and Market (M) metric forms — giving ops teams their internal economic truth and boards the investor-comparable numbers, computed from the same events.

GASP Standard v1 · Last updated

Try searching for:

navigateselect