iOS Receipt Validation (StoreKit 2)
API for validating the signed transaction (Signed Transaction, JWS) of Unity IAP 5.0 (StoreKit 2).
This API uses the service-api.playnanoo.com domain.
This API 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.
API Information
- URL:
https://service-api.playnanoo.com/iap/v20260401/unity/ios - Method:
PUT - Authentication Required: Yes
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| jws_transaction | string | Required | Signed transaction (JWS). Unity IAP 5.0's jwsRepresentation |
| product_id | string | Required | Payment product ID |
| duplicate_allow | string | Optional | Allow duplicate receipt validation (Y/N) |
Unlike the legacy v20221001, currency and price are not passed. The server extracts the currency and amount directly from the JWS payload.
Response Data
Res Class
| Field | Type | Description |
|---|---|---|
| UserID | string | User ID |
| PackageName | string | Package name |
| OrderID | string | Order ID (transactionId) |
| ProductID | string | Product ID |
| Quantity | string | Quantity |
| Currency | string | Currency code |
| Price | string | Price |
| PurchaseState | string | Validation resultpurchase : Successful paymentwait : Processing in progresscancel : Validation failed |
Unity C# Implementation
BaseResponse Class
Base class for all API responses.
public class BaseResponse
{
public string ErrorCode;
public string Message;
public string WithdrawalKey;
public string BlockKey;
}
Field descriptions:
ErrorCode: Error codeMessage: Error messageWithdrawalKey: Key required for recovery when account is in withdrawal grace period (provided only for accounts in withdrawal grace period)BlockKey: Key provided when account is blocked (provided only for blocked accounts)
iOS IAP Validation Class (StoreKit 2)
using System;
using System.Collections;
using UnityEngine.Networking;
public class IAPUnityIOSJWS
{
static string path = "https://service-api.playnanoo.com/iap/v20260401/unity/ios";
[Serializable]
public class Req
{
public string jws_transaction; // 서명된 거래 정보 (JWS)
public string product_id; // 결제 상품 아이디
public string duplicate_allow; // 영수증 중복 검증 허용 여부
public IEnumerator Send(string jws_transaction, string product_id, bool duplicate_allow, Action<Res> onSuccess, Action<BaseResponse> onError)
{
if (!string.IsNullOrEmpty(jws_transaction)) this.jws_transaction = jws_transaction;
if (!string.IsNullOrEmpty(product_id)) this.product_id = product_id;
this.duplicate_allow = duplicate_allow ? "Y" : "N";
yield return HttpClient.Send<Req, Res>(
UnityWebRequest.kHttpVerbPUT,
path,
requireToken: true,
body: this,
onSuccess: onSuccess,
onError: onError
);
}
}
[Serializable]
public class Res : BaseResponse
{
public string UserID;
public string PackageName;
public string OrderID;
public string ProductID;
public string Quantity;
public string Currency;
public string Price;
public string PurchaseState;
}
}
Usage Example
public void ValidateIOSIAP(PendingOrder pendingOrder)
{
IAPUnityIOSJWS.Req req = new IAPUnityIOSJWS.Req();
// Unity IAP 5.0 (StoreKit 2) 서명된 거래
string jwsTransaction = pendingOrder.Info.Apple?.jwsRepresentation;
string productId = "com.example.game.gold_100";
StartCoroutine(req.Send(
jws_transaction: jwsTransaction,
product_id: productId,
duplicate_allow: false, // 중복 영수증 허용 안 함
onSuccess: res =>
{
Debug.Log($"IAP 검증 성공");
Debug.Log($"사용자 ID: {res.UserID}");
Debug.Log($"주문 ID: {res.OrderID}");
Debug.Log($"상품 ID: {res.ProductID}");
Debug.Log($"가격: {res.Price} {res.Currency}");
Debug.Log($"상태: {res.PurchaseState}");
},
onError: (error) =>
{
Debug.LogError($"IAP 검증 실패: [{error.ErrorCode}] [{error.Message}]");
}
));
}
jws_transaction is the signed transaction (Signed Transaction) string obtained from Unity IAP 5.0's pendingOrder.Info.Apple?.jwsRepresentation. Unity IAP 5.0 requires iOS 15.0 or later.
The server validates the x5c certificate chain embedded in the JWS against the Apple Root CA G3 (ES256), and no additional call to Apple servers or key file (.p8) is required. Sandbox / Xcode payments are stored in test mode and are not counted in revenue.
If you register App Store Server Notifications (Version 2), refund (REFUND) events are received automatically. The registration URL is https://service-api.playnanoo.com/webhook/apple/{gameId}. For details, refer to API & Platform Settings > iOS in the console.