question

corporate avatar image
corporate asked

iOS Purchase Validation: No Matching Catalogue Item / No successful callback

Hi there -

I'm running into strange behavior when I attempt to integrate iOS receipt validation of receipts from iTunes Sandbox. I am using Unity 2017.1 with the latest Unity IAP plugin. All of my purchases except for one return the "There is no item in the catalog with an ID matching the product ID in the receipt" error.

The sole exception is one of the bundles - vc_bundle_m. It functions correctly the first time I buy it but when I attempt another purchase, the game informs me that this item has already been purchased and will be restored for free. I suspect it is because, for some inscrutable reason, the ReceiveValidationResult callback (which contains the all-important controller.ConfirmPendingPurchase() is not getting called) - which, presumably, must mean that the game never treats it as a completed transaction (though the currency is still awarded on the server).

I've tested the IAP functionality without PlayFab's validation and I can confirm that purchases are being processed successfully - so the issue must be with the way I'm integrating the PlayFab side of things. I can't seem to find any inconsistencies in the way I've integrated this particular bundle compared to the others - if there's some difference on the iTunes side of things, I can't see it. Moreover.

Behavior (for failed purchases):

  1. Initiate the purchase process by calling the Purchase function in the code below
  2. Receive the iOS confirmation prompt with a request to enter my store credentials
  3. Upon doing so, receive the "Purchase Successful" dialogue - though the purchase is not, in fact, made
  4. Check the PlayFab events in the backend where the "There is no item in the catalog with an ID matching the product ID in the receipt" error is returned.

Behavior (for the one successful purchase):

  1. Initiate the purchase process by calling the Purchase function in the code below
  2. Receive the iOS confirmation prompt with a request to enter my store credentials
  3. Upon doing so, receive the "Purchase Successful" dialogue
  4. PlayFab awards the bundle on the server
  5. Observe that the ReceiveValidationResult callback is not being called
  6. Attempt to purchase the bundle again - and receive the "item has already been purchased and will be restored for free" error

Code references

The IAPController.cs class is responsible for everything related to IAPs. It is initiated at the start of the game via the IAPController.Instance.InitializePurchasing() call from the game controller.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
using System;
using PlayFab.ClientModels;
using PlayFab;
using LitJson;


public class IAPController : IStoreListener
{
    public static event Action<string> didPurchaseCurrencyBundle;


    #region Variables


    public IStoreController controller;
    private IExtensionProvider extensions;
    private Product pendingPurchase;


    public static IAPController Instance { get { if (instance == null) { instance = new IAPController(); } return instance; } }
    private static IAPController instance;


    /// <summary>The IDs of all golden cupcake purchases.</summary>
    public List<string> goldenCupcakeIDs = new List<string> { "vc_bundle_xs", "vc_bundle_s", "vc_bundle_m", "vc_bundle_l", "vc_bundle_xl", "vc_bundle_xxl", "vc_bundle_xxxl" };


    public Dictionary<string, string> goldenCupcakeNames = new Dictionary<string, string>()
    {
        { "vc_bundle_xs", "A Platter of Golden Cupcakes" },
        { "vc_bundle_s", "A Petite Box of Golden Cupcakes" },
        { "vc_bundle_m", "A Large Box of Golden Cupcakes" },
        { "vc_bundle_l", "A Tray of Golden Cupcakes" },
        { "vc_bundle_xl", "A Pyramid of Golden Cupcakes" },
        { "vc_bundle_xxl", "A Display of Golden Cupcakes" },
        { "vc_bundle_xxxl", "A Stand of Golden Cupcakes" },
    };


    /// <summary>Setting for whether to validate receipts via PlayFab or not.</summary>
    enum ValidationMechanism { None, PlayFab }; ValidationMechanism validationMechanism;


    #endregion


    public void InitializePurchasing()
    {
        if (IsInitialized())
        {
            Debug.Log("IAP Controller already initialized! Exiting");
            return;
        }


        validationMechanism = ValidationMechanism.PlayFab;
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
        for (int i = 0; i < goldenCupcakeIDs.Count; i++) { builder.AddProduct(goldenCupcakeIDs[i], ProductType.Consumable); }
        UnityPurchasing.Initialize(this, builder);
        Debug.Log("IAP Controller initialized!");


    }


    /// <summary>Called when Unity IAP is ready to make purchases.</summary>
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { this.controller = controller; this.extensions = extensions; }


    /// <summary>Called when Unity IAP encounters an unrecoverable initialization error. Note that this will not be called if Internet is unavailable; Unity IAP will attempt initialization until it becomes available.</summary>
    public void OnInitializeFailed(InitializationFailureReason error) { Debug.Log("UNITY IAP: Initialization failed! Reason: " + error.ToString()); }


    /// <summary> Called when a purchase fails.</summary>
    public void OnPurchaseFailed(Product i, PurchaseFailureReason p) { Debug.Log("UNITY IAP: Could not purchase " + i.metadata.localizedTitle + " due to " + p.ToString()); }


    private bool IsInitialized() { return controller != null && extensions != null; }


    /// <summary>Called when a purchase completes. May be called at any time after OnInitialized().</summary>
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    {
        if (validationMechanism == ValidationMechanism.None)
        {
            Debug.Log("UNITY IAP: Successfully purchased" + e.purchasedProduct.metadata.localizedTitle + " with an ID of " + e.purchasedProduct.definition.id);
            didPurchaseCurrencyBundle(e.purchasedProduct.definition.id);
            return PurchaseProcessingResult.Complete;
        }


        else
        {
            Debug.Log("UNITY IAP: Initiating validation of the purchase!");
            JsonData receipt = JsonMapper.ToObject(e.purchasedProduct.receipt);
            ValidateIOSReceiptRequest request = new ValidateIOSReceiptRequest
            {
                CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode,
                PurchasePrice = (int)e.purchasedProduct.metadata.localizedPrice * 100,
                ReceiptData = receipt["Payload"].ToString()
            };


            pendingPurchase = e.purchasedProduct;


            PlayFabClientAPI.ValidateIOSReceipt(request, ReceiveValidationResult, null, null);
            return PurchaseProcessingResult.Pending;
        }
    }


    /// <summary>Receive the result of the external validation request.</summary>
    public void ReceiveValidationResult(ValidateIOSReceiptResult result)
    {
        Debug.Log("UNITY IAP: Confirming validation of the purchase!");
        controller.ConfirmPendingPurchase(pendingPurchase);
        pendingPurchase = null;
        PlayerController.Instance.GetUserInventory();
    }


    /// <summary>Start the sequence to purchase this product.</summary>
    public void Purchase(string id) { controller.InitiatePurchase(id); }


}


Successful purchase report

{
    "EventName": "player_realmoney_purchase",
    "PaymentProvider": "iTunes Sandbox",
    "PaymentType": "ReceiptValidation",
    "OrderTotal": 505,
    "TransactionTotal": 500,
    "TransactionCurrency": "CHF",
    "OrderId": "61921CFCE107F9FD",
    "TransactionId": "1000000357390689",
    "PurchasedProduct": [
        "vc_bundle_m"
    ],
    "EventNamespace": "com.playfab",
    "EntityType": "player",
    "Source": "PlayFab",
    "TitleId": "F248",
    "EventId": "e8f59f42c069486597f5d934cc78ee46",
    "EntityId": "9284C0A3BBF1B083",
    "SourceType": "BackEnd",
    "Timestamp": "2017-12-06T07:27:35.5568296Z",
    "History": null,
    "CustomTags": null,
    "Reserved": null
}


{
    "EventName": "player_receipt_validation",
    "PaymentProvider": "iTunes Sandbox",
    "PaymentType": "ReceiptValidation",
    "ReceiptContent": "MIIWgQYJKoZIhvcNAQcCoIIWcjCCFm4CAQExCzAJBgUrDgMCGgUAMIIGIgYJKoZIhvcNAQcBoIIGEwSCBg8xggYLMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQECAQEEAwIBADALAgELAgEBBAMCAQAwCwIBDgIBAQQDAgFrMAsCAQ8CAQEEAwIBADALAgEQAgEBBAMCAQAwCwIBGQIBAQQDAgEDMAwCAQoCAQEEBBYCNCswDQIBAwIBAQQFDAMzOTkwDQIBDQIBAQQFAgMBrbMwDQIBEwIBAQQFDAMxLjAwDgIBCQIBAQQGAgRQMjQ5MBgCAQQCAQIEEFNUNsI1rwA8BkdNzjPY/PAwGwIBAAIBAQQTDBFQcm9kdWN0aW9uU2FuZGJveDAcAgEFAgEBBBQoW+TxJ5GY6CTxLB5X4Kc7eBy8izAeAgEMAgEBBBYWFDIwMTctMTItMDZUMDc6Mjc6MzRaMB4CARICAQEEFhYUMjAxMy0wOC0wMVQwNzowMDowMFowIgIBAgIBAQQaDBhjb20uU0lBLkNhbmR5Q2xpY2tlclRlc3QwTgIBBwIBAQRG3hNglyfHKI06F5OpDwepl0apO1fapJ/wxpadpLA53UdtqkjvUQdrBoEz8/deBvpS92mlyjab5ocQ+SGpBhEquPE8emTmzDBSAgEGAgEBBEo06PgxiFjRNMVJ9LdxddOHkFvxWMCR0yCXg6BkxsfE9QOG961xomksK/hq8DlE7er7k6ikP1sfC+w5Cn+NG5QjbSK1tDLQS/mr4jCCAVACARECAQEEggFGMYIBQjALAgIGrAIBAQQCFgAwCwICBq0CAQEEAgwAMAsCAgawAgEBBAIWADALAgIGsgIBAQQCDAAwCwICBrMCAQEEAgwAMAsCAga0AgEBBAIMADALAgIGtQIBAQQCDAAwCwICBrYCAQEEAgwAMAwCAgalAgEBBAMCAQEwDAICBqsCAQEEAwIBATAMAgIGrgIBAQQDAgEAMAwCAgavAgEBBAMCAQAwDAICBrECAQEEAwIBADAWAgIGpgIBAQQNDAt2Y19idW5kbGVfbTAbAgIGpwIBAQQSDBAxMDAwMDAwMzU3MzkwNjg5MBsCAgapAgEBBBIMEDEwMDAwMDAzNTczOTA2ODkwHwICBqgCAQEEFhYUMjAxNy0xMi0wNlQwNzoyNzozNFowHwICBqoCAQEEFhYUMjAxNy0xMi0wNlQwNzoyNzozNFowggFQAgERAgEBBIIBRjGCAUIwCwICBqwCAQEEAhYAMAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgazAgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAMAgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQEwDAICBq4CAQEEAwIBADAMAgIGrwIBAQQDAgEAMAwCAgaxAgEBBAMCAQAwFgICBqYCAQEEDQwLdmNfYnVuZGxlX3MwGwICBqcCAQEEEgwQMTAwMDAwMDM1NzM4NzcyNTAbAgIGqQIBAQQSDBAxMDAwMDAwMzU3Mzg3NzI1MB8CAgaoAgEBBBYWFDIwMTctMTItMDZUMDc6MjA6NTZaMB8CAgaqAgEBBBYWFDIwMTctMTItMDZUMDc6MjA6NTZaMIIBUQIBEQIBAQSCAUcxggFDMAsCAgasAgEBBAIWADALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEBMAwCAgauAgEBBAMCAQAwDAICBq8CAQEEAwIBADAMAgIGsQIBAQQDAgEAMBcCAgamAgEBBA4MDHZjX2J1bmRsZV94czAbAgIGpwIBAQQSDBAxMDAwMDAwMzU3Mzg3NjE0MBsCAgapAgEBBBIMEDEwMDAwMDAzNTczODc2MTQwHwICBqgCAQEEFhYUMjAxNy0xMi0wNlQwNzoxOTo0NlowHwICBqoCAQEEFhYUMjAxNy0xMi0wNlQwNzoxOTo0Nlqggg5lMIIFfDCCBGSgAwIBAgIIDutXh+eeCY0wDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMTEzMDIxNTA5WhcNMjMwMjA3MjE0ODQ3WjCBiTE3MDUGA1UEAwwuTWFjIEFwcCBTdG9yZSBhbmQgaVR1bmVzIFN0b3JlIFJlY2VpcHQgU2lnbmluZzEsMCoGA1UECwwjQXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApc+B/SWigVvWh+0j2jMcjuIjwKXEJss9xp/sSg1Vhv+kAteXyjlUbX1/slQYncQsUnGOZHuCzom6SdYI5bSIcc8/W0YuxsQduAOpWKIEPiF41du30I4SjYNMWypoN5PC8r0exNKhDEpYUqsS4+3dH5gVkDUtwswSyo1IgfdYeFRr6IwxNh9KBgxHVPM3kLiykol9X6SFSuHAnOC6pLuCl2P0K5PB/T5vysH1PKmPUhrAJQp2Dt7+mf7/wmv1W16sc1FJCFaJzEOQzI6BAtCgl7ZcsaFpaYeQEGgmJjm4HRBzsApdxXPQ33Y72C3ZiB7j7AfP4o7Q0/omVYHv4gNJIwIDAQABo4IB1zCCAdMwPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLXd3ZHIwNDAdBgNVHQ4EFgQUkaSc/MR2t5+givRN9Y82Xe0rBIUwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSIJxcJqbYYYIvs67r2R1nFUlSjtzCCAR4GA1UdIASCARUwggERMIIBDQYKKoZIhvdjZAUGATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMA4GA1UdDwEB/wQEAwIHgDAQBgoqhkiG92NkBgsBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEADaYb0y4941srB25ClmzT6IxDMIJf4FzRjb69D70a/CWS24yFw4BZ3+Pi1y4FFKwN27a4/vw1LnzLrRdrjn8f5He5sWeVtBNephmGdvhaIJXnY4wPc/zo7cYfrpn4ZUhcoOAoOsAQNy25oAQ5H3O5yAX98t5/GioqbisB/KAgXNnrfSemM/j1mOC+RNuxTGf8bgpPyeIGqNKX86eOa1GiWoR1ZdEWBGLjwV/1CKnPaNmSAMnBjLP4jQBkulhgwHyvj3XKablbKtYdaG6YQvVMpzcZm8w7HHoZQ/Ojbb9IYAYMNpIr7N4YtRHaLSPQjvygaZwXG56AezlHRTBhL8cTqDCCBCIwggMKoAMCAQICCAHevMQ5baAQMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpBcHBsZSBJbmMuMSYwJAYDVQQLEx1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEWMBQGA1UEAxMNQXBwbGUgUm9vdCBDQTAeFw0xMzAyMDcyMTQ4NDdaFw0yMzAyMDcyMTQ4NDdaMIGWMQswCQYDVQQGEwJVUzETMBEGA1UECgwKQXBwbGUgSW5jLjEsMCoGA1UECwwjQXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMxRDBCBgNVBAMMO0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyjhUpstWqsgkOUjpjO7sX7h/JpG8NFN6znxjgGF3ZF6lByO2Of5QLRVWWHAtfsRuwUqFPi/w3oQaoVfJr3sY/2r6FRJJFQgZrKrbKjLtlmNoUhU9jIrsv2sYleADrAF9lwVnzg6FlTdq7Qm2rmfNUWSfxlzRvFduZzWAdjakh4FuOI/YKxVOeyXYWr9Og8GN0pPVGnG1YJydM05V+RJYDIa4Fg3B5XdFjVBIuist5JSF4ejEncZopbCj/Gd+cLoCWUt3QpE5ufXN4UzvwDtIjKblIV39amq7pxY1YNLmrfNGKcnow4vpecBqYWcVsvD95Wi8Yl9uz5nd7xtj/pJlqwIDAQABo4GmMIGjMB0GA1UdDgQWBBSIJxcJqbYYYIvs67r2R1nFUlSjtzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFCvQaUeUdgn+9GuNLkCm90dNfwheMC4GA1UdHwQnMCUwI6AhoB+GHWh0dHA6Ly9jcmwuYXBwbGUuY29tL3Jvb3QuY3JsMA4GA1UdDwEB/wQEAwIBhjAQBgoqhkiG92NkBgIBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAT8/vWb4s9bJsL4/uE4cy6AU1qG6LfclpDLnZF7x3LNRn4v2abTpZXN+DAb2yriphcrGvzcNFMI+jgw3OHUe08ZOKo3SbpMOYcoc7Pq9FC5JUuTK7kBhTawpOELbZHVBsIYAKiU5XjGtbPD2m/d73DSMdC0omhz+6kZJMpBkSGW1X9XpYh3toiuSGjErr4kkUqqXdVQCprrtLMK7hoLG8KYDmCXflvjSiAcp/3OIK5ju4u+y6YpXzBWNBgs0POx1MlaTbq/nJlelP5E3nJpmB6bz5tCnSAXpm4S6M9iGKxfh44YGuv9OQnamt86/9OBqWZzAcUaVc7HGKgrRsDwwVHzCCBLswggOjoAMCAQICAQIwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTA2MDQyNTIxNDAzNloXDTM1MDIwOTIxNDAzNlowYjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5JGpCR+R2x5HUOsF7V55hC3rNqJXTFXsixmJ3vlLbPUHqyIwAugYPvhQCdN/QaiY+dHKZpwkaxHQo7vkGyrDH5WeegykR4tb1BY3M8vED03OFGnRyRly9V0O1X9fm/IlA7pVj01dDfFkNSMVSxVZHbOU9/acns9QusFYUGePCLQg98usLCBvcLY/ATCMt0PPD5098ytJKBrI/s61uQ7ZXhzWyz21Oq30Dw4AkguxIRYudNU8DdtiFqujcZJHU1XBry9Bs/j743DN5qNMRX4fTGtQlkGJxHRiCxCDQYczioGxMFjsWgQyjGizjx3eZXP/Z15lvEnYdp8zFGWhd5TJLQIDAQABo4IBejCCAXYwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCvQaUeUdgn+9GuNLkCm90dNfwheMB8GA1UdIwQYMBaAFCvQaUeUdgn+9GuNLkCm90dNfwheMIIBEQYDVR0gBIIBCDCCAQQwggEABgkqhkiG92NkBQEwgfIwKgYIKwYBBQUHAgEWHmh0dHBzOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzCBwwYIKwYBBQUHAgIwgbYagbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjANBgkqhkiG9w0BAQUFAAOCAQEAXDaZTC14t+2Mm9zzd5vydtJ3ME/BH4WDhRuZPUc38qmbQI4s1LGQEti+9HOb7tJkD8t5TzTYoj75eP9ryAfsfTmDi1Mg0zjEsb+aTwpr/yv8WacFCXwXQFYRHnTTt4sjO0ej1W8k4uvRt3DfD0XhJ8rxbXjt57UXF6jcfiI1yiXV2Q/Wa9SiJCMR96Gsj3OBYMYbWwkvkrL4REjwYDieFfU9JmcgijNq9w2Cz97roy/5U2pbZMBjM3f3OgcsVuvaDyEO2rpzGU+12TZ/wYdV2aeZuTJC+9jVcZ5+oVK3G72TQiQSKscPHbZNnF5jyEuAF1CqitXa5PzQCQc3sHV1ITGCAcswggHHAgEBMIGjMIGWMQswCQYDVQQGEwJVUzETMBEGA1UECgwKQXBwbGUgSW5jLjEsMCoGA1UECwwjQXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMxRDBCBgNVBAMMO0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENlcnRpZmljYXRpb24gQXV0aG9yaXR5AggO61eH554JjTAJBgUrDgMCGgUAMA0GCSqGSIb3DQEBAQUABIIBAIav2gcblGAlPFK4cKw3KA1Ur/FMwrE5PN94WGs+VT35NoTE+rbyNPzpZxDew4kkObunoI0ikcZVDMFayiKGjNa6S9whIZStu7eMa6BFWDnI7u57QM7RoA9mi5NVoMLTAR8UYPWE5eWKQ8Wz4e4tuITIX9ZvtdSRc/WS2OkwtAUJDg13fpU1pAY68TeOqxhFBPBzEEtDvbljZB/R4dPbXNxr3rU/lZ4lnbO+V7aETtcKt/uz8tkaZKja2mhfhana3Ppp9K9HUkE8l/AHSPdyyM+JMbBXOGfhCdYdLF5Zu1VRkMGSt17bkxW9IRG82wek3ZeFhj4cF37K8Rj8rwK1FCE=",
    "Valid": true,
    "Error": null,
    "EventNamespace": "com.playfab",
    "EntityType": "player",
    "Source": "PlayFab",
    "TitleId": "F248",
    "EventId": "a27bdff396134c7b86de3c326777c7fe",
    "EntityId": "9284C0A3BBF1B083",
    "SourceType": "BackEnd",
    "Timestamp": "2017-12-06T07:27:35.5568296Z",
    "History": null,
    "CustomTags": null,
    "Reserved": null
}

Unsuccessful Purchase Report

{
    "EventName": "player_receipt_validation",
    "PaymentProvider": "iTunes Sandbox",
    "PaymentType": "ReceiptValidation",
    "ReceiptContent": "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",
    "Valid": true,
    "Error": "There is no item in the catalog with an ID matching the product ID in the receipt",
    "EventNamespace": "com.playfab",
    "EntityType": "player",
    "Source": "PlayFab",
    "TitleId": "F248",
    "EventId": "ddb99f4382df4378955e3b078107e8da",
    "EntityId": "9284C0A3BBF1B083",
    "SourceType": "BackEnd",
    "Timestamp": "2017-12-06T07:27:35.5568296Z",
    "History": null,
    "CustomTags": null,
    "Reserved": null
}
Player DataIn-Game Economy
2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

corporate avatar image corporate commented ·

Important: I believe I've solved the issue partially by using the GetStoreItems method rather than constructing items in the client. This helped fixed the issue of missing products (turns out, an empty space at the end of the ID was to blame), but ReceiveValidationResult is still not being called.

0 Likes 0 ·
corporate avatar image corporate commented ·

I think I fixed it - seems like using (result) => {} instead of spelling it out in a separate callback method did the trick, somehow. Not sure how it made the difference but it did.

0 Likes 0 ·

1 Answer

·
brendan avatar image
brendan answered

Actually, the only real problem you had was that you had items in the catalog on the Apple side that had Product IDs that weren't the same in your Catalog in PlayFab. Because of that, the call to validate the receipt was failing. And since you had the error callback set to null, you weren't seeing the errors. Your original way to call the success callback should work fine - just make sure to add another callback to catch the errors and log them, so that you can see those when they occur.

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

corporate avatar image corporate commented ·

I now have another question - I noticed every time I start the app, it generates an invalid IOS receipt / missing parameters error. This happens even if I use an entirely new account (e.g., deleting the account on PlayFab and installing a fresh build on the device).

I'm not sure if this is normal - it might be that Unity IAP checks for pending transactions at the start of every session and, when there are none, triggers that error?

0 Likes 0 ·
brendan avatar image brendan corporate commented ·

Our SDK makes no receipt validation calls to our service by default. The only way you could be getting that is if your project is explicitly making the call to us. What I would recommend is adding some logging to the places where the receipt validation call is referenced in your project, so that you can see what's initiating the call.

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.