Skip to content

Billing

Billing

Purpose

Document subscription, payment, credit-application, dispute, dunning, and failed-operation recovery behavior.

Participants

  • Sirloin owns all billing state and APIs.
  • Chargebee owns subscription and invoice state.
  • Primer processes payments and disputes.
  • Postgres stores billing, fraud, failed-operation, and subscription-sync records.
  • PostHog and Klaviyo receive analytics and lifecycle events.

Sequence

sequenceDiagram
participant Brisket
participant Sirloin
participant Primer
participant Chargebee
participant DB as Postgres
Brisket->>Sirloin: Create checkout
Sirloin->>Primer: Create payment session
Sirloin-->>Brisket: Client token/order
Brisket->>Primer: User pays
Sirloin->>Chargebee: Poll invoice/subscription state
Sirloin->>DB: Apply credits if idempotency checks pass
Primer-->>Sirloin: Dispute webhook when dispute changes
  • apps/sirloin/internal/app/services/billing/createprimercheckout.go
  • apps/sirloin/internal/app/services/billing/submitpaidinvoice.go
  • apps/sirloin/internal/app/services/billing/events/poller.go
  • apps/sirloin/internal/app/services/billing/events/credits.go
  • apps/sirloin/internal/app/services/billing/disputes/primer_webhook.go
  • apps/sirloin/internal/app/services/billing/dunningretry.go

State Transitions

Checkout creates a Primer session. Chargebee invoice/subscription state is discovered primarily through polling. Credits are applied only after payment detection and idempotency checks. Failed operations are persisted for retry rather than silently dropped.

Invariants

  • Sirloin is the billing owner.
  • Chargebee polling is the primary event mechanism.
  • Primer disputes are webhook-driven.
  • Credit application must be idempotent.
  • Failed operations must remain retryable and auditable.

Error Paths

Dunning retries can succeed, remain processing, no-op when already paid or not in dunning, fail retryably, fail on hard decline, or be blocked by fraud velocity rules.

Tests And Verification

  • cd apps/sirloin && make run-tests
  • cd apps/sirloin && make run-tests-all
  • cd apps/sirloin && make lint