Files
carmanagement/docs/project-design/B2B_BILLING_AND_INVOICE_EXECUTION_PLAN.md
2026-05-26 19:28:44 -04:00

34 KiB

B2B Billing and Invoice Execution Plan

1. Objective

Build a billing and invoice system that manages the financial lifecycle behind B2B subscriptions.

The system must support:

  • Subscription invoices
  • Trial conversion invoices
  • Renewal invoices
  • One-time invoices
  • Usage-based invoices
  • Manual invoices
  • Payment collection
  • Payment retries
  • Credits
  • Refunds
  • Taxes
  • Discounts
  • Invoice adjustments
  • Failed payments
  • Invoice reconciliation
  • Revenue auditability
  • Admin billing operations

The billing system must integrate with the subscription policy system but remain logically separate from subscription status.


2. Core Principle

Subscription state and invoice state are related, but they are not the same thing.

Bad design:

subscription.status = invoice.status

Better design:

subscription.status = active
invoice.status = open
payment.status = failed
entitlement.access_level = full

A customer can have an active subscription and an unpaid invoice during a grace period.

A customer can have a canceled subscription and still owe an unpaid invoice.

A customer can have a paid invoice and no active subscription if the invoice was for a one-time service.

Do not merge these concepts. That is how billing systems become haunted.


3. Core Billing Entities

The billing system should use these primary objects:

billing_account
subscription
invoice
invoice_line_item
payment_intent
payment_attempt
payment_method
credit_balance
credit_note
refund
tax_record
billing_event
Entity Purpose
billing_account Represents the paying customer or company
subscription Represents recurring service agreement
invoice Represents money owed
invoice_line_item Represents individual charges or credits
payment_intent Represents attempt to collect invoice payment
payment_attempt Represents each actual payment try
payment_method Represents card, ACH, bank transfer, invoice terms, etc.
credit_balance Tracks customer prepaid or credited amount
credit_note Reduces or reverses invoice amount
refund Returns money after payment
tax_record Stores calculated tax details
billing_event Immutable audit trail

4. Billing Account Model

A billing account represents the organization or legal entity responsible for payment.

CREATE TABLE billing_accounts (
  id UUID PRIMARY KEY,

  workspace_id UUID NOT NULL,
  customer_id UUID NOT NULL,

  legal_name TEXT NOT NULL,
  billing_email TEXT NOT NULL,

  billing_address_line1 TEXT,
  billing_address_line2 TEXT,
  billing_city TEXT,
  billing_state TEXT,
  billing_postal_code TEXT,
  billing_country TEXT,

  tax_id TEXT,
  tax_exempt BOOLEAN DEFAULT FALSE,

  default_currency TEXT NOT NULL DEFAULT 'USD',
  default_payment_method_id UUID,

  invoice_terms TEXT NOT NULL DEFAULT 'due_on_receipt',
  net_terms_days INTEGER DEFAULT 0,

  provider_customer_id TEXT,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Billing account rules:

  • A workspace should have one primary billing account.
  • Enterprise customers may have multiple billing accounts if departmental billing is supported.
  • A billing account owns invoices, payment methods, and credit balance.
  • Billing contact information must be snapshotted on finalized invoices.
  • Invoices should preserve historical billing details and must not dynamically read current billing address after creation.

5. Invoice Lifecycle

Invoices should have their own state machine.

draft
open
paid
partially_paid
payment_pending
past_due
void
uncollectible
refunded
partially_refunded
Status Meaning
draft Invoice is being prepared and is not payable yet
open Invoice is finalized and awaiting payment
payment_pending Payment has been initiated but not completed
partially_paid Some amount has been paid, but balance remains
paid Invoice is fully paid
past_due Invoice due date has passed
void Invoice was canceled before payment
uncollectible Invoice is written off as bad debt
refunded Fully paid invoice was fully refunded
partially_refunded Paid invoice was partially refunded

6. Invoice State Transitions

Happy path:

draft
  ↓
open
  ↓
payment_pending
  ↓
paid

Failure flow:

open
  ↓
payment_pending
  ↓
open
  ↓
past_due
  ↓
uncollectible

Void flow:

draft/open
  ↓
void

Refund flow:

paid
  ↓
partially_refunded
  ↓
refunded
Current Status Event New Status Notes
draft Invoice finalized open Invoice becomes payable
draft Invoice canceled void No payment expected
open Payment started payment_pending Payment is in progress
open Full payment received paid Invoice closed
open Partial payment received partially_paid Balance remains
open Due date passed past_due Trigger dunning
payment_pending Payment succeeded paid Invoice closed
payment_pending Payment failed open Retry may continue
partially_paid Remaining balance paid paid Invoice closed
partially_paid Due date passed past_due Balance overdue
past_due Payment received paid Restore account if needed
past_due Written off uncollectible Bad debt
paid Partial refund issued partially_refunded Access review may be needed
paid Full refund issued refunded Access review required
open Admin voids invoice void Audit required

7. Invoice Types

subscription_initial
subscription_renewal
trial_conversion
subscription_upgrade
subscription_downgrade_credit
usage_based
one_time
manual
correction
cancellation_fee
Invoice Type Description
subscription_initial First paid invoice for a new subscription
subscription_renewal Recurring invoice for next billing period
trial_conversion Invoice generated when trial converts to paid
subscription_upgrade Prorated invoice for plan upgrade
subscription_downgrade_credit Credit issued for downgrade
usage_based Usage charges for metered products
one_time Non-recurring charge
manual Admin-created invoice
correction Accounting correction
cancellation_fee Fee after contract cancellation, if applicable

8. Invoice Creation Policy

8.1 Trial Conversion Invoice

trialing subscription
  ↓
generate trial_conversion invoice
  ↓
attempt payment

Rules:

  • Generate invoice at trial end.
  • Include subscription plan line item.
  • Include tax if applicable.
  • Apply credits if available.
  • Apply discounts if valid.
  • Attempt payment immediately if payment method exists.
  • If payment succeeds, mark invoice paid and subscription active.
  • If payment fails, mark invoice open or payment_pending and subscription payment_pending.

8.2 Renewal Invoice

active subscription
  ↓
generate renewal invoice
  ↓
finalize invoice
  ↓
attempt payment
Billing Model Invoice Timing
Credit card / auto-pay Generate and charge at renewal time
ACH / bank debit Generate 3-5 days before due date
Net terms Generate at period start, due later
Enterprise contract Generate according to contract schedule

Default SaaS rule:

Generate renewal invoice at current_period_end.
Charge immediately.

Default B2B enterprise rule:

Generate invoice at period start.
Due date = invoice_date + net_terms_days.

8.3 Upgrade Invoice

active subscription
  ↓
calculate prorated charge
  ↓
generate upgrade invoice
  ↓
attempt payment

Recommended policy:

  • Upgrade takes effect immediately.
  • Charge prorated amount immediately.
  • If payment succeeds, apply upgraded entitlements.
  • If payment fails, keep existing plan active.
  • Do not remove already-paid access because an upgrade payment failed.

8.4 Downgrade Invoice or Credit

Recommended policy:

Downgrade takes effect at next billing cycle.
No immediate refund by default.

Alternative policy:

Immediate downgrade creates account credit.

Preferred default:

Action Policy
Downgrade Effective next billing period
Refund No automatic refund
Credit Optional, admin-controlled
Entitlement reduction At period end

8.5 Manual Invoice

Admins may create manual invoices for:

  • Custom services
  • Enterprise onboarding
  • Extra seats
  • Support packages
  • Contracted fees
  • Usage corrections
  • Migration adjustments

Manual invoices require:

admin_id
reason
line_items
approval if over threshold
audit event

9. Invoice Line Items

Every invoice must be composed of line items.

subscription_fee
seat_fee
usage_fee
setup_fee
discount
tax
credit
proration
refund_adjustment
manual_adjustment
CREATE TABLE invoice_line_items (
  id UUID PRIMARY KEY,

  invoice_id UUID NOT NULL,
  subscription_id UUID,
  plan_id UUID,

  type TEXT NOT NULL,
  description TEXT NOT NULL,

  quantity NUMERIC NOT NULL DEFAULT 1,
  unit_amount INTEGER NOT NULL,
  amount INTEGER NOT NULL,

  currency TEXT NOT NULL,

  period_start TIMESTAMP,
  period_end TIMESTAMP,

  metadata JSONB,

  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Rules:

  • Invoice totals must be derived from line items.
  • Never manually mutate invoice total without a corresponding line item.
  • Negative line items are allowed for discounts, credits, and adjustments.
  • Tax should be represented as a separate line item or tax record.
  • Historical line item descriptions should not change after invoice finalization.

10. Invoice Amount Calculation

subtotal = sum(charge line items)
discount_total = sum(discount line items)
credit_total = sum(credit line items)
tax_total = calculated tax
total = subtotal - discount_total - credit_total + tax_total
amount_due = total - amount_paid

Constraints:

amount_due cannot be less than 0
paid invoice cannot have amount_due > 0
void invoice cannot accept payments
draft invoice cannot accept payments

If credits exceed invoice total:

invoice amount_due = 0
remaining credit stays on billing account
invoice may be marked paid

11. Payment Lifecycle

Payments should be tracked separately from invoices.

requires_payment_method
requires_confirmation
requires_action
processing
succeeded
failed
canceled
refunded
partially_refunded

Payment flow:

invoice.open
  ↓
payment_intent.created
  ↓
payment.processing
  ↓
payment.succeeded
  ↓
invoice.paid

Failure flow:

payment.failed
  ↓
invoice.open
  ↓
retry scheduled
  ↓
subscription payment_pending / past_due

12. Payment Methods

Supported payment methods:

card
ach_debit
bank_transfer
wire_transfer
manual_invoice
purchase_order
Customer Type Payment Method
Self-serve SaaS Card
Mid-market Card or ACH
Enterprise Invoice terms / ACH / wire
High-risk customer Card or upfront payment only

Rules:

  • Each billing account may have one default payment method.
  • Payment methods must be tokenized through the provider.
  • Do not store raw card or bank details.
  • Expired cards should trigger notification before renewal.
  • Failed payment method should not be retried indefinitely.

13. Net Terms Policy

Supported terms:

due_on_receipt
net_7
net_15
net_30
net_45
net_60

Default:

Self-serve: due_on_receipt
B2B standard: net_15 or net_30
Enterprise: contract-specific

Rules:

  • Net terms require approval above a revenue threshold.
  • Net terms customers may remain active while invoice is open.
  • Once due date passes, invoice becomes past_due.
  • Subscription state should only degrade after the configured grace policy.

Example:

{
  "invoice_date": "2026-06-01T00:00:00Z",
  "net_terms_days": 30,
  "due_at": "2026-07-01T00:00:00Z"
}

14. Dunning and Payment Recovery

Dunning is triggered by unpaid invoices.

Day Invoice Status Subscription Status Action
0 open active or payment_pending Notify billing owner
3 open payment_pending Retry payment
7 past_due past_due Limit access
14 past_due suspended Suspend account
30 uncollectible or void canceled Cancel subscription

Rules:

  • Dunning is invoice-driven.
  • Subscription status reacts to unpaid invoice state.
  • A customer may have multiple unpaid invoices.
  • The oldest unpaid invoice should control escalation.
  • Payment of all blocking invoices should restore subscription.
  • Admins may pause dunning for enterprise customers.

15. Credits and Credit Balance

Credits should reduce future invoice amounts.

Credit sources:

downgrade credit
service credit
SLA credit
manual goodwill credit
overpayment
refund converted to credit
CREATE TABLE credit_balances (
  id UUID PRIMARY KEY,

  billing_account_id UUID NOT NULL,
  currency TEXT NOT NULL,

  balance_amount INTEGER NOT NULL DEFAULT 0,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE credit_ledger_entries (
  id UUID PRIMARY KEY,

  billing_account_id UUID NOT NULL,
  invoice_id UUID,

  type TEXT NOT NULL,
  amount INTEGER NOT NULL,
  currency TEXT NOT NULL,

  reason TEXT NOT NULL,
  created_by TEXT,

  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Credit rules:

  • Credits must be ledgered.
  • Credit balance cannot change without a ledger entry.
  • Credits should be currency-specific.
  • Credits apply before payment collection.
  • Credits should not silently expire unless terms clearly say so.
  • Enterprise credits may require approval.

16. Discounts and Coupons

Discount types:

percentage
fixed_amount
trial_extension
contractual
promotional
manual

Rules:

  • Discounts must have start and end dates.
  • Discounts must define scope: invoice, subscription, plan, or account.
  • Discounts should not apply to taxes unless legally permitted.
  • Expired discounts must not apply to new invoices.
  • Manual discounts require admin reason.

Example:

{
  "discount_type": "percentage",
  "percent_off": 20,
  "applies_to": "subscription",
  "starts_at": "2026-06-01T00:00:00Z",
  "ends_at": "2026-12-01T00:00:00Z"
}

17. Tax Policy

Tax calculation should happen at invoice finalization.

Requirements:

  • Use billing address for tax jurisdiction.
  • Use tax exemption status if present.
  • Store tax calculation result.
  • Store tax rate and jurisdiction.
  • Do not recalculate finalized invoice taxes unless issuing correction.
  • Support reverse charge or VAT if applicable.
CREATE TABLE tax_records (
  id UUID PRIMARY KEY,

  invoice_id UUID NOT NULL,

  jurisdiction TEXT,
  tax_rate NUMERIC,
  tax_amount INTEGER NOT NULL,
  tax_type TEXT,

  tax_exempt BOOLEAN DEFAULT FALSE,
  exemption_reason TEXT,

  provider_tax_id TEXT,
  metadata JSONB,

  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Recommended: integrate tax calculation through a provider if selling across jurisdictions. Tax logic is not the place to be brave.


18. Refund Policy

Refunds reverse payments, not invoices.

Refund types:

full
partial
goodwill
duplicate_payment
service_issue
fraud
chargeback

Rules:

  • Refunds require a paid invoice.
  • Refunds must reference the original payment.
  • Refunds must create a refund event.
  • Full refund may require subscription cancellation or entitlement review.
  • Partial refund may leave subscription active.
  • Refund does not delete the invoice.
  • Refund does not erase revenue history.
CREATE TABLE refunds (
  id UUID PRIMARY KEY,

  invoice_id UUID NOT NULL,
  payment_attempt_id UUID NOT NULL,
  billing_account_id UUID NOT NULL,

  amount INTEGER NOT NULL,
  currency TEXT NOT NULL,

  reason TEXT NOT NULL,
  status TEXT NOT NULL,

  provider_refund_id TEXT,
  created_by TEXT,

  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Refund Event Invoice Impact Subscription Impact
Partial refund partially_refunded Usually no change
Full refund current period refunded Review access
Fraud refund refunded Suspend or cancel
Duplicate payment refund Keep paid No change
SLA credit as refund partially_refunded No change

19. Credit Notes

Credit notes reduce the amount owed on an invoice.

Use credit notes when:

  • Invoice was wrong
  • Customer received a contractual credit
  • Customer downgraded and receives credit
  • Tax correction is needed
  • Admin adjusts invoice before collection

Do not use refunds when money was never collected.

CREATE TABLE credit_notes (
  id UUID PRIMARY KEY,

  invoice_id UUID NOT NULL,
  billing_account_id UUID NOT NULL,

  amount INTEGER NOT NULL,
  currency TEXT NOT NULL,

  reason TEXT NOT NULL,
  status TEXT NOT NULL,

  created_by TEXT,

  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

20. Chargeback Policy

Chargebacks are high-risk and should override normal happy-path billing.

chargeback.created
  ↓
invoice disputed
  ↓
subscription suspended
  ↓
admin/risk review

Rules:

  • Chargeback should immediately flag billing account.
  • Current subscription should become suspended unless enterprise exception applies.
  • Disable automatic reactivation until resolved.
  • Require admin review to restore.
  • Track dispute outcome.
Outcome Action
Won Restore invoice/payment state
Lost Keep invoice unpaid or refunded
Withdrawn Restore access after review
Under review Keep account restricted

21. Reconciliation Policy

The billing system must reconcile local records with the payment provider.

Daily reconciliation should compare:

  • Provider customer records
  • Provider subscriptions
  • Provider invoices
  • Provider payments
  • Provider refunds
  • Provider disputes
Mismatch Action
Provider invoice paid, local invoice open Mark local invoice paid
Provider payment failed, local payment processing Mark failed
Provider subscription canceled, local active Flag for review
Local invoice exists, provider missing Flag critical
Provider refund exists, local missing Import refund

Rules:

  • Do not blindly overwrite local admin overrides.
  • Create reconciliation events.
  • Alert on high-risk mismatches.
  • Store provider snapshot for audit.

22. Billing Events

Every financial action must create an immutable event.

billing_account.created
billing_account.updated

invoice.created
invoice.finalized
invoice.sent
invoice.payment_started
invoice.payment_failed
invoice.payment_succeeded
invoice.partially_paid
invoice.paid
invoice.past_due
invoice.voided
invoice.marked_uncollectible

payment_intent.created
payment_attempt.created
payment_attempt.succeeded
payment_attempt.failed
payment_method.updated

credit.created
credit.applied
credit.expired
credit.reversed

discount.applied
discount.expired

tax.calculated
tax.exempt_applied

refund.created
refund.succeeded
refund.failed

chargeback.created
chargeback.won
chargeback.lost

billing.reconciled
billing.reconciliation_failed
admin.billing_override_created

23. Admin Billing Console

Admins need operational tools, but every button should leave fingerprints.

Capabilities:

  • View billing account
  • View invoices
  • View invoice line items
  • View payments
  • View payment attempts
  • View credit balance
  • View credit ledger
  • View refunds
  • View chargebacks
  • Retry payment
  • Send invoice
  • Void invoice
  • Mark invoice uncollectible
  • Issue credit note
  • Issue refund
  • Apply discount
  • Update billing email
  • Update tax ID
  • Update billing address
  • Change net terms
  • Pause dunning
  • Resume dunning

Audit fields:

{
  "admin_id": "admin_123",
  "action": "void_invoice",
  "invoice_id": "inv_123",
  "reason": "Duplicate invoice generated during migration",
  "previous_status": "open",
  "new_status": "void",
  "created_at": "2026-06-15T00:00:00Z"
}

Require approval for:

  • Refunds above threshold
  • Manual credits above threshold
  • Changing enterprise net terms
  • Marking invoice uncollectible
  • Voiding paid invoices
  • Removing tax
  • Applying large discounts

24. Customer Billing Portal

Customers should be able to:

  • View current plan
  • View billing account details
  • View invoices
  • Download invoices as PDF
  • Update payment method
  • Pay open invoices
  • View payment history
  • View credit balance
  • Update billing email
  • Update tax ID
  • Update billing address
  • Cancel subscription if permitted
  • Request plan change

Do not expose internal statuses like:

uncollectible
dunning_paused
provider_mismatch

Map them to customer-friendly labels.


25. Customer-Facing Invoice Labels

Internal Status Customer Label
draft Preparing
open Due
payment_pending Payment processing
paid Paid
partially_paid Partially paid
past_due Past due
void Canceled
uncollectible Contact support
refunded Refunded
partially_refunded Partially refunded

26. Billing Notifications

Event Recipient Notification
Invoice finalized Billing owner Invoice available
Invoice due soon Billing owner Upcoming due date
Payment succeeded Billing owner Receipt
Payment failed Billing owner + admins Payment failed
Invoice past due Billing owner + admins Payment overdue
Account suspended Billing owner + admins Access restricted
Invoice paid after failure Billing owner + admins Payment recovered
Refund issued Billing owner Refund confirmation
Credit applied Billing owner Credit applied

Rules:

  • Every notification must include invoice number.
  • Payment failure notifications must include update-payment link.
  • Past due notifications must include deadline.
  • Enterprise invoices should include PO number if available.
  • Receipts should include amount paid and payment method summary.

27. Invoice Numbering

Invoice numbers must be sequential and immutable.

Recommended format:

INV-2026-000001

Rules:

  • Invoice number assigned at finalization.
  • Draft invoices may not need invoice numbers.
  • Invoice numbers must never be reused.
  • Voided invoices keep their invoice numbers.
  • Region-specific sequencing may be needed for tax compliance.

Fields:

invoice_number TEXT UNIQUE
invoice_sequence INTEGER UNIQUE

Do not generate invoice numbers using random UUIDs. Accounting teams will hate you, and this time they will be right.


28. Data Model Summary

Invoices Table

CREATE TABLE invoices (
  id UUID PRIMARY KEY,

  billing_account_id UUID NOT NULL,
  subscription_id UUID,
  workspace_id UUID NOT NULL,

  invoice_number TEXT UNIQUE,
  invoice_type TEXT NOT NULL,
  status TEXT NOT NULL,

  currency TEXT NOT NULL,

  subtotal_amount INTEGER NOT NULL DEFAULT 0,
  discount_amount INTEGER NOT NULL DEFAULT 0,
  credit_amount INTEGER NOT NULL DEFAULT 0,
  tax_amount INTEGER NOT NULL DEFAULT 0,
  total_amount INTEGER NOT NULL DEFAULT 0,
  amount_paid INTEGER NOT NULL DEFAULT 0,
  amount_due INTEGER NOT NULL DEFAULT 0,

  invoice_date TIMESTAMP,
  due_at TIMESTAMP,
  finalized_at TIMESTAMP,
  paid_at TIMESTAMP,
  voided_at TIMESTAMP,
  marked_uncollectible_at TIMESTAMP,

  billing_name TEXT,
  billing_email TEXT,
  billing_address JSONB,

  provider_invoice_id TEXT,

  metadata JSONB,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Payment Attempts Table

CREATE TABLE payment_attempts (
  id UUID PRIMARY KEY,

  invoice_id UUID NOT NULL,
  billing_account_id UUID NOT NULL,

  provider_payment_id TEXT,
  payment_method_id UUID,

  status TEXT NOT NULL,
  amount INTEGER NOT NULL,
  currency TEXT NOT NULL,

  failure_code TEXT,
  failure_message TEXT,

  attempted_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Billing Events Table

CREATE TABLE billing_events (
  id UUID PRIMARY KEY,

  billing_account_id UUID,
  invoice_id UUID,
  subscription_id UUID,
  workspace_id UUID,

  event_type TEXT NOT NULL,
  source TEXT NOT NULL,

  payload JSONB NOT NULL,

  occurred_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

29. API Requirements

Create Invoice

POST /billing/invoices
{
  "billing_account_id": "ba_123",
  "invoice_type": "manual",
  "line_items": [
    {
      "type": "setup_fee",
      "description": "Enterprise onboarding",
      "quantity": 1,
      "unit_amount": 500000
    }
  ]
}

Finalize Invoice

POST /billing/invoices/{invoice_id}/finalize

Behavior:

  • Assign invoice number.
  • Calculate totals.
  • Calculate tax.
  • Apply credits.
  • Set status to open.
  • Send invoice if configured.

Pay Invoice

POST /billing/invoices/{invoice_id}/pay
{
  "payment_method_id": "pm_123"
}

Retry Payment

POST /billing/invoices/{invoice_id}/retry-payment

Void Invoice

POST /billing/invoices/{invoice_id}/void
{
  "reason": "Duplicate invoice"
}

Issue Credit Note

POST /billing/invoices/{invoice_id}/credit-notes
{
  "amount": 10000,
  "reason": "Service credit"
}

Issue Refund

POST /billing/invoices/{invoice_id}/refunds
{
  "amount": 10000,
  "reason": "Customer requested partial refund"
}

30. Scheduled Jobs

Job Frequency Purpose
Invoice generation job Hourly/Daily Generate renewal invoices
Invoice finalization job Hourly Finalize pending invoices
Payment collection job Hourly Charge open invoices
Payment retry job Hourly Retry failed payments
Invoice due reminder job Daily Notify customers before due date
Past due job Hourly Mark overdue invoices as past due
Dunning escalation job Daily Escalate unpaid invoices
Credit application job On invoice finalization Apply available credits
Reconciliation job Daily Match provider and local state
Tax sync job Daily/On demand Validate tax records
Invoice PDF generation job On finalization Generate downloadable invoices

31. Subscription Integration Rules

Billing should drive subscription changes only through defined events.

Billing Event Subscription Reaction
invoice.paid for trial conversion trialing → active
invoice.payment_failed for renewal active → payment_pending
invoice.past_due payment_pending → past_due
invoice.marked_uncollectible suspended → canceled or admin review
refund.succeeded full current period Entitlement review
chargeback.created active → suspended

Important: not every invoice should affect subscription status.

A manual invoice for onboarding should not cancel the subscription if unpaid unless policy says it is blocking.

Add this field:

is_subscription_blocking

Example:

{
  "invoice_type": "manual",
  "is_subscription_blocking": false
}

32. Blocking vs Non-Blocking Invoices

Blocking invoices can affect subscription access:

subscription_initial
subscription_renewal
trial_conversion
subscription_upgrade

Non-blocking invoices should not automatically affect access:

manual
setup_fee
professional_services
correction
one_time
Invoice Type Blocks Subscription?
subscription_initial Yes
trial_conversion Yes
subscription_renewal Yes
subscription_upgrade Usually no
manual Configurable
one_time No by default
usage_based Configurable
setup_fee No by default
cancellation_fee No, subscription already ending

33. Accounting Rules

Immutability

Once finalized:

  • Invoice number cannot change.
  • Invoice date cannot change.
  • Line items cannot be edited directly.
  • Totals cannot be edited directly.
  • Billing address snapshot cannot be edited directly.

Corrections require:

credit note
adjustment invoice
refund
void if unpaid

Revenue Integrity

  • Paid invoices remain in history.
  • Refunded invoices remain in history.
  • Voided invoices remain in history.
  • Deleted invoices should not exist in production.
  • Admin changes must be audited.

34. Testing Plan

Unit Tests

Test:

  • Invoice total calculation
  • Tax calculation hooks
  • Credit application
  • Discount application
  • Invoice state transitions
  • Payment state transitions
  • Refund rules
  • Credit note rules
  • Net terms due date logic
  • Blocking invoice logic

Integration Tests

Test:

  • Create invoice
  • Finalize invoice
  • Pay invoice
  • Failed payment
  • Retry payment
  • Apply credit
  • Issue refund
  • Void invoice
  • Reconcile provider payment
  • Handle duplicate webhook
  • Handle out-of-order webhook

End-to-End Tests

Test:

Trial ends → invoice created → payment succeeds → subscription active
Trial ends → invoice created → payment fails → subscription payment_pending
Renewal invoice fails → dunning starts → subscription past_due
Past due invoice paid → subscription restored
Enterprise invoice created with net_30 → due date passes → past_due
Upgrade invoice fails → existing subscription remains active
Full refund current period → entitlement review triggered
Chargeback created → subscription suspended

35. Monitoring and Alerts

Track:

invoice_created_count
invoice_finalized_count
invoice_paid_count
invoice_failed_count
invoice_past_due_count
invoice_voided_count
invoice_uncollectible_count
payment_attempt_count
payment_success_rate
payment_failure_rate
refund_count
credit_note_count
reconciliation_mismatch_count
average_days_to_payment
accounts_receivable_total
past_due_amount_total

Alert on:

Payment failure spike
Invoices stuck in payment_pending
Invoices overdue beyond policy
Provider/local invoice mismatch
Provider/local payment mismatch
Refund spike
Credit abuse
Chargeback created
Invoice finalization failure
Tax calculation failure

36. Rollout Plan

Phase 1: Invoice Foundation

Deliver:

  • Billing account model
  • Invoice model
  • Invoice line items
  • Invoice statuses
  • Invoice total calculation
  • Basic invoice admin view

Acceptance criteria:

  • Admin can create draft invoice.
  • Admin can finalize invoice.
  • Finalized invoice gets immutable number.
  • Invoice totals are derived from line items.

Phase 2: Payment Collection

Deliver:

  • Payment method support
  • Payment intent model
  • Payment attempt model
  • Payment success handling
  • Payment failure handling

Acceptance criteria:

  • Open invoice can be paid.
  • Failed payment creates payment attempt.
  • Successful payment marks invoice paid.
  • Payment event is auditable.

Phase 3: Subscription Billing Integration

Deliver:

  • Trial conversion invoices
  • Renewal invoices
  • Initial subscription invoices
  • Blocking invoice logic
  • Subscription reaction events

Acceptance criteria:

  • Trial conversion payment activates subscription.
  • Renewal failure moves subscription to payment_pending.
  • Invoice payment restores subscription when applicable.
  • Non-blocking invoices do not affect subscription.

Phase 4: Dunning and Net Terms

Deliver:

  • Due dates
  • Net terms
  • Past due logic
  • Payment retries
  • Dunning notifications
  • Subscription escalation rules

Acceptance criteria:

  • Net terms invoices become past due after due date.
  • Failed payments retry on schedule.
  • Blocking unpaid invoices escalate subscription status.
  • Admin can pause dunning.

Phase 5: Credits, Refunds, Adjustments

Deliver:

  • Credit balance ledger
  • Credit note support
  • Refund support
  • Discount support
  • Adjustment invoice support

Acceptance criteria:

  • Credits apply to future invoices.
  • Credit balance is ledgered.
  • Refunds reference original payments.
  • Finalized invoices are corrected through credit notes or adjustments.

Phase 6: Tax and Compliance

Deliver:

  • Tax calculation integration
  • Tax records
  • Tax exemption handling
  • Invoice PDF generation
  • Invoice address snapshots

Acceptance criteria:

  • Tax calculated at finalization.
  • Tax result is stored.
  • Finalized invoice preserves billing details.
  • Customer can download invoice PDF.

Phase 7: Reconciliation and Hardening

Deliver:

  • Provider reconciliation
  • Webhook replay
  • Dead-letter queue
  • Mismatch alerts
  • Admin correction workflows

Acceptance criteria:

  • Provider and local states stay aligned.
  • Failed webhooks are replayable.
  • Mismatches create alerts.
  • Reconciliation does not overwrite valid admin decisions.

37. Final Default Billing Policy

Use this as the baseline B2B billing policy:

Invoices are generated from subscriptions, usage, or admin action.
Invoices start as draft and become payable only after finalization.
Invoice numbers are assigned only at finalization.
Finalized invoices are immutable.
Subscription invoices are blocking by default.
Manual invoices are non-blocking by default.
Credits are applied before payment collection.
Tax is calculated during finalization.
Payment failures create payment attempts and dunning events.
Payment retries follow configured schedule.
Open invoices become past_due after due date.
Blocking past_due invoices affect subscription status.
Refunds reverse payments, not invoices.
Credit notes reduce invoice balances before or after finalization depending on accounting rules.
All billing changes are event-driven and audited.
Daily reconciliation compares local billing state with payment provider state.

38. Definition of Done

The billing and invoice system is complete when:

  • Billing accounts exist and own invoices.
  • Invoices have a clear lifecycle.
  • Invoice totals are line-item driven.
  • Finalized invoices are immutable.
  • Invoice numbers are sequential and permanent.
  • Payment attempts are tracked.
  • Failed payments trigger dunning.
  • Paid invoices update subscription status when appropriate.
  • Non-blocking invoices do not affect access.
  • Credits and refunds are ledgered.
  • Admin billing actions are audited.
  • Customers can view and pay invoices.
  • Provider reconciliation is operational.
  • Tests cover invoice, payment, refund, and subscription integration flows.