Overview
Every Despia app needs a single, consistent user identifier (app_user_id) that persists across sessions and devices. This identifier connects all your services together.
Identity Resolution
On every app launch, resolve the user’s identity using this priority:| Priority | Source | Description |
|---|---|---|
| 1 | Storage Vault | Synced via iCloud/Google backup |
| 2 | Service Recovery | Recovers users via service-specific IDs (e.g., RevenueCat externalUserId) |
| 3 | Install ID | Fallback for new users (despia.uuid) |
Implementation
Important: The RevenueCat purchase history recovery (Step 2) is critical for apps with in-app purchases. It allows paying users to recover their identity on new devices. If you’re not using RevenueCat, comment out that block and the identity will fall through to the install ID.
Flow Diagram
Note: The getpurchasehistory:// step is RevenueCat-specific. If not using RevenueCat, the flow goes directly from “Vault not found” to “Use install_id”.
Paywall Readiness
Before launching a paywall, ensure both identity resolution and database sync are complete:User Login (Claim vs Recover)
When a user authenticates, the backend determines whether to claim the current identity or recover an existing one.Login Actions
| Action | Condition | Result |
|---|---|---|
| CLAIM | Account has no app_user_id | Link current app_user_id to account |
| RECOVER | Account already has app_user_id | Return existing app_user_id |
Client-Side Implementation
Backend API Endpoints
User Registration Endpoint
This endpoint receives identity syncs from the app on every launch:User Login Endpoint
Login Flow Diagram
Syncing to Services
After identity resolution, sync theapp_user_id to all integrated services.
Generic Sync Pattern
Restore Purchases (Required for App Store)
Provide a restore purchases button for users who need to recover their subscriptions on a new device. This is required by both Apple and Google.Where to Place the Restore Button
- Settings screen (most common)
- Paywall screen
- Account or profile screen
- Onboarding flow for returning users
Integration Examples
RevenueCat (In-App Purchases) — Deep Integration
RevenueCat is deeply integrated into Despia. Theapp_user_id is passed as external_id when launching paywalls.
Purchase Response Fields
Thegetpurchasehistory:// response includes:
| Field | Description |
|---|---|
transactionId | Unique identifier for this transaction |
originalTransactionId | Links to original purchase (for renewals) |
productId | Product ID from App Store Connect / Play Console |
type | "subscription" or "product" |
entitlementId | The entitlement this purchase grants |
isActive | Whether purchase currently grants access |
willRenew | Whether subscription will auto-renew |
purchaseDate | ISO timestamp of transaction |
expirationDate | When access expires (null for lifetime) |
externalUserId | The app_user_id linked to this purchase |
store | "app_store" or "play_store" |
Hybrid Payment Example (Native + Web)
OneSignal (Push Notifications)
Stripe (Web-Based Payments)
For web-based services like Stripe, sync via your backend:Generic Web SDK Pattern
For any web-based SDK, follow this pattern:Database Schema
Store theapp_user_id as the primary link across all tables:
Summary
| Component | Key | Purpose |
|---|---|---|
| Storage Vault | app_user_id | Persistent identity across sessions/reinstalls |
| Backend DB | app_user_id | Central user record |
| RevenueCat | external_id | Links purchases to user |
| OneSignal | external_user_id | Links push notifications to user |
| Stripe | metadata.app_user_id | Links payments to user |
| Any SDK | varies | Always map back to app_user_id |
app_user_id is the single source of truth. Every service integration should either accept it directly or map their internal IDs back to it via your backend.