Files
chat_web_app/llm-fe/MONETIZATION.md
T
westfarn c938995380
Unit Tests / test (pull_request) Successful in 13s
Buy on StoreKit and Play Billing, then confirm with the backend (#78).
Native purchases replace RevenueCat. The app sends the signed transaction or Play token to /monetization/store/confirm/ so access is granted only after the store check.
2026-10-19 06:14:29 -05:00

24 lines
1.5 KiB
Markdown

# Monetization (web Stripe + native store billing)
## Channels
| Runtime | Checkout / manage | Ledger |
|---------|-------------------|--------|
| Web (`!isNativePlatform`) | Stripe Checkout + Customer Portal via `/monetization/...` | Stripe webhooks |
| Native Capacitor | StoreKit (iOS) and Play Billing (Android) | `POST /monetization/store/confirm/` verifies the store transaction and writes the same invoice/payment tables |
There is no App Store, Play, or RevenueCat webhook. After the store sheet succeeds, the app sends the signed StoreKit transaction or the Play purchase token. The backend checks it before granting access. Renewals and restores send the current store entitlement again. Access ends when the verified period end passes.
FE displays whatever `/monetization/invoices/` (and subscription) returns after refresh. Provider badge uses `provider` (`app_store`, `play_store`, or legacy `revenuecat`) plus `revenuecat_store`.
## Store account token
`GET /monetization/subscription/` returns `store_account_token`. The native purchase passes that value as StoreKit `appAccountToken` and Play Billing `obfuscatedAccountId`. The backend rejects a token that belongs to a different user, and rejects a transaction already linked to another account.
Plan rows expose `store_product_id` (the store product identifier). Configure it on `SubscriptionPlan.revenuecat_product_id`, or set `REVENUECAT_PRODUCT_PLAN_MAP` so a product id maps to a plan slug.
## Related
- Backend issue #78
- [`ANDROID.md`](ANDROID.md) / [`IOS.md`](IOS.md) for store builds