Skip to main content

Billing Overview

High Level Domain

Billing Domain Diagram

Fundamental Concepts

Service Entitlement vs money

Entitlement: what the customer can still use:

  • placement_credit (sponsored placements)
    • 16 Sponsored Placement coins left
  • gig_credit_cents (stored value credits measured in cents)
    • 23717 gig credits left (cents value of $237.17)

Money: is what finance cares about:

  • deferred revenue (you owe since delivery)
  • principal liability (refundable stored value)
  • recognised revenue (earned)
important

The term "Entitlement" is important to memorise and understand. It will be used extensively throughout the documentation. It is an umbrella term to represent "what users CAN do on the platform", which can be anything that requires a "stored value" (i.e. credits):

  • creating a Career::Job post for X placement credits
  • creating a Gig::Job with shifts for Y gig credits
  • creating a Ad::Campagin over 7 days for Z placement credits

Ledger vs Projection

Ledger

  • append-only journal of all balance-affecting actions
    • grant, reserve, release, consume, adjust

Projection

  • Cached "current state" tables for fast reads (e.g. balances, active holds)
  • Projections are rebuildable from the ledger

Deferred Revenue vs Principal liability

Deferred Revenue

  • money received in the bank account, but service is not yet provided (i.e. SFRS(I) 15)

Principal Liability

  • money/credits refundable to the customer
  • behaves like a "stored value" that we owe back (not revenue)

Reservation is not consumption

  • Reserve moves units from available -> reserved
  • Consume reduces units
    • usually from reserved, sometimes directly from available
  • Ensures company cannot overspend by:
    • multiple gig job postings
    • multi-day campaigns where credits cost more than what they have

Why Gig is special?

Gig Credits require:

  • FIFO (first in first out)
  • Per-lot platform fee rates
  • We MUST track consumption against purchase batches

Sponsored Placements (Ads, Career Job Post, Boost):

  • does not need per-batch tracking like Gig
  • track proportionally

Xero-friendly exports

  • Finance process is lump-sum journaling (daily or monthly)
  • Internal system still needs customer-level statements and auditability (SOA for companies)
  • Design should support both without refactors

Overview

::Billing will be the bounded context that manages:

  • customer entitlements (units)
  • deferred revenue / liability movements (money)
  • reservations and consumption
  • statement of accounts (SOA)
  • finance exports compatible with current journaling workflow and future Xero Integration

Products/Instruments supported

Placement Credits (visibility-driven, pool deferred revenue)

  • Ads (display placements)
  • Job Boost (featured placement for a duration)
  • Careers Job Postings (per post/per application later)

Gig Credits (stored value + FIFO lots for platform fee):

  • credit represents wage value
  • platform fee deferred and recognised by FIFO lots

Subscription (Workforce, future)

  • introduce later as another entitlement type
    • seat-days
    • seat-months
    • or contract schedules

Glossary

termdescriptionexamples
Entitlement Typedefines unit type and accounting policyplacement_credit, gig_credit_cents
Ledger Entryone atomic balance-changing record (append only)-
Balancecurrent available/reserved units and deferred money for a given entitlement type10030cents available gig credits, 10 placement credits reserved for 7 day campaign
Holdactive reservation projection keyed by a referenceGig::Shift#123, Ad::CampaignPlacement#456
Lotgig purchase batch with its own platform fee rate. Used for FIFO allocationCompany A would have 3 Billing::Lot if they purchased gig credits 3 different times. Each lot would store the platform fee margin.
Allocationmapping from a ledger entry to one or more lots (gig only)-
Referenceexternal domain object that caused the billing eventAds::Campaign, Careers::Job, Gig::Shift (reserve), Gig::ShiftSettlement (consume)
Productglobal definition of what is being sold (stable); used to derive entitlements granted1000 Placement Credit Pack without the price attached to it. We can sell the same pack across different countries.
Offermarket-specific price list row for a product (currency, taxes, seller legal entity, gig fee terms)1000 Placement Credit Pack in SG costs $100, while in ID it might cost IDR 1,000,000. Tax calculation also is different in each country
Legal Entityyour seller-of-record for a jurisdiction (drives invoice numbering + tax treatment)Represents Jod legal entities in different countries. Possible to have multiple entities in a single country.
Bill-To Profilecustomer billing recipient details (address/contact), owned by the customer companyCompany A might use the platform, but it's sister company might be the one that makes payments on behalf of Company A.
Invoicecustomer-facing commercial document generated from an offer snapshot-
Paymentoffline bank transfer record + verification statusEach invoice tied to one or more payments recorded manually by business/finance team
Postingthe idempotent internal action that grants entitlements into the ledger once an invoice is settledAn accounting action and not a "product use-case".

Modelling canonical "financial primitives"

Stable finance primitives we can use instead of using domains (Ads/Gig/etc.).

These primitives apply to all instruments listed in billing_entitlement_types (e.g. gig_credit_cents, placement_credits, subscriptions, etc.)

  • Only the policies differ per entitlement type.
termdescriptionexample
Grantincrease available entitlements (usually after payment verification)Company made payment via bank transfer. Business marks invoice as paid and credits will be "granted" to the company's billing account
Reserve (Hold)move available to reserved (to prevent overspend)100 credits reserved after company posts a Gig::Shift, 20 credits reserved after company creates an Ad::Campaign
Releasemove reserved back to available (campaign cancelled, shift cancelled)Previously reserved 100 credits moved back into usable credits cause Gig::Shift was cancelled.
Consumereduce reserved or available (service delivered)Gig::ShiftSettlement created, Daily for a 7 day ad campaign.
Adjustmanual correctionsThink CAFS

Entitlement TYpes

Placement Credits (placement_credits)

Services granted:

  • Ads (display placements)
  • Job Boost (featured placement for a duration)
  • Careers Job Posting (per post / per application)

Finance Policy:

  • Units are pooled regardless of price and time of purchase
    • no per-purchase unit price tracking like in Gig
  • Money tracking:
    • deferred_revenue_cents (remaining)
    • revenue recognised proportionally at consumption time:
      • recognised = units_consumed * (deferred_revenue_before / units_before)

Gig Credits (gig_credit_cents)

  • Units represents the wage value (in cents)
  • Requires FIFO lots because platform fee rate can differ per purchase/invoice.
  • Money tracking:
    • principal liability
      • Jod owes stored value back or owes to provide a service like finding applicants for Gig or placing an ad on the website.
    • platform fee deferred and recognised based on FIFO lot allocations
  • Reservation may span multiple lots

Subscriptions (future)

Subscriptions (e.g. for Workforce management) will be introduced as another entitlement type (seat-days, seat-months) and/or based on the contract from sales.

Projections (fast reads) vs ledger (truth)

Two main projections:

  • billing_entitlement_balances
    • what is the available gig_credits_cents/placement_credits?
    • what is the reserved gig_credits_cents/placement_credits?
    • what is the deferred revenue existing on gig_credits_cents/placement_credits?
  • billing_entitlement_holds
    • what active holds (gig_credits_cents/placement_credits) exist for a given reference (e.g. Gig::Shift, Ad::Campaign, Boost::Job)

Both should be updated in the same DB transaction as when creating a ledger entry record. Both are rebuildable from ledger (and lots for gig)

Considering Xero Integration

We design for two export modes for Xero automation:

  • Journal mode
    • Aggregate daily totals across the platform
      • movement in deferred revenue
      • recognised revenue
      • gig credits consumed (liability reduction)
      • insurance deductions/sponsored amounts
    • Export as journal lines (CSV now, API later)
  • Invoice mode (future)
    • Later we want per-customer sales invoices in Xero
      • Keep billing_invoices and billing_payments
      • Ledger remains the "delivery and recognition" system of record

Ledger stores recognition snapshots at the moment of consumption.

  • ensure can export accounting entries later without recomputing history and risking drift.