본문으로 건너뛰기

iOS 영수증 검증 (StoreKit 2)

Unity IAP 5.0 (StoreKit 2) 의 서명된 거래(Signed Transaction, JWS)를 검증하는 API입니다.

URL 확인

이 API는 service-api.playnanoo.com 도메인을 사용합니다.

StoreKit 2 (JWS) 방식

이 API는 Unity IAP 5.0 (iOS 15.0 이상) 의 StoreKit 2 서명된 거래(JWS)를 검증합니다. Unity IAP 4.x (StoreKit 1) 의 Base64 영수증을 사용하는 경우 iOS 영수증 검증 을 참고하세요.

API 정보

  • URL: https://service-api.playnanoo.com/iap/v20260401/unity/ios
  • Method: PUT
  • 인증 필요: 예

요청 파라미터

파라미터타입필수설명
jws_transactionstring필수서명된 거래 정보 (JWS). Unity IAP 5.0의 jwsRepresentation
product_idstring필수결제 상품 아이디
duplicate_allowstring선택영수증 중복 검증 허용 여부 (Y/N)
currency / price 파라미터 없음

레거시 v20221001 과 달리 currency, price 를 전달하지 않습니다. 통화·금액은 서버가 JWS payload 에서 직접 추출합니다.

응답 데이터

Res 클래스

필드타입설명
UserIDstring사용자 ID
PackageNamestring패키지 이름
OrderIDstring주문 ID (transactionId)
ProductIDstring상품 ID
Quantitystring수량
Currencystring통화 코드
Pricestring가격
PurchaseStatestring검증 결과
purchase : 정상결제
wait : 처리 진행중
cancel : 검증실패

Unity C# 구현

BaseResponse 클래스

모든 API 응답의 기본 클래스입니다.

public class BaseResponse
{
public string ErrorCode;
public string Message;
public string WithdrawalKey;
public string BlockKey;
}

필드 설명:

  • ErrorCode: 에러 코드
  • Message: 에러 메시지
  • WithdrawalKey: 탈퇴 유예 상태인 경우 복구에 필요한 키 (탈퇴 유예 중인 계정만 제공)
  • BlockKey: 차단된 계정인 경우 제공되는 키 (차단된 계정만 제공)

iOS IAP 검증 클래스 (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;
}
}

사용 예제

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 획득

jws_transaction 은 Unity IAP 5.0의 pendingOrder.Info.Apple?.jwsRepresentation 에서 얻는 서명된 거래(Signed Transaction) 문자열입니다. Unity IAP 5.0은 iOS 15.0 이상 이 필요합니다.

로컬 인증서 체인 검증

서버는 JWS 내장 x5c 인증서 체인을 Apple Root CA G3 기준으로 검증(ES256)하며, Apple 서버로의 추가 호출이나 키파일(.p8)이 필요하지 않습니다. Sandbox / Xcode 결제는 테스트 모드로 저장되어 매출에 집계되지 않습니다.

환불 감지 (Webhook)

App Store Server Notifications(Version 2)를 등록하면 환불(REFUND) 이벤트를 자동으로 수신합니다. 등록 URL은 https://service-api.playnanoo.com/webhook/apple/{gameId} 이며, 자세한 내용은 콘솔의 API 및 플랫폼 설정 > iOS 를 참고하세요.