Apple & StoreKit
Goal: Tie App Store purchases, renewals, and refunds to a BitEasy install.
Requirement: A stable installId generated once per device install. Must be a valid UUID — StoreKit 2 only accepts UUID values for appAccountToken. Passing a non-UUID string will cause the purchase to fail silently.
App Store Server Notifications
Section titled “App Store Server Notifications”Summary
Section titled “Summary”Apple never sends device IDs or custom metadata in their server notifications. To link purchases to installs, the client must inject appAccountToken into each purchase.
BitEasy first learns the install ID when your app calls the /claim endpoint.
Step 1: Generate & persist a stable Install ID
Section titled “Step 1: Generate & persist a stable Install ID”Generate a UUID the first time the app is opened and store it permanently on the device. This must be a valid UUID (e.g. 550e8400-e29b-41d4-a716-446655440000) — Apple’s StoreKit 2 requires appAccountToken to be a UUID type. A non-UUID value will prevent the purchase sheet from appearing.
import AsyncStorage from '@react-native-async-storage/async-storage';import { v4 as uuidv4 } from 'uuid';
const INSTALL_KEY = 'biteasy_install_id';
export async function getStableInstallId() { let id = await AsyncStorage.getItem(INSTALL_KEY);
if (!id) { id = uuidv4(); await AsyncStorage.setItem(INSTALL_KEY, id); }
return id;}- Stored once via AsyncStorage
- Survives restarts; clears only if user manually wipes data or uninstalls
- No regeneration ensures deterministic attribution
Step 2: Use Install ID during Claim
Section titled “Step 2: Use Install ID during Claim”BitEasy learns the install ID the first time a user claims a referral code:
await fetch('https://api.biteasy.com/api/v1/claim', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ appId, installId: await getStableInstallId(), code, }),});Note: This is just an example. You may also pass
installIdwhen using the JS SDK.
Step 3: Pass the Install ID inside purchase calls
Section titled “Step 3: Pass the Install ID inside purchase calls”To link the purchase back to the claim, you must pass the install ID as the appAccountToken.
Swift (StoreKit 2)
Section titled “Swift (StoreKit 2)”let installId = getStableInstallId()guard let uuid = UUID(uuidString: installId) else { return }
let result = try await product.purchase( options: [.appAccountToken(uuid)])Swift (StoreKit 1)
Section titled “Swift (StoreKit 1)”let payment = SKMutablePayment(product: product)payment.applicationUsername = installIdqueue.add(payment)React Native (react-native-iap)
Section titled “React Native (react-native-iap)”Verified against latest react-native-iap (v13+) API surface.
Subscriptions:
import * as RNIap from 'react-native-iap';
await RNIap.requestSubscription({ sku: 'your_sku_here', appAccountToken: await getStableInstallId(),});One-time purchases:
await RNIap.requestPurchase({ sku: 'your_sku_here', appAccountToken: await getStableInstallId(),});Restore purchases:
await RNIap.restorePurchases({ appAccountToken: await getStableInstallId(),});Why it matters
Section titled “Why it matters”If you do NOT pass appAccountToken, App Store Server Notifications cannot identify who made the purchase.
If you DO pass it, Apple embeds it in:
- Initial trial or paid purchase
- Renewals
- Billing retries
- Refunds / Revokes
That’s it! BitEasy will automatically attribute the purchase to the install ID.