SYSTEM OVERVIEW
The Data Model
Accounts, subscriptions, invoices, and the six stores that hold them. State is not a single field — it is an emergent property read from fragmented records across subs_account, subs_customer, subs_dunning, billing_prod, cf_prod, and Stripe.
A subs_account holds the billing profile for a Cloudflare account. Each account has a subs_customer row that maps it to a Stripe customer. The Stripe customer owns up to two subscriptions (monthly and yearly), each containing subscription items tied to prices. On the domain side, each billable product component is an OPE (subs_object_products_element) whose license_source_id references the Stripe subscription item that funds it. Invoices are generated by Stripe on renewal and mirrored into billing_prod. Payment methods live on the Stripe customer.
Customer identity is fragmented across three stores. subs_account holds the billing profile and flags. subs_customer maps Stripe customer IDs to Cloudflare accounts. stripe.Customer is the authoritative identity for payment. No unified model exists today.
| Object | Owns | Key Detail |
|---|---|---|
subs_account | Billing profile, flags bitmask, account type | Bit 15 of flags = bad_debt. Account type stored here as fallback. |
subs_customer | Stripe↔CF account mapping, checkout data | Multi-writer: accounts_svc (setup) + subscriptions_api (checkout). |
stripe.Customer | Payment identity, metadata (52 fields) | cf_account_type in metadata is authoritative when set. |
Each customer has up to two Stripe subscriptions — monthly and yearly. Subscription items carry prices. PayGo detection uses two signals: subscription_type=PAYGO in metadata (newer) or cf:sub:type=paygo (older).
Covers Workers, R2, Stream, and usage-based products. Renews monthly. Triggers the dunning cycle on payment failure.
Covers zone plans (Pro/Biz/Ent), SSL, and annual add-ons. Renews yearly. Delayed downgrades defer to period end.
Each subscription item references a price in the catalog. Items carry metadata: cf:sub_item:catalog_component, cf:sub_item:catalog_pkg, cf:sub_item:catalog_rp.
An OPE (Object Products Element) is a row in subs_object_products_element — an individual product component attached to a billable object (zone or account). Multiple OPEs compose a subscription. The parent table subs_object_products represents the billable object itself.
OPE state is emergent, not stored. It is computed from five signals read together: deleted_date, value_phases[0], value_phases[1], license_source_id, and workflow_id. No single column tells you what state a subscription is in.
| Signal | Meaning | Example |
|---|---|---|
deleted_date | NULL = active. Timestamp = soft-deleted or cancelled. | NULL → active; 2026-01-15 → cancelled |
value_phases[0] | Current value — what the customer has right now. | "pro", 5, metered config |
value_phases[1] | Scheduled change — what they will have at next period. | "free", -1, empty |
license_source_id | Billing relationship — how the OPE is billed. | sub_X:si_Y, ADMIN:reason, PENDING:PENDING |
workflow_id | In-flight Temporal workflow (e.g. 3DS auth). Empty = none. | wf_abc123 or empty |
Stripe invoices follow a five-state machine: draft → open → paid / void / uncollectible. State is inferred from timestamp fields (finalized_at, paid_at, voided_at, marked_uncollectible_at), not a status enum. Credit notes adjust finalized invoices. See Invoicing for the full state machine and finalization paths.
An SSLC (Scheduled Service Level Change) stores a pending downgrade: the target state (next_value_phase, next_price_id, next_license_source_id), an action_date, and a link to the OPE it modifies. A partial unique index enforces one active SSLC per OPE (WHERE deleted_date IS NULL). For how SSLCs are triggered and applied, see Subscription Lifecycle.
| Store | Purpose | Writers | Drift Risk |
|---|---|---|---|
subs_account | Billing profile, flags (bit 15 = bad_debt), account type | engine + facade | High — bad_debt flag is primary drift vector |
subs_customer | Stripe↔CF account mapping, checkout data | engine + facade | Medium — shared writes |
cf_prod | Entitlements, product access | accounts_svc + entitlements_api | Medium — multi-writer |
subs_dunning | Retry count, escalation level, dunning status | engine only | Low — single writer |
billing_prod | Invoice and charge history — financial audit trail | engine only | Low — single writer |
| Stripe | Subscriptions, invoices, payment intents, customer metadata | engine + pipe | High — 5 metadata keys govern bad-debt state |
| Format | Meaning | Billed? |
|---|---|---|
sub_X:si_Y | Stripe subscription item — live billing relationship | Yes — via Stripe |
ADMIN:reason | Admin-provisioned override | No — unbilled |
USER:reason | User free trial or self-provisioned | No — unbilled |
CONTRACT:CONTRACT | Enterprise contract backfill | Via contract (not Stripe) |
PENDING:PENDING | Awaiting Stripe subscription creation | Not yet — in-flight |
State is distributed across six stores with three writers. Understanding which store owns which truth — and where they disagree — is the foundation for understanding every other page in this section.