Fulfill purchases through the SDK
Retrieve purchase information and determine purchase status for products bought by players.
Read time 2 minutesLast updated a month ago
Unity IAP fetches purchase information from the store so your application can recognize and fulfill what players have bought. This ensures that your game can deliver content or entitlements to users based on their purchase history, even if they bought items outside your app or on another device.
A purchase is represented as an object. The contains all relevant details about the purchase and provides information needed to track and manage it with the store.
OrderOrderRetrieve purchases
Purchases made by the user can be retrieved from the store. However, consumable products must be tracked by your application after they are consumed, because stores don't return consumables that have already been fulfilled. For non-consumable products and subscriptions, the store accurately returns these purchases when you call or .
FetchPurchasesCheckEntitlementDetermine purchase status
You can determine the status of a purchase in two ways:
- Use to determine if the
Orderis aOrder,PendingOrder,ConfirmedOrderorDeferredOrder.FailedOrder - Use to receive
CheckEntitlement, which returnsEntitlementStatus,EntitledButNotFinished,EntitledUntilConsumed,FullyEntitledorNotEntitled.Unknown
Purchase attributes
Attribute | Description |
|---|---|
| A unique identifier for the purchase. |
| The purchased product. |
| The quantity of the product purchased. |
| Receipt data for validating the purchase with the store. |
Purchase states
State | Description |
|---|---|
| The purchase has been paid but not yet fulfilled. |
| The purchase has been fulfilled and acknowledged. |
| The purchase failed due to an error. |
| The purchase is waiting for payment. |
Process purchases
The callback is invoked when a purchase is made and is awaiting fulfillment. Your application should fulfill the purchase at this point, for example by unlocking local content or sending the purchase receipt to a server to update a server-side game model.
OnPurchasePendingNote that may be called at any point following a successful initialization. If your application crashes during execution of the handler, then it is invoked again the next time Unity IAP initializes. Consider implementing your own de-duplication logic.
OnPurchasePendingOnPurchasePending// Handle restore on initializationprivate async void Start(){ // Setup, e.g. add listeners to your StoreController... m_StoreController.OnPurchasePending += OnPurchasePending; m_StoreController.OnPurchasesFetched += OnPurchasesFetched; await m_StoreController.Connect(); // Fetch previous purchases (includes confirmed orders) m_StoreController.FetchPurchases();}// Handle new purchases and pending transactionsprivate void OnPurchasePending(PendingOrder order){ ProcessPurchase(order);}// Handle fetched purchases (includes previously confirmed orders)private void OnPurchasesFetched(Orders orders){ foreach (var confirmedOrder in orders.ConfirmedOrders) { if (confirmedOrder.CartOrdered.Items().FirstOrDefault()?.Product.definition.type != ProductType.Consumable) { // Mark non-consumable and subscription products as entitled on fetch, as they only need to be granted once MarkAsEntitled(confirmedOrder.CartOrdered.Items().FirstOrDefault().Product); } }}// Your ProcessPurchase logicprivate void ProcessPurchase(PendingOrder order){ foreach (var product in order.CartOrdered.Items()) { // Grant product GrantProduct(product); } // Confirm the order to finalize the transaction m_StoreController.ConfirmPurchase(order);}
Reflect purchase state in your UI
Keep your buy buttons in sync with the purchase and entitlement state that Unity IAP reports, rather than treating them as always available. Syncing button states prevents duplicate purchase attempts, avoids offering a product the player already owns, and gives clear feedback while a purchase is processing. The correct mapping depends on the product type.
Non-consumables and subscriptions
Non-consumable and subscription products are entitled once and shouldn't be offered for purchase while the user owns them.
After succeeds, or when returns , reflect that entitlement state in your UI instead of a purchase action:
FetchPurchasesCheckEntitlementFullyEntitled- Non-consumables: Show an Owned state. Non-consumables are purchased once and owned forever, so no further action is needed unless the purchase is later refunded.
- Subscriptions: Show a Manage or Renew action. Unlike non-consumables, subscriptions can expire or be canceled, so provide a mechanism for the player to manage, renew, or cancel them.
Because subscriptions can expire, reevaluate subscription state on each app launch. Don't permanently cache subscriptions as owned.
Consumables
Consumables are normally available for purchase. Don't deactivate the buy button based on entitlement.
NotEntitledOnly deactivate the buy button when there's an unfinished order. If a consumable has an associated , either reported through or returned as by , complete the order before reenabling the button:
PendingOrderOnPurchasePendingEntitledUntilConsumedCheckEntitlement- Grant the reward.
- Call .
ConfirmPurchase - Re-enable the buy button.
Don't permanently deactivate the buy button of a consumable after purchase.
Update the button state during purchase flow
Deactivate the buy button when the purchase starts, whether you call or the Direct-to-Consumer (D2C) .
PurchaseProductShowPurchaseOptionBecause the button is deactivated when the purchase starts, update its state in every callback that can resolve the purchase attempt. Otherwise, the button can remain deactivated.
Update the button state in the following callbacks when the purchase attempt resolves:
Callback | Description |
|---|---|
| The purchase is paid and awaiting fulfillment. This order can be a new purchase or an unconfirmed order redelivered at launch. After you fulfill and confirm the order, set the resolved state: owned for a non-consumable product or subscription, or buyable for a consumable product. For more information, refer to Process purchases. |
| The order has been fulfilled and acknowledged. Use this callback to set the final owned state for non-consumable products and subscriptions if you don't do so in |
| The purchase failed or the player canceled it. Return the button to its buyable state. |
| The purchase is deferred and waiting to complete, such as for Ask to Buy approval. Show a waiting state instead of re-enabling the button. |
| Purchases retrieved on launch or restore. Set the owned state for any non-consumable products and subscriptions the player already owns. |
| The fetch couldn't complete, including when the device is offline and the status is |
Register these callbacks on your during setup, as shown in the example in Process purchases.
StoreControllerPurchase acknowledgement and reliability
Unity IAP requires you to explicitly acknowledge purchases to ensure that purchases are reliably fulfilled, even during network outages or application crashes. If a purchase is paid for but not fulfilled, Unity IAP delivers the purchase to your application the next time it initializes. This process prevents purchases from being lost when the purchase flow is interrupted or when purchases are completed while the application is offline.
After successfully fulfilling a purchase, call with the relevant to acknowledge the purchase to the store.
ConfirmPurchasePendingOrderAcknowledge purchases persisted to the cloud
If you are saving consumable purchases to the cloud, you must call when you have successfully persisted the purchase.
ConfirmPurchaseWhen returning , Unity IAP keeps transactions open on the underlying store until confirmed as processed. This ensures consumable purchases are not lost even if a user reinstalls your application while a consumable is pending.
PendingRestore purchases
Enable users to regain access to previously owned products and subscriptions when they reinstall your app or switch devices. Understand how IAP retrieves a record of entitlements and grants access:
- When a user reinstalls the application, Unity IAP restores owned products on the first call.
StoreController.FetchPurchases() - IAP invokes the listener with an
OnPurchasesFetchedobject that includes all purchases (all states).Orders - If the setting is set to
PurchaseService.ProcessPendingOrdersOnPurchasesFetched, IAP invokes thetruelistener for each unfulfilled purchase.OnPurchasePending - Subsequent calls in the same session don't trigger
FetchPurchases()for orders that you have already seen in the same session.OnPurchasePending
Use server-side validation alongside the SDK
You can make calls to the backend API while using the Unity In-App Purchases (IAP) SDK. This hybrid approach allows your server to act as the authority by validating transactions directly against Unity’s records before you reward the player. Unlike the standard backend API method, this doesn't require you to expose a public endpoint for webhooks, which can reduce your attack surface and simplify your server infrastructure.
Client-side implementation
When a purchase is initiated, the SDK returns a object. Extract the and pass it to your backend.
PendingOrderOrderInfo.TransactionIdBackend authentication
Use the Key ID and Secret Key from your Service Account to perform a Token Exchange to receive a stateless Bearer token. For more information, refer to how to Authenticate an API using a stateless token.
Refer to the following token exchange endpoint:
POST https://services.api.unity.com/auth/v1/token-exchange?projectId={projectId}&environmentId={envId}
Validate the order
Once your backend has a Bearer token, query the Unity IAP Order service with the following request:
GET https://iap.services.api.unity.com/v1/projects/{projectId}/environments/{envId}/orders/{orderId}
The is the same as the in the previous step.
Refer to the following important response fields:
orderIdTransactionId- must be
statusbefore you grant the items.paid - contains the underlying Stripe Checkout Session ID, if you need it to cross-reference in the Stripe Dashboard.
paymentProviderResourceId
Fulfill and complete the order
Refer to the following workflow to complete orders with server authority:
- Verify that the status is paid and the productSku matches the expected item.
- Update your player's database with the new entitlement.
- After the backend returns a success code to the client, use one of the following methods to finalize the transaction in the Unity IAP system:
- Update the order directly with the API
- Make the client call .
m_StoreController.ConfirmPurchase(order)
For more information, refer to the section on how to Mark orders as fulfilled through the API.
Next steps
This page is part of a workflow to set up Direct-to-Consumer (D2C) payment providers with IAP. To continue this workflow, choose one of the following options: