iOS Receipt Validation (StoreKit 2)
Validates the signed transaction (Signed Transaction, JWS) of Unity IAP 5.0 (StoreKit 2).
This method validates the StoreKit 2 signed transaction (JWS) of Unity IAP 5.0 (iOS 15.0 or later). If you use the Base64 receipt of Unity IAP 4.x (StoreKit 1), refer to iOS Receipt Validation.
Call Information
IAP.IOS_JWS(string jwsTransaction, string productID, PlayNANOODelegate callback) {}
IAP.IOS_JWS(string jwsTransaction, string productID, bool isDuplicateAllow, PlayNANOODelegate callback) {}
Call Details
| Parameter | Description | Type |
|---|---|---|
| jwsTransaction | Signed transaction (JWS). Unity IAP 5.0's pendingOrder.Info.Apple?.jwsRepresentation | string |
| productID | Payment product ID | string |
| isDuplicateAllow | Allow duplicate receipt validation | boolean |
| callback | Communication result | PlayNANOODelegate |
Unlike the legacy IOS(), currency and price are not passed. The server extracts the currency and amount directly from the JWS payload to prevent forgery or tampering.
Example
When using Unity IAP Service (Unity IAP 5.0)
using PlayNANOO;
using UnityEngine.Purchasing;
public class PlayNANOOExample : MonoBehaviour
{
Plugin plugin;
void Awake()
{
plugin = Plugin.GetInstance();
}
// Unity IAP 5.0 - PendingOrder 처리
public void OnPurchasePending(PendingOrder pendingOrder)
{
string jws = pendingOrder.Info.Apple?.jwsRepresentation;
string productID = pendingOrder.CartOrdered.Items()[0].Product.definition.id;
plugin.IAP.IOS_JWS(jws, productID, (status, errorMessage, jsonString, values) => {
if (status.Equals(Configure.PN_API_STATE_SUCCESS))
{
Debug.Log(values["UserID"]);
Debug.Log(values["PackageName"]);
Debug.Log(values["OrderID"]);
Debug.Log(values["ProductID"]);
Debug.Log(values["Currency"]);
Debug.Log(values["Quantity"]);
Debug.Log(values["Price"]);
Debug.Log(values["PurchaseState"]);
// 검증 성공 시 거래 확정
storeController.ConfirmPurchase(pendingOrder);
}
else
{
Debug.Log("Fail");
}
});
}
}
Response
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"UserID" : "String",
"PackageName" : "String",
"OrderID" : "String",
"ProductID" : "String",
"Quantity" : "Integer",
"Currency" : "String",
"Price" : "Integer",
"PurchaseState" : "String"
}
Response Details
| Data Key | Description | Type |
|---|---|---|
| UserID | User identifier ID | string |
| PackageName | App package name | string |
| OrderID | Order ID (transactionId) | string |
| ProductID | Payment product ID | string |
| Quantity | Purchase quantity | integer |
| Currency | Payment currency code | string |
| Price | Product price | integer |
| PurchaseState | Validation result (purchase successful payment / wait processing in progress / cancel validation failed) | string |
Games that have migrated to StoreKit 2 can automatically detect refunds through App Store Server Notifications (Webhook). For the registration procedure, refer to the Refund Webhook Registration section at the bottom of this page.
Error Information
When receipt validation fails
ErrorCode : 20000
ErrorMessage : ValidationFailException
When the application package name does not match
ErrorCode : 20002
ErrorMessage : NotMatchPackageNameException
When the receipt has already been used
ErrorCode : 20005
ErrorMessage : ExistsReceiptException
Refund Webhook Registration (App Store Server Notifications)
To receive events such as refunds (REFUND) in real time, register the following Webhook URL with App Store Server Notifications (Version 2). The Webhook operates on a per-game (per-app) basis, so registering the URL applies regardless of the SDK version, and refunds are automatically reflected in the payment log.
Webhook URL
https://service-api.playnanoo.com/webhook/apple/{gameId}
{gameId} is the game channel ID. Copy the actual URL auto-generated per game from Console > Settings > API & Platform Settings > iOS using the copy button.
App Store Connect Registration Steps
| Step | Description |
|---|---|
| 1 | Go to App Store Connect > Select app > App Information > App Store Server Notifications |
| 2 | Enter the Webhook URL above in Production Server URL |
| 3 | Enter the same URL in Sandbox Server URL |
| 4 | Select "Version 2" for Notification Version and save |
Webhook receipt verification is also performed using only the JWS signature (Apple certificate chain), so no separate authentication key is required. The Production / Sandbox distinction is determined automatically by the environment field in the payload sent by Apple.