A customer’s ability to use a feature is a product decision derived from billing and account policy, not a direct copy of the last invoice row. Model a product, plan, feature, quantity or limit, effective period, tenant, and status. Keep the source billing event and the resulting entitlement separate. This lets the product explain why access exists and handle a delayed, corrected, or disputed billing event without corrupting the account model.
Map billing events to durable states
List the events that can change access: subscription creation, upgrade, downgrade, renewal, payment failure, cancellation, refund, trial expiry, and manual adjustment. Define the state transition and effective time for each. Do not let a webhook handler invent business policy from event names. Store the event ID, payload reference, processing status, and resulting entitlement version so retries and reordered delivery can be reconciled.
Use a grace policy deliberately
Payment failure does not always mean immediate suspension, and a cancellation may take effect at period end. Make grace periods explicit per product and customer policy, then expose the current state to both support and the product. During grace, restrict only the capability that policy names or preserve access while a retry is pending. Avoid a silent mismatch in which the billing dashboard says one thing while the application grants another.
Keep access checks deterministic
The application should ask a stable entitlement service or local projection whether a tenant may perform an action. It should not parse raw billing payloads in every feature. Return the decision, feature, scope, quantity, expiry, and policy version needed for debugging. Cache carefully with tenant and entitlement version in the key. For high-risk actions, re-check current state rather than trusting a long-lived client token.
Handle upgrades and downgrades without races
Two billing events can arrive close together or be retried after a later event has already been processed. Use provider event ordering when available, otherwise compare effective timestamps and maintain a reconciliation rule. Make projection updates idempotent. When a plan change affects limits, decide what happens to existing usage before reducing access. A customer should not lose data simply because a downgrade and a usage job crossed paths.
Give support a safe correction path
Support needs to inspect the billing source, entitlement projection, recent events, and current product access without editing raw records casually. Provide a documented adjustment workflow with reason, approver, expiry, and link to the source issue. Manual grants should be visible to customers where appropriate and must not disappear during the next automated sync. Correction is part of the model, not a hidden database patch.
Reconcile continuously and test recovery
Run a reconciliation job that compares source billing state with the entitlement projection and reports missing, extra, stale, or conflicting grants. Test duplicate events, out-of-order delivery, webhook outage, provider correction, trial expiry, clock boundaries, and partial application failure. Monitor time to converge, entitlement drift, support adjustments, and denied actions after a valid purchase. The objective is predictable access with an evidence trail from money state to product state.
Define the reconciliation contract
Reconciliation needs a clear answer to which system wins when billing and product state disagree. Compare subscription status, plan version, quantity, effective dates, manual adjustments, and product projection at the same point in time. Classify drift as delayed event, missing event, invalid mapping, stale projection, unauthorized manual grant, or genuine source correction. Automatically repair only the classes that are safe and idempotent; route ambiguous cases to support with the evidence attached. Avoid granting access merely because a customer’s payment provider says a subscription exists if the tenant or product mapping is missing. Conversely, avoid revoking a valid capability because one webhook was delayed. Include entitlement state in customer-facing support views and expose the next scheduled change, such as a period-end downgrade. Test the reconciliation job against a copy of production-shaped data before changing its authority. A mature entitlement workflow converges predictably, explains every exception, and makes manual corrections temporary, visible, and compatible with the next source event.
Separate product policy from provider quirks
Keep provider-specific statuses in the billing adapter and translate them into product states at one boundary. Product teams should reason about trial, active, grace, scheduled cancellation, suspended, and restored states rather than dozens of vendor event names. This makes provider migrations and pricing changes safer because the application contract remains stable while the adapter evolves.



