Billing And Entitlements
Stripe is the payment rail, but entitlements are the access-control language SPAPS exposes to apps. That separation lets a subscription, checkout, manual grant, wallet payment, or policy rule all project into a feature decision without forcing downstream services to understand every billing event.
Mental Model
Primary Domains
| Domain | Owns |
|---|---|
stripe | Products, checkout sessions, guest checkout, subscriptions, billing portal, payment history, webhook processing |
entitlements | Entitlement grants, mappings, policy-facing access checks |
applications | Per-app keys and settings that determine which client is asking |
policies | Higher-level policy evaluation for access decisions |
Example Access Check Shape
from spaps_server_quickstart.sdk import FeatureContext, FeatureDefinition, FeatureEvaluator
definition = FeatureDefinition(
kill_switch_key="feature.disabled",
minimum_role="user",
)
context = FeatureContext(
user_id="user_123",
user_roles={"user"},
is_super_admin=False,
)
# evaluator.is_enabled(...) depends on a ServerEntitlementsClient plus RoleHierarchy.Operational Pitfalls
Do not let a downstream app infer paid access directly from Stripe. SPAPS should project payment state into entitlements so every app consumes the same access contract.
- Missing Stripe webhook secret makes signature verification impossible.
- Price-to-entitlement mapping gaps create paid users without access grants.
- Local tests should mock Stripe with deterministic responses instead of touching the network.