Coding Guidelines


First of all we need to initialize Store Kit before we can use the In App purchases API.

Make sure that InApp purchases Setup Guide is complete.


We can init store using this method:


But before we do this, we need to define the product that we want to sell and subscribe to the OSXInAppPurchaseManager actions.

There are two ways to define products:

1) Using scripting. Here is an example how we can define product SKUs with scripting:

public const string SMALL_PACK 	=  "";
public const string NC_PACK 	=  "";


2) Using Plugin Config. 

All you need to do is to Open

Windows -> OSX Native -> Edit Settings  and add your products ids under billing parameters section.



Listening for important events

There are 2 main actions we need to listen while implementing In Apps in the project:

public Action<IOSStoreKitResponse> OnTransactionComplete = delegate{};
public Action<ISN_Result> OnStoreKitInitComplete = delegate{};


We should subscribe to the OnStoreKitInitComplete action before sending load store requests; we should subscribe to the OnTransactionComplete before making any transaction requests.

Let subscribe to both events and initialize the store:

OSXInAppPurchaseManager.instance.OnStoreKitInitComplete += OnStoreKitInitComplete;
OSXInAppPurchaseManager.instance.OnTransactionComplete += OnTransactionComplete;



As soon as we get response from Apple, the OnStoreKitInitComplete action will be fired. Here is an example how we can handle the result.

private static void OnStoreKitInitComplete (ISN_Result result) {
		OSXInAppPurchaseManager.instance.OnStoreKitInitComplete -= OnStoreKitInitComplete;

		if(result.IsSucceeded) {
			Debug.Log("Inited successfully, Avaliable products cound: " + OSXInAppPurchaseManager.instance.products.Count.ToString());
		} else {
			Debug.Log("StoreKit Init Failed.  Error code: " + result.error.code + "\n" + "Error description:" + result.error.description);


As soon as OSXInAppPurchaseManager is initialized successfully, we can being making purchases.  You can always find out if OSXInAppPurchaseManager was initialized by checking:



You may also use following flag to find out if we're still waiting for the initialization response:


Getting In-app products info

After initialization is complete, you can get information about your products. All product info is stored within the IOSInAppPurchaseManager.instance.products array, and represented as IOSProductTemplate object:

public class OSXProductTemplate  {
	public string id {get;}
	public string title {get;}
	public string description {get;}
	public string price {get;}
	public string localizedPrice {get;}
	public string currencySymbol {get;}
	public string currencyCode {get;}


So for example, here is how you can get localized price of a specific product:

string localizedPrice = OSXInAppPurchaseManager.instance.GetProductById("YOUT_PRODUCT_ID").localizedPrice;


Or printing data for all products:

foreach(OSXProductTemplate tpl in OSXInAppPurchaseManager.instance.products) {
	Debug.Log("id" +;
	Debug.Log("title" + tpl.title);
	Debug.Log("description" + tpl.description);
	Debug.Log("price" + tpl.price);
	Debug.Log("localizedPrice" + tpl.localizedPrice);
	Debug.Log("currencySymbol" + tpl.currencySymbol);
	Debug.Log("currencyCode" + tpl.currencyCode);



Now we're ready to make the purchase. All you need to do is to call buyProduct function with the product id you want to buy:



It's a good idea to lock your interface before the OnTransactionComplete  action is fired. Here's an example of how to parse the result:

private static void OnTransactionComplete (OSXStoreKitResponse responce) {

        Debug.Log("OnTransactionComplete: " + responce.productIdentifier);
        Debug.Log("OnTransactionComplete: state: " + responce.state);

        switch(responce.state) {
        case OSXInAppPurchaseState.Purchased:
        case OSXInAppPurchaseState.Restored:
            //Our product been succsesly purchased or restored
            //So we need to provide content to our user 
            //depends on productIdentifier
        case OSXInAppPurchaseState.Deferred:
            //iOS 8 introduces Ask to Buy, which lets 
            //parents approve any purchases initiated by children
            //You should update your UI to reflect this 
            //deferred state, and expect another Transaction 
            //Complete  to be called again with a new transaction state 
            //reflecting the parent's decision or after the 
            //transaction times out. Avoid blocking your UI 
            //or gameplay while waiting for the transaction to be updated.
        case OSXInAppPurchaseState.Failed:
            //Our purchase flow is failed.
            //We can unlock interface and report user that the purchase is failed. 
            Debug.Log("Transaction failed with error, code: " + responce.error.code);
			Debug.Log("Transaction failed with error, description: " + responce.error.description);

        OSXMessage.Create("Store Kit Response", "product " + responce.productIdentifier + " state: " + responce.state.ToString());


The transaction response is represented as an  IOSStoreKitResponse object:

If the Transaction is InAppPurchaseState.Failed we can use the error property to find out the exact reason it failed:

Debug.Log("Transaction failed with error, code: " + responce.error.code);
Debug.Log("Transaction failed with error, description: " + responce.error.description);


You can see available error codes here.

The Error is represented as an IOSStoreKitError object


Note: So far I haven't found any specific recommendation from Apple what to do when you receive a Deferred purchase state.  Here's Apple's recommendation:

You should update your UI to reflect this deferred state, and expect another Transaction Complete  to be called again with a new transaction state reflecting the parent's decision or after the transaction times out. Avoid blocking your UI or gameplay while waiting for the transaction to be updated.

In other words:

  • keep listening for the transaction complete event, you will get fail/success depending on a parents decision or request timeout

  • Make sure you are not blocking UI or gameplay while awaiting the parents response

  • Update your UI to inform the user that purchase is waiting for approval.


If you have Non-Consumable products in your game, you also need to implement Restoring Purchases.

A full example can be found in PaymentManagerExample.cs.


Script Reference


public class OSXStoreKitResponse  {
	public string productIdentifier {get;}
	public OSXInAppPurchaseState state {get;}

    public string transactionIdentifier {get;}
	public string receipt{get;}

	public OSXStoreKitError error{get;}


public enum OSXInAppPurchaseState {


public class OSXStoreKitError  {
	public string description;
	public OSXTransactionErrorCode code;


public enum OSXTransactionErrorCode  {
	SKErrorUnknown = 0,
	SKErrorClientInvalid = 1,               // client is not allowed to issue the request, etc.
	SKErrorPaymentCancelled = 2,            // user cancelled the request, etc.
	SKErrorPaymentInvalid = 3,              // purchase identifier was invalid, etc.
	SKErrorPaymentNotAllowed = 4,           // this device is not allowed to make the payment
	SKErrorStoreProductNotAvailable = 5     // Product is not available in the current storefront