Skip to main content

iOS Receipt Validation (StoreKit 2)

API for validating the signed transaction (Signed Transaction, JWS) of Unity IAP 5.0 (StoreKit 2).

URL Verification

This API uses the service-api.playnanoo.com domain.

StoreKit 2 (JWS) Method

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

ParameterTypeRequiredDescription
jws_transactionstringRequiredSigned transaction (JWS). Unity IAP 5.0's jwsRepresentation
product_idstringRequiredPayment product ID
duplicate_allowstringOptionalAllow duplicate receipt validation (Y/N)
No currency / price Parameters

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

FieldTypeDescription
UserIDstringUser ID
PackageNamestringPackage name
OrderIDstringOrder ID (transactionId)
ProductIDstringProduct ID
QuantitystringQuantity
CurrencystringCurrency code
PricestringPrice
PurchaseStatestringValidation result
purchase : Successful payment
wait : Processing in progress
cancel : 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 code
  • Message: Error message
  • WithdrawalKey: 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}]");
}
));
}
Obtaining the JWS

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.

Local Certificate Chain Validation

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.

Refund Detection (Webhook)

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.