Concepts

Entitlements

The account → app → user → entitlement hierarchy

stubkit has four concepts. An account is a customer of stubkit. An app is a mobile or web product that belongs to an account. A user is an end user of that app, identified by a stable external ID the customer controls. An entitlement is a named feature flag gated on subscription state — typically pro.

Why the extra layer

Keeping entitlements distinct from products means you can ship two different product IDs (monthly vs yearly) and have both resolve to the same pro entitlement. Your app only ever checks isActive(userId, 'pro') — it does not care which product was purchased.

Entitlement status values

StatusMeaningGrants access?
activeCurrent billing period is paid and unexpired.yes
graceBilling retry in progress. Typically lasts up to 16 days on iOS, 30 on Android.yes
cancelledUser turned off auto-renew but the current period still has time left.yes (until expires_at)
expiredNatural end of billing, no retry. Hard loss of access.no
refundedApple, Google, or Stripe refunded the transaction.no

How stubkit decides

Every webhook from Apple, Google, and Stripe — plus every admin grant — flows through an isolated, serialized state engine keyed on (app, user). Concurrent updates for the same user are applied one at a time, and the canonical result is persisted before any API read returns. See state machine for the transition rules.