subs_account billing profile flags ACCOUNT
subs_customer stripe_customer_id checkout data CUSTOMER
stripe.Customer payment methods metadata PAYMENT IDENTITY
Monthly Subscription items prices STRIPE
Yearly Subscription items prices STRIPE
subs_object_products_element value_phases license_source_id DOMAIN MODEL
1:many maps to owns owns license_source_id license_source_id

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.

ObjectOwnsKey Detail
subs_accountBilling profile, flags bitmask, account typeBit 15 of flags = bad_debt. Account type stored here as fallback.
subs_customerStripe↔CF account mapping, checkout dataMulti-writer: accounts_svc (setup) + subscriptions_api (checkout).
stripe.CustomerPayment 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).

Monthly Subscription

Covers Workers, R2, Stream, and usage-based products. Renews monthly. Triggers the dunning cycle on payment failure.

Yearly Subscription

Covers zone plans (Pro/Biz/Ent), SSL, and annual add-ons. Renews yearly. Delayed downgrades defer to period end.

Subscription Items & Prices

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.

KEY INSIGHT — State Is Not a Status Field

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.

SignalMeaningExample
deleted_dateNULL = 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_idBilling relationship — how the OPE is billed.sub_X:si_Y, ADMIN:reason, PENDING:PENDING
workflow_idIn-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.

accounts_svc profiles setup ACCOUNT DOMAIN
subscriptions_api dunning invoices checkout SUBS DOMAIN
billing_webhooks charges events PAYMENTS DOMAIN
Shared Stores subs_account subs_customer cf_prod MULTI-WRITER — drift zone
Billing Stores subs_dunning billing_prod SINGLE-WRITER
Stripe EXTERNAL
profiles, setup bad_debt, checkout dunning r/w, invoices charges events.in
StorePurposeWritersDrift Risk
subs_accountBilling profile, flags (bit 15 = bad_debt), account typeengine + facadeHigh — bad_debt flag is primary drift vector
subs_customerStripe↔CF account mapping, checkout dataengine + facadeMedium — shared writes
cf_prodEntitlements, product accessaccounts_svc + entitlements_apiMedium — multi-writer
subs_dunningRetry count, escalation level, dunning statusengine onlyLow — single writer
billing_prodInvoice and charge history — financial audit trailengine onlyLow — single writer
StripeSubscriptions, invoices, payment intents, customer metadataengine + pipeHigh — 5 metadata keys govern bad-debt state
FormatMeaningBilled?
sub_X:si_YStripe subscription item — live billing relationshipYes — via Stripe
ADMIN:reasonAdmin-provisioned overrideNo — unbilled
USER:reasonUser free trial or self-provisionedNo — unbilled
CONTRACT:CONTRACTEnterprise contract backfillVia contract (not Stripe)
PENDING:PENDINGAwaiting Stripe subscription creationNot yet — in-flight