One-time consumable course IAP — product IDs, deferred acknowledgment, platform-specific receipt handling
- 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
| Platform |
Format |
Example |
| Android |
Lowercase course code |
h01enb |
| iOS |
Bundle prefix + lowercase |
me.hypnoelp.app.h01enb |
- Initialize — start InAppPurchaseService, call
restorePurchases(), normalize product ID
- Query & buy — query product details from store, call
buyConsumable()
- Wait — listen to purchase stream (20 minute timeout), detect duplicates via
user_profile.json
- Extract platform data — get verification token/receipt
- Validate — send to
/functions/v1/validate_purchase
- Server validates — Google Play API or Apple verifyReceipt API
- Acknowledge — ONLY after server confirms, call
completePurchase()
- Update — add to user profile, trigger sync to download content
| 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 |
{
"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"
}
{
"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"
}
{
"status": "success",
"message": "Course purchase validated",
"acknowledged": true,
"course": {
"course_code": "H01ENB",
"title": "Confidence Building",
"voice": "Female",
"purchased_at": "2025-12-23T12:00:00Z"
}
}
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.