The Despia In-App Purchase SDK v2 enables secure in-app purchases across iOS, Android, and web platforms. This new version introduces enhanced security features, server-side webhooks, and native validation through Apple StoreKit and Google Billing Center.
Important: Make sure to publish a new version via TestFlight to test and use In-App Purchases successfully using our V2 SDK.
Key Features
-
Server-side webhooks for subscription status updates
-
Native validation through Apple/Google payment systems
-
Real-time transaction verification
-
Automatic receipt validation
-
Support for both consumable and non-consumable purchases
-
Cross-platform compatibility (iOS, Android, Web)
Prerequisites
Before implementing in-app purchases:
-
Published Despia mobile application
-
Apple Developer account or Google Play Developer account
-
Configured bank account in respective app stores
-
Completed tax forms and business information
-
Product IDs set up in App Store Connect/Google Play Console
Basic Implementation
1. Initialize Purchase
Single Product ID (iOS and Android)
If your product bundle ID is the same for both iOS and Android:
const product_id = "yourproductid"; // Your Product ID
const consumable = false; // Set true for consumable purchases
const baseUrl = 'inapppurchase://?package=' + product_id;
const finalDeeplink = navigator.userAgent === "despia-iphone" ||
navigator.userAgent === "despia-ipad"
? `${baseUrl}&successful_url=""`
: `${baseUrl}&successful_url=""&consumable=${consumable}`;
window.despia = finalDeeplink;
Different Product IDs (Platform-Specific)
If you need to use different product IDs for iOS and Android:
// Simple example for different product IDs on iOS and Android
let product_id = "yourdefaultproductid"; // Default product ID
// Check for iOS devices
if (navigator.userAgent.includes("despia-iphone") || navigator.userAgent.includes("despia-ipad")) {
product_id = "your.ios.productid"; // Use iOS product ID
}
// Check for Android devices
else if (navigator.userAgent.includes("despia-android")) {
product_id = "your.android.productid"; // Use Android product ID
}
const consumable = false; // Set true for consumable purchases
const baseUrl = 'inapppurchase://?package=' + product_id;
const finalDeeplink = navigator.userAgent === "despia-iphone" ||
navigator.userAgent === "despia-ipad"
? `${baseUrl}&successful_url=""`
: `${baseUrl}&successful_url=""&consumable=${consumable}`;
window.despia = finalDeeplink;
2. Variable Tracker Implementation
The VariableTracker is a crucial component that helps your application detect when Despia injects purchase-related variables into your application's window object.
-
Despia injects variables into your application after a purchase is completed
-
These variables contain essential transaction data (planID, transactionID, receipts)
-
VariableTracker reliably monitors when these variables become available
-
More robust than callbacks or global functions as it continues checking until variables are found
-
Works even if variables are injected after your tracking code has already executed
-
Persists within the current session until the variables are detected
class VariableTracker {
constructor(variables, onReady) {
this.variables = variables;
this.onReady = onReady;
this.triggered = false;
this.processing = false;
// Create tracker element
this.tracker = document.createElement('div');
this.tracker.style.display = 'none';
document.body.appendChild(this.tracker);
// Setup observer with debounce
let timeout;
this.observer = new MutationObserver(() => {
clearTimeout(timeout);
timeout = setTimeout(() => this.check(), 100);
});
this.observer.observe(this.tracker, { attributes: true });
this.check();
this.interval = setInterval(() => this.check(), 1000);
}
check() {
if (this.processing || this.triggered) return;
this.processing = true;
try {
const values = {};
const allSet = this.variables.every(name => {
const val = window[name];
if (val === undefined || val === "n/a") return false;
values[name] = val;
return true;
});
if (allSet && !this.triggered) {
this.triggered = true;
this.cleanup();
this.onReady(values);
}
} catch (err) {
console.error("Error during check:", err);
}
this.processing = false;
}
cleanup() {
this.observer.disconnect();
clearInterval(this.interval);
this.tracker.remove();
}
}
3. Track Purchase Variables
Use the VariableTracker to monitor for specific purchase-related variables that Despia will inject into your app:
new VariableTracker(
['planID', 'transactionID', 'subreceipts'],
values => {
// If usng JavaScript simply use the object below as needed.
console.log("Purchase Success", {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
});
// EXAMPLES FOR SECURE PURCHASE VALIDATION (for NoCode/LowCode Tools)
// ---------- WEWEB ----------
// WEWEB example using wwWorkflow to handle callback natively
// 1. Create a Native WeWeb Global Worklfow to receive following paramaters:
// A. plan
// B. transaction
// C. receipt
// 2. Add Logic to that Workflow to send those parameters to your backend for secure validation.
// 3. Call your Workflow from exactly this line of code here:
wwLib.wwWorkflow.executeGlobal('YOUR WEWEB WORKFLOW ID', {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
});
// ---------- WIZED ----------
// WIZED example using Wized's JS API
v.inapppurchase = {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
}
// Create a request (API Call) that will send "v.inapppurchase" to your server for validation.
const result = await Wized.requests.execute('REQUEST NAME TO VALIADTE PURCHASE');
console.log(result); // Or set result as variable if needed
// ---------- NORDCRAFT / TODDLE ----------
// For Nordcraft / Toddle - simply install the "Despia" Package and listen for the event callback.
// Clone the package from here: https://toddle.dev/projects/despia_package/branches/main
// Or run following after registering an "onCallback" Event in your Custom Action:
ctx.triggerActionEvent("onCallback", {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
});
}
);
Note: To restore previous purchases when a user reinstalls your app or uses it on a new device, refer to our Restore In-App Purchase documentation.
Purchase Flow
Initial Purchase
-
User triggers purchase through your UI
-
SDK initiates native purchase flow
-
Returns transaction data including receipt and ID
Validation
-
SDK automatically validates purchase with platform (client-side)
-
Returns base64 encoded receipt data + transaction id + bundle
-
Server can verify this data with Apple/Google APIs
Success Handling
-
Receive transaction ID and receipt
-
Send to your server with user authentication
-
Update user access/permissions
Make sure to validate the transaction data via your server on the backend using Apple’s / Google’s Official APIs - server side handling of purchase data is critical!
Security Best Practices
Backend Verification (Important)
Always verify purchases on your backend server to prevent fraud:
-
When your frontend receives transaction data from the VariableTracker, send the complete object to your backend
-
Your backend should then verify the purchase with the platform's API:
For Apple App Store:
-
Use Apple's App Store Server API to verify receipts
-
Call the Get Transaction Info endpoint
-
Refer to Apple's latest documentation for the most current verification process
For Google Play Store:
-
Use Google's Android Publisher API to verify purchases
-
Call the Purchases.products: get endpoint
-
Refer to Google's latest documentation for the most current verification process
-
- Only grant access to purchased content/features after successful backend verification!
Example Frontend Code:
If you’re using a no-code/low-code tool, please refer to the examples above. Below is a sample JavaScript implementation showing both front-end and server-side validation.
new VariableTracker(
['planID', 'transactionID', 'subreceipts'],
values => {
// Send complete purchase data to your backend
fetch('https://your-backend.com/verify-purchase', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_AUTH_TOKEN' // Include user authentication
},
body: JSON.stringify({
planId: values.planID,
transactionId: values.transactionID,
receipt: values.subreceipts,
platform: navigator.userAgent.includes("despia-iphone") ||
navigator.userAgent.includes("despia-ipad") ? "ios" : "android"
})
})
.then(response => response.json())
.then(data => {
if (data.verified === true) {
// Grant access to purchased content
console.log("Purchase verified on backend");
} else {
// Handle verification failure
console.error("Purchase verification failed");
}
})
.catch(error => {
console.error("Error verifying purchase:", error);
});
}
);
Receipt Validation
-
Always validate receipts server-side
-
Use Apple/Google APIs for verification
-
Store transaction IDs for reference
User Authentication
-
Link purchases to authenticated users
-
Include device ID or auth token with validation
-
Prevent unauthorized access sharing
Webhook Handling
-
Implement secure webhook endpoints
-
Verify webhook authenticity
-
Process subscription updates in real-time
Testing Tips
Sandbox Testing
-
Use consumable products for repeated testing
-
Create test accounts in App Store/Play Console
-
Verify webhook functionality in test environment
Common Issues
-
Ensure bank account is linked in developer console
-
Verify product IDs match exactly
-
Check user agent detection for platform-specific code
If you need assistance implementing the SDK or have questions, contact our support team at support@despia.com