콘텐츠로 이동

3단계. 상품 구매

사용자가 선택한 상품에 대해 Google Play 결제창을 호출하고 구매 승인 프로세스를 진행합니다. 호출 결과로 결제 완료 신호와 구매 영수증 데이터를 수신합니다.

아래 과정을 따라 Google Play 상품 구매를 진행합니다.

1. 인앱 상점 UI 노출

앱에서 인앱 상점 UI를 구현하고 사용자에게 노출합니다. 사용자가 상품을 선택하고 결제 버튼을 누를 수 있도록 합니다. 사용자가 결제 버튼을 누르면 다음 단계로 진행합니다.

2. 구매 사전 정보 저장

사용자가 결제 버튼을 누른 뒤 스토어 결제창을 열기 전에 구매 시도 정보를 저장합니다. 소모성 상품에서는 이 절의 CreatePrePurchaseAsync() 호출이 선택 사항입니다. 구독 상품은 CreatePrePurchaseAsync() 대신 PrepareSubscriptionAsync()를 반드시 호출하세요. 구독 자동 갱신 알림에는 Player ID가 없으므로, Hive Axyl 서버는 이 메서드로 저장한 기록에서 Player ID와 IapPayload를 찾습니다. 요청 필드는 PrepareSubscriptionAsync를, 소모성 상품의 전체 흐름은 구매 정보 기록을 참조하세요.

Method

CreatePrePurchaseAsync

CreatePrePurchaseAsync()는 상품, 결제 예정 금액, 통화, 국가와 언어, 앱 서버, IapPayload를 사전 구매 추적 레코드로 저장합니다.

호출 파라미터

필드명 타입 필수 여부 설명
request PrePurchase Required 구매 사전 정보 저장 요청 데이터 객체입니다.
context ApiCallContext Optional 호출 단위 설정 객체입니다. 멱등키·취소 토큰·요청 정책을 지정하며, 생략하면 기본값이 사용됩니다.

PrePurchase

필드명 타입 필수 여부 설명
Country string Required 사용자의 국가 코드(ISO 3166-1 두 자리)를 전달합니다
Currency string Required 결제 통화(ISO 4217 세 자리)를 전달합니다. 2단계. 상품 목록 조회에서 조회한 상품의 통화 값을 사용합니다
Language string Required 언어 코드(ISO 639-1 두 자리)를 전달합니다
Price decimal Required 결제 예정 금액입니다. 통화에 따라 소수점이 포함될 수 있습니다. 2단계. 상품 목록 조회에서 조회한 상품의 가격 값을 전달합니다
ProductId string Required 사용자가 선택한 인앱 상품의 고유 식별자입니다. 2단계. 상품 목록 조회에서 조회한 Product ID를 전달합니다
ProviderId PrePurchaseProviderId Required 마켓·결제 수단 식별자(enum)입니다. Google Play 결제 전용 요청이므로 Google만 지정합니다.
ServerId string Optional Hive 콘솔 앱 서버를 따라 앱 정보 > 앱 서버에서 앱 서버를 등록한 뒤 앱 서버 탭에서 확인하는 서버 ID
AccountUuid string Optional 로그인한 사용자의 playerId로 생성한 UUIDv5 값입니다. 스토어 결제창을 열기 전에 전달합니다. AccountUuid 생성을 참조하세요.
IapPayload string Optional 개발자가 마켓 결제 시 첨부하는 페이로드(JSON 문자열). 구매 완료 후 앱 서버 콜백에 그대로 전달됩니다.
RequestDate DateTimeOffset Optional 요청 시각(UTC)입니다. 생략하면 서버의 현재 시각을 사용합니다.

IapPayload 사용 예시

PrePurchase의 IapPayload에는 구매 완료 후 발급되는 영수증에 앱별 데이터를 담을 수 있습니다. 아래는 IapPayload를 활용하는 한 가지 예입니다.

예를 들어 사용자 프로필이 A, B, C 세 가지인 모바일 앱에서 사용자가 A 프로필로 앱 내 상품을 구매했다고 가정합니다. 이때 IapPayload에 {"character": "A"}와 같은 JSON 문자열을 담아 구매를 요청하면, 결제가 정상적으로 완료됐을 때 이 값이 구매 영수증에 포함되어 앱에 전달됩니다.

결제는 완료됐지만 네트워크 오류로 상품을 지급하지 못한 경우에는 지급 실패 건을 조회하고 해당 영수증을 다시 검증한 후 상품을 지급해야 합니다. 이때 사용자가 보유한 A, B, C 프로필 중 지급할 프로필을 알아야 합니다. 구매 영수증에 포함된 IapPayload의 {"character": "A"} 정보를 사용하면 지급 대상이 A 프로필임을 확인하고 정확하게 상품을 지급할 수 있습니다.

이는 한 가지 예일 뿐입니다. 상품 구매 시각, 구매 사용자 정보 등 앱에 필요한 정보를 IapPayload에 담아 구매 영수증에 첨부할 수 있습니다. 앱의 상황에 맞게 활용하세요.

호출 예시

PaymentsCreatePrePurchaseResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)는 아래 예시와 응답 상태에서 확인합니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.

using System;
using Hive.Axyl.Payments;
using Hive.Axyl.Core;

// payments: 초기화 시 등록된 IPaymentsService (자세한 획득은 [모듈 설치 및 초기화](../init.md) 참고)
IPaymentsService payments = HiveCore.Resolve<IPaymentsService>();

// 사용자가 결제 버튼을 누른 시점의 상품 정보로 요청 객체 생성
var request = new PrePurchase
{
    Country = "KR",
    Currency = "KRW",
    Language = "ko",
    Price = 1200.0m,
    ProductId = "com.game.item.gold_100",
    ProviderId = PrePurchaseProviderId.Google,
    ServerId = "server01",
    RequestDate = DateTimeOffset.UtcNow,
    AccountUuid = accountUuid
};

PaymentsCreatePrePurchaseResult result = await payments.CreatePrePurchaseAsync(request);

switch (result)
{
    case PaymentsCreatePrePurchaseResult.Success success:
        // 사전 저장 성공. 반환 데이터는 없습니다. 스토어 결제창 호출을 진행하세요.
        break;

    // 요청 값 문제 — 필수값과 형식 확인
    case PaymentsCreatePrePurchaseResult.PaymentBadRequest:
    case PaymentsCreatePrePurchaseResult.PaymentInvalidParameter:
        Debug.LogError("요청 파라미터를 확인하세요.");
        break;

    case PaymentsCreatePrePurchaseResult.UnknownOutcome unknownOutcome:
        Debug.LogWarning($"알 수 없는 결과: {unknownOutcome.Code}");
        break;

    // 공통 Failure 처리
    case PaymentsCreatePrePurchaseResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        break;

    // 안전망: 처리하지 않은 결과
    default:
        Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
        break;
}

응답 데이터

성공 시 별도 반환 데이터는 없습니다.

응답 예시

// Success 분기에서 별도 데이터 없이 스토어 결제창 호출을 진행합니다.

응답 상태

아래 표에는 PaymentsCreatePrePurchaseResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)를 정리했습니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요. 성공 시 별도의 반환 데이터는 없습니다.

응답 케이스 설명 앱 클라이언트 대응
Success 사전 저장 성공 스토어 결제창 호출 진행
PaymentBadRequest 결제 요청을 처리할 수 없습니다. 요청 값과 호출 조건을 점검
PaymentInvalidParameter 결제 요청 파라미터가 유효하지 않습니다. 요청 필드 값을 점검
UnknownOutcome SDK가 알 수 없는 도메인별 결과입니다. 실패로 처리하고 결과 코드를 기록
Failure 공통 Failure입니다. 공통 오류 처리를 참조하세요. 공통 오류 처리 기준에 따라 처리

3. Google Play 결제 요청

사용자가 결제 버튼을 누르는 시점에 Google 결제 플러그인을 통해 Google Play 결제창을 호출합니다. 사용자가 결제를 승인하면 구매 영수증(purchaseToken)과 마켓 주문번호를 획득합니다. 이 요청에는 구매 수량 필드가 없으므로 상품별 ProductId와 필요한 경우 OfferToken만 설정합니다.

Google 결제 플러그인의 LaunchBillingFlowAsync()를 호출해 Google Play 결제창을 실행합니다. 이 메서드는 결제창 실행 성공 여부만 반환하며, 실제 구매 결과는 PurchasesUpdated 이벤트를 통해 비동기로 수신합니다.

BillingClient 연결 필수

LaunchBillingFlowAsync()를 호출하기 전에 반드시 StartConnectionAsync()로 BillingClient를 연결하세요. 연결 방법은 1단계. 연동 환경 구성을 참조하세요.

3.1. 구매 결과 이벤트 구독

결제창을 호출하기 전에 PurchasesUpdated 이벤트를 구독합니다. 이 이벤트는 LaunchBillingFlowAsync()를 통한 결제 결과뿐 아니라 프로모션 코드 사용 등 외부에서 발생한 구매 결과도 전달합니다.

using Hive.Axyl.Core;
using Hive.Axyl.Payments.Addon.Google;

// Google 결제 플러그인 획득 (초기화 시 builder.AddPlayBilling()으로 등록 필요)
if (!HiveCore.TryResolve<IGooglePlayBillingPlugin>(out var googlePlugin))
{
    Debug.LogError("Google Play Billing 플러그인이 등록되지 않았습니다.");
    return;
}

// 구매 결과 이벤트 구독 (앱 생명주기 초기에 한 번만 등록)
googlePlugin.PurchasesUpdated += (PurchasesUpdatedEventArgs args) =>
{
    foreach (GooglePurchase purchase in args.Purchases)
    {
        if (purchase.PurchaseState == PurchaseState.Purchased)
        {
            // 결제 완료. purchaseToken과 orderId를 저장하고 다음 단계 진행
            string purchaseToken = purchase.PurchaseToken;
            string orderId = purchase.OrderId;
            Debug.Log($"구매 완료 — 상품: {string.Join(", ", purchase.Products)}, 주문: {orderId}");
        }
        else if (purchase.PurchaseState == PurchaseState.Pending)
        {
            // 결제 보류 중 (예: 편의점 결제). 확정 시 다시 이벤트 수신
            Debug.Log("결제가 보류 중입니다. 결제 확정 후 다시 이벤트를 수신합니다.");
        }
    }
};

// BillingClient 연결 해제 이벤트 구독 (플러그인은 자동 재연결하지 않음)
googlePlugin.BillingServiceDisconnected += () =>
{
    Debug.LogWarning("BillingClient 연결이 해제되었습니다. 재연결이 필요합니다.");
};

3.2. 결제창 호출

Method

LaunchBillingFlowAsync

Google Play 결제창을 호출하려면 Google 결제 플러그인이 제공하는 LaunchBillingFlowAsync()를 호출하세요. 2단계. 상품 목록 조회의 QueryProductDetailsAsync()에서 획득한 상품의 ProductId와 OfferToken을 전달합니다.

호출 파라미터

필드명 타입 필수 여부 설명
request LaunchBillingFlowRequest Required 결제창 호출 요청 데이터입니다.
ct CancellationToken Optional 취소 토큰입니다.

LaunchBillingFlowRequest

필드명 타입 필수 여부 설명
Products IReadOnlyList<LaunchBillingFlowProductParams> Required 구매할 상품 목록입니다. 1개 이상 담아야 합니다.
ObfuscatedAccountId string? Optional AccountUuid 생성에서 만든 값과 같은 값을 전달합니다. Google Play가 구매 정보에 연결하며, 영수증 검증 때 계정 대조에 사용합니다.
ObfuscatedProfileId string? Optional 난독화된 사용자 프로필 ID입니다.

ObfuscatedAccountId는 소모성 상품과 구독 상품에 같은 방식으로 전달합니다. 구독 상품은 같은 요청에 OfferToken도 전달하세요.

구독 상품은 2. 구매 사전 정보 저장에서 호출하는 PrepareSubscriptionAsync()의 SubscriptionPrePurchaseRequest.AccountUuid에도 같은 값을 전달하세요. 이 값은 구독 자동 갱신과 복원 시 사전 구매 기록을 찾는 기준입니다. 요청 필드는 PrepareSubscriptionAsync를 참조하세요.

LaunchBillingFlowProductParams

필드명 타입 필수 여부 설명
ProductId string Required 구매할 상품의 고유 식별자(Product ID)입니다.
OfferToken string Required 구독 상품 또는 다중 일회성 오퍼의 토큰입니다. QueryProductDetailsAsync()에서 조회한 현재 값을 전달하세요. 단일 일회성 오퍼는 빈 문자열로 둡니다.

호출 예시

LaunchBillingFlowAsync()의 반환 객체 GooglePlayBillingServiceLaunchBillingFlowResult는 결제창 실행 성공 여부만 나타냅니다. 실제 구매 결과는 위에서 구독한 PurchasesUpdated 이벤트를 통해 수신합니다.

using Hive.Axyl.Core;
using Hive.Axyl.Payments.Addon.Google;
using System.Threading;

// Google 결제 플러그인 획득
if (!HiveCore.TryResolve<IGooglePlayBillingPlugin>(out var googlePlugin))
{
    Debug.LogError("Google Play Billing 플러그인이 등록되지 않았습니다.");
    return;
}

// 결제창 호출 요청 객체 생성
var request = new LaunchBillingFlowRequest
{
    Products = new[]
    {
        new LaunchBillingFlowProductParams
        {
            ProductId = "com.game.item.gold_100",
            OfferToken = offerToken  // QueryProductDetailsAsync()에서 획득한 오퍼 토큰
        }
    },
    ObfuscatedAccountId = accountUuid
};

GooglePlayBillingServiceLaunchBillingFlowResult result =
    await googlePlugin.LaunchBillingFlowAsync(request, CancellationToken.None);

switch (result)
{
    case GooglePlayBillingServiceLaunchBillingFlowResult.Success:
        // 결제창 실행 성공. 실제 구매 결과는 PurchasesUpdated 이벤트로 수신
        Debug.Log("Google Play 결제창이 실행되었습니다.");
        break;

    case GooglePlayBillingServiceLaunchBillingFlowResult.UnknownOutcome:
        Debug.LogWarning("알 수 없는 결제창 실행 결과입니다.");
        break;

    case GooglePlayBillingServiceLaunchBillingFlowResult.Failure failure:
        Debug.LogError($"결제창 실행 실패: {failure}");
        break;

    default:
        Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
        break;
}

응답 상태

반환 객체 GooglePlayBillingServiceLaunchBillingFlowResult는 아래 케이스 중 하나로 분기됩니다. switch 구문으로 처리하세요.

응답 케이스 설명 앱 클라이언트 대응
Success 결제창 실행 성공. 실제 구매 결과는 PurchasesUpdated 이벤트로 수신합니다. PurchasesUpdated 이벤트 대기
UnknownOutcome 알 수 없는 결과 재시도 또는 오류 안내
Failure 공통 Failure입니다. 공통 오류 처리를 참조하세요. 공통 오류 처리 기준에 따라 처리
PurchasesUpdated 이벤트로 수신하는 구매 정보

PurchasesUpdated 이벤트의 GooglePurchase 객체에서 다음 정보를 획득합니다.

필드명 타입 설명
OrderId string? 마켓 주문번호입니다. (예: GPA.3389-9543-8198-17604)
PurchaseToken string 구매 영수증(purchaseToken)입니다. 이후 영수증 검증 및 거래 완료 처리에 사용합니다.
Products IReadOnlyList<string> 구매한 상품 ID 목록입니다.
PurchaseState PurchaseState 구매 상태입니다. Purchased(완료) 또는 Pending(보류)입니다.
PurchaseTime DateTimeOffset 구매 시각입니다.
Quantity int 구매 수량입니다.
IsAcknowledged bool 구매 확인(acknowledge) 완료 여부입니다.
Signature string 구매 서명 데이터입니다.
OriginalJson string Google Play가 반환한 원본 구매 JSON 데이터입니다.

Google 결제 플러그인을 호출해 결제 승인 후 다음 값을 받아 저장합니다.

  • 구매 영수증(purchaseToken)
  • 마켓 주문번호(예: GPA.3389-9543-8198-17604)

4. 결제 결과 데이터 저장

소모성 상품은 결제가 완료된 직후 영수증과 거래 정보를 저장합니다. 영수증 검증 전에 결제 사실을 보관하므로, 이후 처리가 중단되어도 검증, 상품 지급, 고객 지원과 정산에 사용할 수 있습니다. 영수증 검증 전에 이 단계를 완료하세요. 구독 상품은 이 단계 대신 5. 구독 구매 정보 저장을 진행하세요. 전체 흐름은 구매 정보 기록을 참조하세요.

Method

RecordStorePurchaseAsync

RecordStorePurchaseAsync()는 영수증, 거래 ID 등 결제 결과를 Hive Axyl 서버에 저장합니다.

호출 파라미터

필드명 타입 필수 여부 설명
request PurchaseRequest Required 결제 결과 저장 요청 데이터 객체입니다.
context ApiCallContext Optional 호출 단위 설정 객체입니다. 멱등키·취소 토큰·요청 정책을 지정하며, 생략하면 기본값이 사용됩니다.

PurchaseRequest

필드명 타입 필수 여부 설명
AccountUuid string Optional 로그인한 사용자의 playerId로 생성한 UUIDv5 값입니다. 스토어 결제가 끝난 뒤 구매 결과 기록에 전달합니다. 결제 시작 단계에 전달한 경우 같은 값을 사용하세요. AccountUuid 생성을 참조하세요.
AxylReceipt string Required Google Play 구매 토큰(purchaseToken)입니다.
Country string Required 국가 코드(ISO 3166-1 두 자리)입니다. 예: KR
Currency string Optional 결제 통화(ISO 4217 세 자리)입니다. Price와 짝을 이뤄 서버가 기록한 값과 대조하는 데 사용합니다. 둘 중 하나만 보내면 통화는 대조하지 않고 금액만 대조합니다. 예: KRW
IapPayload string Optional 개발자가 마켓 결제 시 첨부한 페이로드(JSON 문자열). 앱 서버 검증과 구매 완료 콜백에 그대로 전달됩니다.
Language string Required 언어 코드(ISO 639-1 두 자리)입니다. 예: ko
OrderId string Optional Hive Axyl 내부 주문 번호입니다. Steam/PG에 사용합니다.
Price decimal Optional 결제 금액입니다. 통화에 따라 소수점이 포함될 수 있습니다. 보내면 서버가 기록한 금액과 대조하고, 생략하면 대조하지 않습니다. Google 결제는 금액이 달라도 기록만 하고 요청을 거절하지 않습니다. 결제 내역에 남는 금액은 서버가 마켓에서 확인한 값입니다.
ProductId string Required 마켓에 등록한 인앱 상품 ID입니다.
ProjectInfo string Optional 앱별 자유 형식 JSON 문자열입니다. 값은 저장만 하며 앱 서버로 전달하지 않습니다. 앱 서버로 전달할 값은 IapPayload에 설정하세요.
ProviderId PurchaseRequestProviderId Required Google Play 결제 결과 저장 전용 요청이므로 Google을 지정합니다.
Quantity int Optional 구매 수량
RequestDate DateTimeOffset Optional 클라이언트 요청 시각(UTC)입니다. 생략하면 서버의 현재 시각을 사용합니다.
RequestType int Optional 요청 유형입니다. 1: 신규 구매, 2: 구매 복원
ServerId string Optional Hive 콘솔 앱 서버를 따라 등록한 앱 서버 ID입니다.
StoreTransactionId string Optional Google Play 스토어 거래 ID입니다.

호출 예시

PaymentsRecordStorePurchaseResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)는 아래 예시와 응답 상태에서 확인합니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.

using System;
using Hive.Axyl.Payments;
using Hive.Axyl.Core;

// payments: 초기화 시 등록된 IPaymentsService (자세한 획득은 [모듈 설치 및 초기화](../init.md) 참고)
IPaymentsService payments = HiveCore.Resolve<IPaymentsService>();

// 스토어 결제 완료 직후, 마켓이 발급한 영수증으로 요청 객체 생성
var request = new PurchaseRequest
{
    AxylReceipt = purchaseToken, // Google Play 구매 토큰
    ProviderId = PurchaseRequestProviderId.Google,
    ProductId = "com.game.item.gold_100",
    Price = 1200.0m,
    Currency = "KRW",
    Country = "KR",
    Language = "ko",
    Quantity = 1,
    StoreTransactionId = "GPA.3389-9543-8198-17604",
    RequestType = 1, // 1: 신규 구매
    RequestDate = DateTimeOffset.UtcNow,
    ServerId = "server01",
    AccountUuid = accountUuid
};

PaymentsRecordStorePurchaseResult result = await payments.RecordStorePurchaseAsync(request);

switch (result)
{
    case PaymentsRecordStorePurchaseResult.Success success:
        // 저장 성공. success.Data.Meta를 확인할 수 있습니다.
        break;

    // 요청 값 또는 결제 상태 문제
    case PaymentsRecordStorePurchaseResult.PaymentBadRequest:
    case PaymentsRecordStorePurchaseResult.PaymentInvalidParameter:
    case PaymentsRecordStorePurchaseResult.PaymentResourceNotFound:
    case PaymentsRecordStorePurchaseResult.PaymentUnauthorized:
    case PaymentsRecordStorePurchaseResult.VerifyError:
        Debug.LogError("요청 값과 결제 상태를 확인하세요.");
        break;

    case PaymentsRecordStorePurchaseResult.UnknownOutcome unknownOutcome:
        Debug.LogWarning($"알 수 없는 결과: {unknownOutcome.Code}");
        break;

    // 공통 Failure 처리
    case PaymentsRecordStorePurchaseResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        break;

    // 안전망: 처리하지 않은 결과
    default:
        Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
        break;
}

응답 데이터

성공 시 PaymentsRecordStorePurchaseResult.Success의 Data(PurchaseResponseData)에 결과가 담깁니다.

필드명 타입 필수 여부 설명
Data.Meta string Optional 응답 메타 정보

응답 예시

// Success 분기에서 success.Data.Meta를 확인할 수 있습니다.

응답 상태

아래 표에는 PaymentsRecordStorePurchaseResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)를 정리했습니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.

응답 케이스 설명 앱 클라이언트 대응
Success 결제 결과 저장 성공 앱 서버에 영수증을 전달해 영수증 검증 단계로 진행
PaymentBadRequest 결제 요청을 처리할 수 없습니다. 요청 값과 호출 조건을 점검
PaymentInvalidParameter 결제 요청 파라미터가 유효하지 않습니다. AxylReceipt 등 요청 필드를 점검
PaymentResourceNotFound 저장할 결제 정보를 찾을 수 없습니다. 영수증과 거래 정보를 점검
PaymentUnauthorized 결제 요청 권한이 없습니다. 앱과 인증 상태를 점검
VerifyError 결제 검증 중 오류가 발생했습니다. 영수증과 마켓 결제 상태를 점검
UnknownOutcome SDK가 알 수 없는 도메인별 결과입니다. 실패로 처리하고 결과 코드를 기록
Failure 공통 Failure입니다. 공통 오류 처리를 참조하세요. 공통 오류 처리 기준에 따라 처리

5. 구독 구매 정보 저장

구독 상품은 앱 서버에 영수증 검증을 요청하기 전에 PurchaseSubscriptionAsync()로 구독 구매 정보를 Hive Axyl 서버에 저장합니다. Hive Axyl 서버는 구독 완료 처리에서 같은 영수증으로 이 단계의 구독 기록을 찾으므로, 이 단계에 전달한 AxylReceipt를 구독 완료 처리까지 보관하세요.

Method

PurchaseSubscriptionAsync

PurchaseSubscriptionAsync()는 구독 영수증으로 구독 구매 정보를 저장하고, 저장한 구독 기록의 거래 ID와 조회 키를 반환합니다.

호출 파라미터

필드명 타입 필수 여부 설명
request SubscriptionPurchaseRequest Required 구독 구매 정보 저장 요청 데이터 객체입니다.
context ApiCallContext Optional 호출 단위 설정 객체입니다. 멱등키·취소 토큰·요청 정책을 지정하며, 생략하면 기본값이 사용됩니다.

SubscriptionPurchaseRequest

필드명 타입 필수 여부 설명
AppVersion string Optional 앱 버전입니다.
AxylReceipt string Required 구독 결제의 Google Play 구매 토큰(purchaseToken)입니다.
Country string Required 국가 코드(ISO 3166-1 두 자리)입니다. 예: KR
Currency string Required 통화(ISO 4217 세 자리)입니다. 예: KRW
Language string Required 언어 코드(ISO 639-1 두 자리)입니다. 예: ko
OriginalPrice decimal Optional 할인 전 가격입니다.
Price decimal Required 구독 가격입니다. 2단계. 상품 목록 조회에서 조회한 상품의 가격을 전달합니다.
ProviderId SubscriptionPurchaseRequestProviderId Required Google 구독이므로 Google을 지정합니다.
RequestTimeMs long Optional 요청 시각(밀리초)입니다.
ServerId string Optional Hive 콘솔 앱 서버를 따라 등록한 앱 서버 ID입니다.
StoreTransactionId string Optional Google 구독에서는 전달하지 않아도 됩니다. 서버가 영수증에서 조회 키를 만들며, 전달하더라도 이 값을 사용하지 않습니다.

호출 예시

PaymentsPurchaseSubscriptionResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)는 아래 예시와 응답 상태에서 확인합니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.

using Hive.Axyl.Payments;
using Hive.Axyl.Core;

// payments: 초기화 시 등록된 IPaymentsService (자세한 획득은 [모듈 설치 및 초기화](../init.md) 참고)
IPaymentsService payments = HiveCore.Resolve<IPaymentsService>();

// 구독 결제가 끝난 직후, 스토어가 발급한 영수증으로 요청 객체 생성
var request = new SubscriptionPurchaseRequest
{
    AxylReceipt = purchaseToken, // 구독 결제의 GooglePurchase.PurchaseToken
    ProviderId = SubscriptionPurchaseRequestProviderId.Google,
    Price = 5500.0m,
    Currency = "KRW",
    Country = "KR",
    Language = "ko",
    ServerId = "server01"
};

PaymentsPurchaseSubscriptionResult result = await payments.PurchaseSubscriptionAsync(request);

switch (result)
{
    case PaymentsPurchaseSubscriptionResult.Success success:
        // 저장 성공. 앱 서버에 구독 영수증 검증을 요청하세요.
        Debug.Log($"구독 기록 거래 ID: {success.Data.HiveAxylTransactionId}");
        break;

    case PaymentsPurchaseSubscriptionResult.PaymentResourceConflict:
        // 이미 저장된 구독입니다. 앱 서버에 구독 영수증 검증을 요청하세요.
        break;

    // 요청 값 또는 결제 상태 문제
    case PaymentsPurchaseSubscriptionResult.PaymentBadRequest:
    case PaymentsPurchaseSubscriptionResult.PaymentInvalidParameter:
    case PaymentsPurchaseSubscriptionResult.PaymentResourceNotFound:
    case PaymentsPurchaseSubscriptionResult.PaymentUnauthorized:
    case PaymentsPurchaseSubscriptionResult.VerifyError:
        Debug.LogError("요청 값과 결제 상태를 확인하세요.");
        break;

    case PaymentsPurchaseSubscriptionResult.UnknownOutcome unknownOutcome:
        Debug.LogWarning($"알 수 없는 결과: {unknownOutcome.Code}");
        break;

    // 공통 Failure 처리
    case PaymentsPurchaseSubscriptionResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        break;

    // 안전망: 처리하지 않은 결과
    default:
        Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
        break;
}

응답 데이터

성공 시 PaymentsPurchaseSubscriptionResult.Success의 Data(SubscriptionPurchaseResponseData)에 저장 결과가 담깁니다.

필드명 타입 필수 여부 설명
Data.HiveAxylTransactionId string Required 저장된 구독 기록의 거래 ID입니다.
Data.HiveAxylProductId string? Optional 저장된 구독 상품 ID입니다.
Data.HiveAxylStoreTransactionId string? Optional 구독 기록의 조회 키입니다. 서버는 구독 완료 처리에서 이 키로 같은 구독 기록을 찾습니다.
Data.Meta string? Optional 응답 메타 정보입니다.

응답 상태

아래 표에는 PaymentsPurchaseSubscriptionResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)를 정리했습니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.

응답 케이스 설명 앱 클라이언트 대응
Success 구독 구매 정보를 저장했습니다. 앱 서버에 구독 영수증 검증 요청
PaymentBadRequest 결제 요청을 처리할 수 없습니다. 요청 값과 호출 조건을 점검
PaymentInvalidParameter 결제 요청 파라미터가 유효하지 않습니다. 요청 필드를 점검
PaymentResourceConflict 이미 저장된 구독 구매 정보입니다. 앱 서버에 구독 영수증 검증 요청
PaymentResourceNotFound 결제 정보를 찾을 수 없습니다. 영수증과 거래 ID를 확인
PaymentUnauthorized 결제 요청 권한이 없습니다. 인증 정보와 요청 권한을 확인
VerifyError 결제 검증 중 오류가 발생했습니다. Google Play 영수증과 결제 상태를 확인
UnknownOutcome SDK가 알 수 없는 도메인별 결과입니다. 실패로 처리하고 결과 코드를 기록
Failure 공통 Failure입니다. 공통 오류 처리를 참조하세요. 공통 오류 처리 기준에 따라 처리

다음 단계

4단계. 영수증 검증을 진행합니다.