Back to Docs
FAQ

Frequently Asked Questions

Detailed answers to common questions about B4X Purchase Manager — how it works, how to integrate it, and how it compares to building your own solution.

What is B4X Purchase Manager?

B4X Purchase Manager (BPM) is a hosted monetization platform built specifically for B4A and B4i developers. It provides server-side purchase validation, subscription management, built-in purchase screens, restore flows, and usage analytics — all through a single B4X library (b4xlib).

The system has three parts: a b4xlib that runs inside your app and handles the entire purchase flow, a validation service that verifies receipts directly with Apple and Google, and a developer dashboard where you register apps, manage API keys, and view analytics.

Instead of building and maintaining your own PHP validation server, you add one library, write a few lines of code, and your app is ready to accept payments on both Android and iOS.

How do I add in-app purchases to my B4A app?

With B4X Purchase Manager, adding in-app purchases to a B4A (Android) app takes just a few steps:

  1. Sign up at app.b4xpurchasemanager.com, register your app, and grab your API key.
  2. Add CreateResourceFromFile(Macro, GooglePlayBilling.GooglePlayBilling) to your manifest.
  3. Drop the B4XPurchaseManager b4xlib into your Additional Libraries folder.
  4. Initialize and add your products:
PurchaseManager.Initialize(Root, BILLING_KEY, APP_ID, API_KEY)
PurchaseManager.AddProduct("premium_unlock", "Premium", "Unlock all features")

' Show the purchase screen
Wait For (PurchaseManager.ShowInAppPurchase) Complete (Success As Boolean)
If Success Then Log("Purchase successful!")

That's it. The library handles the Google Play Billing flow, sends the purchase token to the BPM validation server, verifies it with Google, caches the result locally, and manages unlock status automatically. Your users see a polished purchase screen with no UI work on your end.

How do I add in-app purchases to my B4i app?

The process for B4i (iOS) is almost identical to B4A. The same b4xlib and the same code works on both platforms:

  1. Ensure your App ID in the Apple Developer Portal has the In-App Purchase capability enabled.
  2. Create a provisioning profile based on that explicit (non-wildcard) App ID.
  3. Create your in-app purchases in App Store Connect and generate an App-Specific Shared Secret.
  4. Upload the Shared Secret to the BPM dashboard.
  5. Initialize in your B4i project (BillingKey is ignored on iOS):
PurchaseManager.Initialize(Root, BILLING_KEY, APP_ID, API_KEY)
PurchaseManager.AddProduct("premium_unlock", "Premium", "Unlock all features")

Wait For (PurchaseManager.ShowInAppPurchase) Complete (Success As Boolean)

The library handles StoreKit interaction, receipt validation with Apple via the BPM server, local caching, and unlock status — all cross-platform with the same API.

How do I add subscriptions to my B4X app?

BPM fully supports auto-renewing subscriptions on both Android (Google Play Billing) and iOS (Apple StoreKit). Adding subscriptions follows the same pattern as one-time purchases:

' Add subscription products
PurchaseManager.AddSubscription("premium_monthly", "monthly-plan", _
    "Monthly Premium", "Billed monthly", "Monthly")
PurchaseManager.AddSubscription("premium_annual", "annual-plan", _
    "Annual Premium", "Billed annually", "Annual")

' Show the subscription screen
Wait For (PurchaseManager.ShowSubscriptionPurchase) Complete (Success As Boolean)

' Check subscription status anytime (instant, from cache)
If PurchaseManager.IsSubscriptionActive Then
    Log("User is subscribed: " & PurchaseManager.GetActiveSubscriptionId)
End If

The library monitors subscription status automatically. Active subscriptions are re-validated every 24 hours in the background while the app is in use. If a subscription expires or is cancelled, the status updates on the next validation cycle. Built-in subscription screens with plan cards, dark mode, and theming are included.

What is server-side purchase validation and why does it matter?

Server-side validation means purchase receipts from Google Play or Apple are verified on a secure server rather than on the user's device. This is critical for two reasons:

  • Security — If you validate on-device, a user can modify the app or intercept the response to fake a valid purchase. Server-side validation is tamper-proof.
  • Credentials — Validating with Apple requires a Shared Secret. Validating with Google requires a service account. Ideally, these should never exist in your app code.

With BPM, every receipt is sent to the validation server over HTTPS, verified directly with Apple or Google's APIs, and the result is returned to your app. Zero secrets in your APK or IPA.

Can I use my own purchase UI instead of the built-in screens?

Yes. The built-in purchase and subscription screens are optional conveniences. If you prefer your own custom UI, call the purchase methods directly:

' Purchase a product directly (no built-in screen)
Wait For (PurchaseManager.PurchaseProduct("premium_unlock")) Complete (Success As Boolean)

' Purchase a subscription directly
Wait For (PurchaseManager.PurchaseSubscription("premium_monthly", "monthly-plan")) Complete (Success As Boolean)

Both methods handle the full flow — store interaction, receipt validation, caching, and status updates — regardless of what UI you use. A processing overlay is shown automatically during validation. You get the same server-side validation and caching benefits either way.

How does restore purchases work?

BPM includes a built-in restore flow for both platforms. When a user switches devices or reinstalls your app, they can restore their previous purchases:

' Restore in-app purchases
Wait For (PurchaseManager.RestorePurchases) Complete (Success As Boolean)

' Restore subscriptions
Wait For (PurchaseManager.RestoreSubscriptions) Complete (Success As Boolean)

The library queries the store for the user's purchase history, validates any found receipts with the BPM server, and updates the local cache. This is required by both Apple and Google for app approval.

How does caching and automatic validation work?

The b4xlib uses intelligent local caching so your app never needs to wait for a network call to check purchase status:

  • IsUnlocked and IsSubscriptionActive read from local cache instantly — no network delay.
  • New purchases (first 14 days) are re-validated every 24 hours in the background.
  • Established purchases (after 14 days) are re-validated every 14 days.
  • Active subscriptions are re-validated every 24 hours.
  • Users who have never purchased generate zero API calls.
' On app start or resume — instant, uses cache
PurchaseManager.CheckStatus

If PurchaseManager.IsUnlocked Then
    ' Show premium features immediately
End If

Call CheckStatus on app start or resume. It reads from cache instantly and triggers background validation only if the cache has expired. No loading spinners needed.

What happens if the user is offline?

The library caches entitlement status locally on the device. If a user has previously been validated, their unlock or subscription status is available immediately from cache — no network call needed. The app works normally offline.

When connectivity returns, the background validation system automatically picks up where it left off. If the cache has expired during the offline period, a fresh validation is triggered within 5 minutes of coming back online.

How much does B4X Purchase Manager cost?

BPM uses credit-based pricing where 1 credit = 1 validation request. The key thing: non-purchasing users cost you nothing. Only users who have actually bought something generate validation calls (~15 per month per paying user on average).

  • Free — 500 credits/month, $0. Enough for ~33 paying users. No credit card required.
  • Launch — 1,000 credits/month, $5/month. Enough for ~66 paying users.
  • Starter — 5,000 credits/month, $19/month. Enough for ~333 paying users.
  • Indie — 25,000 credits/month, $49/month. Enough for ~1,666 paying users.

The cost of validation is typically less than 1% of what your paying users generate in revenue — and it only gets smaller as you grow. Your monetization infrastructure should never eat into your earnings.

The free tier is a hard limit (no surprise charges). Paid tiers include automatic overage billing so your app never stops working. Start free for development and testing, then upgrade only when your app has real paying users.

Can I use BPM for multiple apps?

Yes. You can register and manage multiple apps from a single BPM account and dashboard. Each app gets its own API key and store credentials. Your credit allocation is shared across all your apps on the same plan.

Does the same code work on both Android and iOS?

Yes. The B4X Purchase Manager b4xlib is a cross-platform library. The same initialization, product setup, purchase flow, and status checking code works identically on B4A (Android) and B4i (iOS). Just pass your Google Play billing key — it's ignored on iOS:

Private Const BILLING_KEY As String = "MIIBIjANBgkq..."  ' Google Play license key (ignored on iOS)

PurchaseManager.Initialize(Root, BILLING_KEY, APP_ID, API_KEY)

Everything else — adding products, showing purchase screens, checking status, restoring purchases — is identical across platforms. No platform branching needed.

Where are my Apple and Google credentials stored?

Your store credentials (Apple Shared Secret and Google Play service account) are stored encrypted on BPM servers. They are used only for receipt validation and are never exposed in API responses, logs, or your app code.

This is a fundamental security advantage over client-side validation. Your APK or IPA contains only your API key (which grants validation access, not store access). Even if someone decompiles your app, they cannot access your Apple or Google credentials.

Does BPM support consumable products?

Yes. You can add consumable products (coins, gems, credits, etc.) that can be purchased multiple times:

PurchaseManager.AddConsumableProduct("power_boost", "Power Boost", "Boost your power")

' After successful purchase, add consumables
PurchaseManager.AddConsumables(10)

' Use consumables
If PurchaseManager.UseConsumables(1) Then
    Log("Consumed 1 item")
End If

' Check count
Dim count As Int = PurchaseManager.GetConsumableCount

Consumables are tracked locally on-device. If you need cross-device sync, use SetConsumableCount to sync with your own server on app launch.

Can I customize the look of the purchase screens?

Yes. The built-in screens support dark mode, custom color themes, and feature cards:

' Enable dark mode
PurchaseManager.DarkMode = True

' Custom color theme (Primary, Secondary, Accent, Background1, Background2)
PurchaseManager.SetThemeColors(0xFF6366F1, 0xFF8B5CF6, 0xFFEC4899, 0xFFFFFFFF, 0xFFF5F5F7)

' Add feature cards shown on the purchase screen
PurchaseManager.AddFeature("🎨", "Premium Themes", "Access all premium themes")
PurchaseManager.AddFeature("🚀", "Advanced Features", "Unlock powerful tools")

' Customize text
PurchaseManager.DisplayAppName = "My App"
PurchaseManager.DisplayTagline = "Unlock the Full Experience"

Pass 0 for any color parameter to use the default. You can add as many features as you want — they display dynamically on both purchase and subscription screens.

Does BPM help with privacy policy and terms of service?

Yes. The library includes auto-generated privacy policy and terms of service templates that meet App Store and Google Play requirements for subscription apps:

PurchaseManager.PolicyCompanyName = "Your Company"
PurchaseManager.PolicyEmailAddress = "[email protected]"
PurchaseManager.PolicyEffectiveDate = "January 1, 2025"

' Show them from a menu or button
PurchaseManager.ShowPrivacyPolicy
PurchaseManager.ShowTermsOfService

You can also supply your own custom privacy policy and terms — either as a URL to your hosted page, or as raw HTML bundled with your app. The library auto-detects whether you're providing a URL or HTML content.

What happens if my credits run out?

On the free tier, validation requests are blocked at the limit — but your users are not locked out. The library preserves the last known good state from cache. If a user was previously unlocked, they stay unlocked. No surprise charges.

Additionally, brand-new purchases are given a grace validation even when credits are exhausted. This prevents Google auto-refunds and lost sales — if a purchase token has never been validated before, the server lets it through.

On paid tiers, automatic overage billing kicks in so your app never stops working.

How do I test purchases during development?

The free tier gives you 500 credits/month — more than enough for development and testing. Enable debug mode for faster cache intervals:

' Enable debug mode for faster revalidation intervals (30s instead of 5min)
PurchaseManager.DebugValidation = True

For Android, use Google Play's Internal Testing track with test accounts. For iOS, use Sandbox accounts in TestFlight. The library provides reset methods for re-testing:

' Reset a purchase for re-testing
' Android: consumes token (allows re-purchasing)
' iOS: clears cache (use multiple Sandbox accounts for full re-test)
Wait For (PurchaseManager.ResetPurchaseForTesting("premium_unlock")) Complete (Success As Boolean)

Why use BPM instead of building my own validation server?

Building your own server means dealing with:

  • Setting up and maintaining a server (PHP, Node, Python, etc.)
  • Writing code to talk to Apple and Google's verification APIs
  • Storing secrets securely (Apple Shared Secret, Google service account)
  • Paying for hosting, databases, SSL certificates, and backups
  • Handling edge cases (refunds, subscription renewals, grace periods)
  • Scaling when your app grows

With BPM, all of that is handled for you. You add the b4xlib, write a few lines of initialization code, and you're done. The cost starts at $0 and scales to less than 1% of your revenue — far less than the hosting, time, and maintenance cost of running your own infrastructure.

Most solo developers underestimate the ongoing maintenance burden. Store APIs change, certificates expire, servers need patching, and edge cases multiply. BPM handles all of that so you can focus on building your app.

How do I get started with B4X Purchase Manager?

  1. Sign up at app.b4xpurchasemanager.com — free, no credit card required.
  2. Register your app in the dashboard and grab your API key.
  3. Upload store credentials — Apple Shared Secret and/or connect your Google Play service account.
  4. Add the b4xlib to your B4A or B4i project.
  5. Initialize and add products — a few lines of code and you're live.

The entire integration typically takes about 5 minutes if you already have your store products set up. See the Getting Started guide for a detailed walkthrough.

What are the rate limits?

Rate limits are per API key (not per device or per account):

  • Free / Launch / Starter / Indie: 10 requests/minute
  • Growth: 20 requests/minute
  • Pro: 50 requests/minute
  • Business: 200 requests/minute
  • Enterprise: 600 requests/minute

Rate-limited requests do not consume credits. The library's smart caching means you'll rarely hit these limits — non-purchasing users generate zero API calls, and paying users are only validated once per 24 hours.

What does a complete integration look like?

Here's a full working example showing initialization, products, subscriptions, status checking, and restore:

Sub Class_Globals
    Private Root As B4XView
    Private PurchaseManager As B4XPurchaseManager
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")

    ' Initialize (backend URL is built-in)
    PurchaseManager.Initialize(Root, BILLING_KEY, APP_ID, API_KEY)

    ' Configure display
    PurchaseManager.DisplayAppName = "My App"
    PurchaseManager.PolicyCompanyName = "Your Company"
    PurchaseManager.PolicyEmailAddress = "[email protected]"
    PurchaseManager.PolicyEffectiveDate = "January 1, 2025"

    ' Add products and subscriptions
    PurchaseManager.AddProduct("premium_unlock", "Premium", "Unlock all features")
    PurchaseManager.AddSubscription("monthly_sub", "monthly-plan", _
        "Monthly", "Full access", "Monthly")

    ' Add features for the purchase screen
    PurchaseManager.AddFeature("🎨", "Premium Themes", "All themes unlocked")
    PurchaseManager.AddFeature("🚀", "Advanced Tools", "Power features")
End Sub

Private Sub B4XPage_Appear
    PurchaseManager.CheckStatus  ' Instant, reads from cache
    UpdateUI
End Sub

Private Sub btnBuy_Click
    Wait For (PurchaseManager.ShowInAppPurchase) Complete (Success As Boolean)
    If Success Then UpdateUI
End Sub

Private Sub btnSubscribe_Click
    Wait For (PurchaseManager.ShowSubscriptionPurchase) Complete (Success As Boolean)
    If Success Then UpdateUI
End Sub

Private Sub btnRestore_Click
    Wait For (PurchaseManager.RestorePurchases) Complete (Success As Boolean)
    If Not(Success) Then
        Wait For (PurchaseManager.RestoreSubscriptions) Complete (Success As Boolean)
    End If
    UpdateUI
End Sub

Private Sub UpdateUI
    If PurchaseManager.IsUnlocked Or PurchaseManager.IsSubscriptionActive Then
        ' Show premium features
    End If
End Sub

Sub B4XPage_CloseRequest As ResumableSub
    If PurchaseManager.IsActive Then
        PurchaseManager.HidePurchaseScreen
        Return False
    End If
    Return True
End Sub

Have a question not covered here? Contact [email protected]