Keewano Unity SDK
Loading...
Searching...
No Matches
In-App Purchases

Overview

In-app purchases (IAP) are real-money transactions where players purchase premium currency, items, or other content from app stores (Apple App Store, Google Play). The Keewano SDK provides dedicated methods to track both the monetary transaction and the virtual items granted from these purchases.

Note
Best Practice: Server-Side Validation
For optimal fraud prevention and accurate analytics, we strongly recommend calling these IAP tracking methods only after your server validates the purchase receipt with Apple/Google. This ensures your revenue data reflects genuine transactions and helps the Keewano AI Agents provide more accurate insights.

IAP vs Virtual Economy

It's important to understand the distinction between two types of transactions in your game:

  • In-App Purchases (IAP): Real money → Virtual currency/items (tracked with ReportInAppPurchase and ReportInAppPurchaseItemsGranted)
  • Virtual Economy: Virtual items → Other virtual items (tracked with ReportItemsExchange)

For example:

  • Player buys "500 Crystals Pack" for $4.99 → IAP
  • Player spends 100 Crystals to buy a sword → Virtual Economy (see In-Game Balance)

The Two IAP Steps

Tracking in-app purchases involves two steps:

Step 1: ReportInAppPurchase - Track the Monetary Transaction

Use KeewanoSDK.ReportInAppPurchase() to log the real-money purchase event.

All revenue is stored in USD on Keewano servers. Choose one of the two exclusive options for currency conversion:

  • Game-Side Conversion

    Convert to USD cents on your server for precise control over exchange rates:

    // After server validation - pass price already converted to USD cents
    KeewanoSDK.ReportInAppPurchase(productId, priceInUsdCents);
    Definition KeewanoSDK.cs:18
    static void ReportInAppPurchase(string productName, uint priceUsdCents)
    Reports an in-app purchase event.
    Definition KeewanoSDK.cs:290

    This gives you full control over exchange rates and ensures consistency with your other analytics tools.

  • Keewano-Side Conversion

    Pass the local currency and let Keewano handle the conversion:

    // After server validation - pass localized price and currency code
    Product product = GetPurchasedProduct();
    product.definition.id,
    (float)product.metadata.localizedPrice, // e.g., 4.99f for €4.99
    product.metadata.isoCurrencyCode // e.g., "EUR" or "USD"
    );
    Note
    Currency codes must follow ISO 4217. Unrecognized codes are treated as USD. USD values are stored as-is without conversion.
    Warning
    For non-USD currencies, different analytics systems use different exchange rate sources and conversion timing. If you use multiple analytics tools, each may report slightly different revenue figures.

When to call:

  • ONLY after your server validates the purchase with Apple/Google
  • ONCE per purchase (even if items are granted multiple times)

Step 2: ReportInAppPurchaseItemsGranted - Track the Items Delivered

Use KeewanoSDK.ReportInAppPurchaseItemsGranted() to log the virtual items or currencies granted to the player from the purchase.

// After server validation and successful grant
Keewano.Item[] grantedItems = { new Keewano.Item("Crystals", 500) };
static void ReportInAppPurchaseItemsGranted(string productName, Item[] items)
Reports items granted from an in-app purchase.
Definition KeewanoSDK.cs:332
Definition KBatch.cs:6
Represents a game item with a unique identifier and a quantity.
Definition KeewanoItems.cs:11

Parameters:

  • productId - The same product identifier used in ReportInAppPurchase
  • items - Array of items granted (can also use ReadOnlySpan<Item> for zero-copy performance)

When to call:

  • ONLY after items are successfully granted to the player's account
  • Every time items are granted (can be multiple times for monthly/daily packages)

Why Are These Two Steps Separated?

These steps are separated because the purchase event and item grant event may happen at different times:

Common Cases for Separation

  1. Asynchronous Server Validation: Purchase completes → server validates → items granted later
  2. Monthly Packages: Player purchases once, but receives items daily/weekly over a month
  3. Time-Limited Offers: Purchase validated immediately, but items granted when player claims them
  4. Login Rewards: Player purchases a "30-Day Login Bonus" pack → items granted each day they log in
  5. Failed Grants: Purchase validated successfully, but item grant fails (network issue, database error) → retry later

Example: Monthly Login Package

A player purchases a "Monthly Gems Package" for $9.99 that grants 100 gems every day for 30 days:

// Day 1: Player completes purchase
void OnMonthlyPackagePurchased()
{
// Report the monetary transaction ONCE
KeewanoSDK.ReportInAppPurchase("com.mygame.monthly_gems", 999);
// Grant first day's gems
Keewano.Item[] items = { new Keewano.Item("Gems", 100) };
KeewanoSDK.ReportInAppPurchaseItemsGranted("com.mygame.monthly_gems", items);
}
// Days 2-30: Player logs in each day
void OnDailyLogin()
{
if (PlayerHasActiveMonthlyPackage())
{
// Grant daily gems (NO ReportInAppPurchase - already reported on Day 1)
Keewano.Item[] items = { new Keewano.Item("Gems", 100) };
KeewanoSDK.ReportInAppPurchaseItemsGranted("com.mygame.monthly_gems", items);
}
}

The Complete Purchase Flow

Here's the recommended flow for handling in-app purchases:

Flow Diagram

sequenceDiagram
    actor Player
    participant Game
    participant Store as App Store
    participant Server as Your Server
    participant API as Apple/Google API
    participant SDK as KeewanoSDK

    Player->>Game: 1. Click "Buy" button
    activate Game

    rect rgb(200, 230, 201)
    note right of Game: Keewano Auto-Tracking
    Game->>SDK: 2. (Automatic) ReportButtonClick()
    end

    Game->>Store: 3. Initiate purchase
    deactivate Game
    activate Store
    Store->>Store: 4. Process payment
    Store->>Game: 5. Purchase receipt
    deactivate Store

    rect rgb(255, 243, 224)
    note right of Game: Server Validation Phase
    activate Game
    Game->>Server: 6. Validate receipt
    activate Server
    Server->>API: 7. Verify receipt
    activate API
    API-->>Server: 8. Valid confirmation
    deactivate API
    Server->>Server: 9. Grant items to player
    Server-->>Game: 10. Confirm grant
    deactivate Server
    end

    activate Store
    Game->>Store: 11. Finalize/acknowledge purchase
    Store-->>Game: 12. Purchase complete
    deactivate Store

    rect rgb(200, 230, 201)
    note right of Game: Keewano Reporting Phase
    Game->>SDK: 13. ReportInAppPurchase()
    Game->>SDK: 14. ReportInAppPurchaseItemsGranted()
    deactivate Game
    end

Common Scenarios

Scenario 1: Immediate Grant (Synchronous)

The most common case where items are granted immediately after validation.

// Called by your server validation callback
void OnPurchaseValidated(string productId, uint priceUsdCents, Keewano.Item[] grantedItems)
{
// 1. Report the monetary transaction
KeewanoSDK.ReportInAppPurchase(productId, priceUsdCents);
// 2. Report the items granted
KeewanoSDK.ReportInAppPurchaseItemsGranted(productId, grantedItems);
}

Scenario 2: Delayed Grant (Asynchronous)

Purchase is validated first, items are granted later.

// Step 1: Server validates the purchase
void OnPurchaseValidated(string productId, uint priceUsdCents)
{
// Report the monetary transaction immediately
KeewanoSDK.ReportInAppPurchase(productId, priceUsdCents);
// Server will grant items asynchronously...
}
// Step 2: Later, when server grants the items
void OnItemsGrantedFromPurchase(string productId, Keewano.Item[] grantedItems)
{
// Report the items that were granted
KeewanoSDK.ReportInAppPurchaseItemsGranted(productId, grantedItems);
}

Scenario 3: Monthly/Daily Packages

Player purchases once, receives items over time.

// Player purchases "30-Day VIP Pass" for $14.99
void OnVIPPassPurchased()
{
// Report purchase ONCE
KeewanoSDK.ReportInAppPurchase("com.mygame.vip_pass_30days", 1499);
// Grant Day 1 rewards
Keewano.Item[] day1Rewards = {
new Keewano.Item("VIP_Status", 30), // 30 days of VIP
new Keewano.Item("Daily_Gems", 200)
};
KeewanoSDK.ReportInAppPurchaseItemsGranted("com.mygame.vip_pass_30days", day1Rewards);
}
// Each subsequent day (2-30)
void OnDailyLogin()
{
if (PlayerHasActiveVIPPass())
{
// Grant daily rewards (NO ReportInAppPurchase call)
Keewano.Item[] dailyRewards = {
new Keewano.Item("Daily_Gems", 200)
};
KeewanoSDK.ReportInAppPurchaseItemsGranted("com.mygame.vip_pass_30days", dailyRewards);
}
}

Scenario 4: Bundle with Multiple Items

When a purchase grants multiple different items.

void OnStarterPackPurchased()
{
string productId = "com.mygame.starter_pack";
uint price = 999; // $9.99
// Bundle contains multiple items
Keewano.Item[] bundleItems = {
new Keewano.Item("Crystals", 1000),
new Keewano.Item("Gold_Coins", 5000),
new Keewano.Item("Epic_Sword"),
new Keewano.Item("Health_Potion", 10)
};
KeewanoSDK.ReportInAppPurchase(productId, price);
}

Scenario 5: Purchase Validated but Grant Fails

If the purchase is valid but item grant fails temporarily.

void OnPurchaseValidated(string productId, uint priceUsdCents)
{
// Report the monetary transaction (purchase was valid)
KeewanoSDK.ReportInAppPurchase(productId, priceUsdCents);
// Attempt to grant items
bool success = TryGrantItemsToPlayerAccount(productId);
if (success)
{
Keewano.Item[] items = GetItemsForProduct(productId);
}
else
{
// Log error - player paid but didn't receive items yet
KeewanoSDK.LogError($"Failed to grant items for purchase: {productId}");
// Implement retry logic
// Call ReportInAppPurchaseItemsGranted later when items are successfully granted
}
}
static void LogError(string message)
Reports a technical issue encountered during gameplay.
Definition KeewanoSDK.cs:690

Best Practices

Server Validation is Critical

NEVER do this:

// BAD: Reporting immediately on store callback without validation
void OnAppStoreCallback(Purchase purchase)
{
// This is vulnerable to fraud!
KeewanoSDK.ReportInAppPurchase(purchase.productId, purchase.price);
}

ALWAYS do this:

// GOOD: Only report after server validation
void OnAppStoreCallback(Purchase purchase)
{
// Send to your server for validation first
YourServerAPI.ValidatePurchase(purchase.receipt, OnValidationComplete);
}
void OnValidationComplete(ValidationResult result)
{
if (result.isValid)
{
// Now it's safe to report
KeewanoSDK.ReportInAppPurchase(result.productId, result.priceUsdCents);
KeewanoSDK.ReportInAppPurchaseItemsGranted(result.productId, result.items);
}
}
Note
Server validation implementation is your responsibility. You must integrate with Apple's App Store Server API or Google Play Developer API to verify purchase receipts. This documentation shows when to call the Keewano SDK methods, not how to implement server validation.

Use Consistent Product IDs

Use the same product ID for both steps:

string productId = "com.mygame.crystals_500";
KeewanoSDK.ReportInAppPurchaseItemsGranted(productId, items); // Same productId

Only Report Actually Granted Items

Only call ReportInAppPurchaseItemsGranted() when items are successfully added to the player's account:

bool itemsGranted = AddItemsToPlayerInventory(items);
if (itemsGranted)
{
// Only report if grant succeeded
}

Report Purchase Once Only

For packages where items are granted multiple times, only call ReportInAppPurchase() once when the purchase is made:

// DAY 1: Purchase completed
KeewanoSDK.ReportInAppPurchase("monthly_pack", 999); // ✅ Call ONCE
KeewanoSDK.ReportInAppPurchaseItemsGranted("monthly_pack", day1Items);
// DAY 2-30: Daily rewards
// ❌ Do NOT call ReportInAppPurchase again
KeewanoSDK.ReportInAppPurchaseItemsGranted("monthly_pack", dailyItems); // ✅ Call each day

String Parameter Limits

Product IDs and item names are limited to 255 characters and will be trimmed if longer. Empty or null strings will skip the event.

See Also