9 min read

Usage with Cordova

Iaptic is integrated with the cordova purchase plugin. Setting it up is as simple as adding a few lines in your code at plugin initialization.

Plugin version >= 13

The latest version of the plugin contains a Iaptic helper class.

Use the Receipt Validator

Instantiate an "iaptic" object and set the store validator to iaptic's.

const iaptic = new CdvPurchase.Iaptic({
  appName: "[APP_NAME]",
  apiKey: "[PUBLIC_KEY]",
});
CdvPurchase.store.validator = iaptic.validator;

_Note: Replace [PUBLIC_KEY]; and [APP_NAME] with values from your account.

Then make sure to perform receipt validation for approved transactions:

CdvPurchase.store.when()
    .approved(transaction => transaction.verify())
    .verified(receipt => receipt.finish())
    .unverified(receipt => console.log('receipt cannot be verified'));

Use to Determine Apple App Store Discount Eligibility

With App Store, a user is only eligible to certain discount offers if they are or were a subscriber to one of the products of the same subscription group. A user is only eligible to introductory offers if they have never been a subscriber.

You can use iaptic to perform eligibility detection for you. When initializing the APPLE_APPSTORE platform, set the discountEligibilityDeterminer to iaptic's:

CdvPurchase.store.initialize([
  {
    platform: CdvPurchase.Platform.APPLE_APPSTORE,
    options: {
      needAppReceipt: true,
      discountEligibilityDeterminer: iaptic.appStoreDiscountEligibilityDeterminer,
    }
  },
  // other platforms...
]);

Security Policy

Depending on how your app is configured, security policy may prevent it from making requests to the validation service (DOM Exception 18 / Error 0). To prevent this, make sure validator.iaptic.com is listed in your HTML file’s meta "Content-Security-Policy", in the "connect-src" list.

Here is an example of what that looks like:

<meta http-equiv="Content-Security-Policy"
     content="default-src 'self' 'unsafe-eval'; connect-src https://validator.iaptic.com; style-src 'self' 'unsafe-inline'; media-src *; img-src * 'self' data: blob:">

Best Practices

It's recommended to initialize the plugin when your app starts. This ensures:

  1. All active and pending purchases are processed immediately
  2. Purchases initiated from the store or using promo codes are captured
  3. Users don't need to navigate to a specific page to complete pending transactions

Here's the recommended initialization flow:

// Initialize as early as possible in your app
function initPurchasePlugin() {
  // Register your products
  CdvPurchase.store.register(products);
  
  // Setup your handlers
  CdvPurchase.store.when()
    .approved(p => p.verify()) // Validate receipt with iaptic
    .verified(p => p.finish()) // Acknowledge to the store
    .unverified(p => console.error('Receipt validation failed', p));
    
  // Initialize the platforms
  CdvPurchase.store.initialize([
    CdvPurchase.Platform.APPLE_APPSTORE,
    CdvPurchase.Platform.GOOGLE_PLAY
  ]);
}

// Alternative: Wait for user session if needed
SessionService.addEventListener("ready", initPurchasePlugin);

Purchase Processing Flow

sequenceDiagram
    participant App
    participant Plugin/SDK
    participant Store
    participant Iaptic
    participant Server

    rect rgb(255, 255, 255)
        Note over App: Plugin Initialization
        App->>Plugin/SDK: Initialize()
        Plugin/SDK->>Store: Check purchases
        Store-->>Plugin/SDK: Active/pending purchases
        Plugin/SDK-->>App: Notify purchases
        App->>Iaptic: verify()
        Iaptic->>Store: Validate receipt
        Store-->>Iaptic: Receipt status
        Iaptic-->>App: Validation result
        App->>Plugin/SDK: finish()
        Plugin/SDK->>Store: Acknowledge
        Iaptic->>Server: Webhook (RECEIPT_VALIDATED)
        Note over Server: Update user's purchases
    end

    rect rgb(255, 255, 255)
        Note over App: New Purchase Flow
        App->>Plugin/SDK: order()
        Plugin/SDK->>Store: Process purchase
        Store-->>Plugin/SDK: Success
        Plugin/SDK-->>App: Notify approved
        App->>Iaptic: verify()
        Iaptic->>Store: Validate receipt
        Store-->>Iaptic: Receipt status
        Iaptic-->>App: Validation result
        App->>Plugin/SDK: finish()
        Plugin/SDK->>Store: Acknowledge
        Iaptic->>Server: Webhook (RECEIPT_VALIDATED)
        Note over Server: Update user's purchases
    end

Important: Unacknowledged transactions may be refunded after 3 days on some platforms.

Error Handling and Logging

To help troubleshoot issues:

  1. Implement error logging for:
    • Plugin errors
    • Receipt validation failures
    • Uncaught exceptions
  2. Provide a way to access or submit logs when issues occur
  3. Consider adding a "Restore Purchases" feature where users can manually trigger receipt validation

Troubleshooting Purchase Issues

Unacknowledged Purchases

When a purchase is not acknowledged (finished):

  • Google Play will automatically refund it after 3 days
  • No webhook will be sent to iaptic until acknowledgment
  • The purchase won't be associated with any user in iaptic

To prevent these issues:

  1. Always initialize the plugin at app startup
  2. Ensure proper error handling during receipt validation
  3. Implement proper logging to track validation failures

Debugging Missing Purchases

If a purchase is missing from iaptic:

  1. Check if the purchase was acknowledged using the Google Order ID (GPA.xxxx-xxxx) or Apple Transaction ID.
  2. Verify client-side logs for errors that could have caused the call to verify() to be skipped or failed.
  3. You might want to log calls to CdvPurchase.store.error(...) and CdvPurchase.store.when().unverified(...).
  4. Ensure the plugin is properly initialized and handlers are attached at app startup

Common Implementation Issues

  1. Late Plugin Initialization:

    • While it's possible to initialize the plugin on-demand, this may lead to unprocessed purchases
    • Always initialize at app startup to handle background purchases automatically
    • If needed, provide a "Restore Purchases" feature as a fallback
  2. Missing Error Handling:

    • Implement proper error logging for plugin operations
    • Track receipt validation failures
    • Monitor unhandled exceptions
  3. Purchase Flow Issues:

    • After successful payment, no additional user action should be needed
    • The app should handle verification and acknowledgment automatically
    • Always verify purchases before acknowledging them

Need Help?

Contact us!