DocHub
One-time consumable course IAP — product IDs, deferred acknowledgment, platform-specific receipt handling

Course Purchase (One-Time)

Key Points

  • Courses are consumable products (can be repurchased for different voices)
  • Cross-platform: Android (Google Play) and iOS (App Store)
  • Deferred acknowledgment: purchase NOT acknowledged until server validates
  • Google/Apple auto-refunds unacknowledged purchases after 3 days

Product ID Format

Platform Format Example
Android Lowercase course code h01enb
iOS Bundle prefix + lowercase me.hypnoelp.app.h01enb

Purchase Flow

  1. Initialize — start InAppPurchaseService, call restorePurchases(), normalize product ID
  2. Query & buy — query product details from store, call buyConsumable()
  3. Wait — listen to purchase stream (20 minute timeout), detect duplicates via user_profile.json
  4. Extract platform data — get verification token/receipt
  5. Validate — send to /functions/v1/validate_purchase
  6. Server validates — Google Play API or Apple verifyReceipt API
  7. Acknowledge — ONLY after server confirms, call completePurchase()
  8. Update — add to user profile, trigger sync to download content

Platform-Specific Data Extraction

Field Android iOS
Verification data purchase_token from serverVerificationData receipt_data from method channel
Receipt source Google Play Billing Bundle.main.appStoreReceiptURL
Method channel N/A app_receipt -> getAppReceipt

Validation Payload — Android

{
  "product_id": "h01enb",
  "purchase_id": "GPA.1234-5678-9012",
  "transaction_date": "1703347200000",
  "status": "PurchaseStatus.purchased",
  "platform": "android",
  "purchase_token": "token-from-google-play",
  "course_code": "H01ENB",
  "voice": "Female"
}

Validation Payload — iOS

{
  "product_id": "me.hypnoelp.app.h01enb",
  "purchase_id": "1000000123456789",
  "transaction_date": "1703347200000",
  "status": "PurchaseStatus.purchased",
  "platform": "ios",
  "receipt_data": "base64-encoded-app-receipt...",
  "course_code": "H01ENB",
  "voice": "Female"
}

Server Response

{
  "status": "success",
  "message": "Course purchase validated",
  "acknowledged": true,
  "course": {
    "course_code": "H01ENB",
    "title": "Confidence Building",
    "voice": "Female",
    "purchased_at": "2025-12-23T12:00:00Z"
  }
}

Critical: Deferred Acknowledgment

If server validation fails, DO NOT call completePurchase(). Google/Apple will auto-refund the user after 3 days. This protects against invalid or fraudulent purchases.