콘텐츠로 이동

Steam 결제 구현하기

Steam에서 소모성 상품을 판매하고 사용자에게 지급하려면 아래 절차를 순서대로 완료하세요.

시작하기 전에 공통 사전 준비를 마치세요.

전체 흐름

Steam 결제는 다른 마켓과 순서가 다릅니다. Hive Axyl 서버가 먼저 주문을 만들어 영수증을 발급하고, 사용자의 승인은 그 뒤에 Steam 오버레이에서 이루어집니다. 앱은 승인 결과를 콜백으로 직접 받아야 합니다. 영수증 검증과 상품 지급은 11단계에서 앱 서버가 Hive Axyl 서버 API로 처리합니다.

순서 구분 하는 일
1 스토어 콘솔 Steamworks에서 Publisher Web API Key 발급과 상품 등록
2 Hive 콘솔 인증 정보 등록, 가격 등급 설정, 상품 등록
3 Hive Axyl SDK, 스토어 플러그인 SDK 모듈과 Steam 결제 플러그인 설치 및 등록
4 레시피 코드 레시피 폴더 복사
5 앱 코드, Hive Axyl SDK SteamID 획득과 상품 목록 조회
6 레시피 코드 PurchaseOrder 생성
7 스토어 플러그인 결제 승인 콜백 수신 시작
8 레시피 코드 구매 시작
9 스토어 플러그인 사용자 승인 결과 수신
10 레시피 코드 구매 정보 준비
11 앱 코드, 앱 서버, Hive Axyl 서버 API 영수증 검증과 상품 지급
12 레시피 코드 거래 종료
13 Hive Axyl SDK, 스토어 플러그인 지급 결과 기록과 콜백 수신 해제
14 Hive 콘솔, Hive Axyl 서버 API 구매 내역 확인
거래 종료는 상품 지급이 끝난 뒤에 호출하세요

12단계의 거래 종료는 이 구매가 끝났다고 표시하는 동작입니다. 미지급 구매 복구는 종료되지 않은 구매만 찾으므로, 지급보다 종료를 먼저 처리하면 도중에 앱이 중단되었을 때 해당 구매를 다시 찾을 수 없습니다.

1. Steamworks 설정

Steamworks에서 Publisher Web API Key를 발급받고 판매할 상품을 등록하세요. Hive Axyl 서버가 이 키로 Steam에 주문 생성과 결제 확정을 요청합니다.

Steamworks에 등록한 상품 ID를 2단계에서 그대로 사용합니다.

2. Hive 콘솔 설정

  • Hive 콘솔  Hive 콘솔에서 설정하거나 확인합니다.

1단계에서 받은 키를 Hive 콘솔에 등록하고 가격 등급과 상품을 등록하세요.

설정 항목 필수 여부 확인할 곳
Publisher Web API Key 등록 필수 Steam 인증 정보
가격 등급 설정 필수 가격 등급 등록
상품 등록 필수 상품 정보 등록

Steam 결제는 Google Play나 Apple App Store와 달리 Hive 콘솔에 등록한 가격으로 청구합니다. 가격 등급 설정을 건너뛰면 결제 금액이 정해지지 않습니다.

상품 ID를 두 콘솔에서 일치시키세요

Steam에 등록한 상품 ID와 Hive 콘솔에 등록한 상품 ID가 같아야 합니다. 값이 다르면 영수증 검증이 실패합니다.

3. SDK 모듈과 플러그인 준비

필요한 SDK 모듈과 Steam 결제 플러그인을 설치한 뒤 SDK를 초기화할 때 등록하세요. 결제는 로그인한 사용자를 기준으로 동작하므로 결제 모듈과 함께 인증 모듈 AddAuth()와 토큰 모듈 AddToken()도 등록해야 합니다. 결제 모듈을 등록하지 않으면 레시피가 FailedPrecondition 오류로 실패합니다.

  • 설치할 패키지
    • com.com2usplatform.hiveaxyl.core: SDK 초기화와 공통 기능
    • com.com2usplatform.hiveaxyl.auth: 결제 주체인 사용자의 로그인 세션과 토큰 발급
    • com.com2usplatform.hiveaxyl.payments: 결제 서버 호출
    • com.com2usplatform.hiveaxyl.payments.addon.steam: 결제 승인 콜백 수신
Steamworks를 먼저 초기화하세요

앱을 시작할 때 SteamAPI.Init()를 호출하고 매 프레임 SteamAPI.RunCallbacks()를 실행해야 합니다. Steamworks가 초기화되지 않은 상태에서 플러그인을 사용하면 FAILED_PRECONDITION 오류가 발생합니다.

아래는 SDK를 초기화할 때 인증, 토큰, 결제 모듈과 Steam 결제 플러그인을 등록하는 예제 코드입니다. 예제는 개발과 테스트를 위해 결제 모듈을 샌드박스 서버에 연결하므로, 실제 서비스 빌드에서는 sandbox: true 없이 AddPayments()로 등록하세요.

using Hive.Axyl.Core;
using Hive.Axyl.Core.Unity;
using Hive.Axyl.Auth;
using Hive.Axyl.Payments;
using Hive.Axyl.Payments.Addon.Steam;

var config = CoreConfig.CreateBuilder("{appId}").Build();

HiveBootstrap.Initialize(config, builder =>
{
    builder.AddAuth();
    builder.AddToken();
    builder.AddPayments(sandbox: true);
    builder.AddSteamMicrotransactions();
});

4. 레시피 코드 설치

  • 레시피 코드  레시피 코드를 프로젝트에 복사합니다.

레시피는 패키지가 아니라 프로젝트에 복사해서 사용하는 소스 코드입니다. axyl-samples-unity 저장소에서 아래 항목을 Unity 프로젝트의 Assets/Recipes/ 아래로 복사하세요.

  • 복사 대상
    • Recipes.asmdef: 공통 어셈블리 정의
    • AssemblyInfo.cs: 내부 헬퍼를 다른 레시피 어셈블리에 공개하는 설정
    • Helper/: 여러 레시피가 함께 사용하는 공통 코드
    • Payments/: 레시피 본체와 공통 타입
    • Payments.Steam/: Steam 담당 코드

앱 코드에서 레시피를 호출하려면 앱 쪽 어셈블리 정의의 references에 Hive.Axyl.Samples.Recipes, Hive.Axyl.Samples.Recipes.Payments, Hive.Axyl.Samples.Recipes.Payments.Steam을 추가하세요.

Steam 결제 플러그인 없이도 컴파일됩니다

Payments.Steam/은 Steam 결제 플러그인을 참조하지 않으므로 언제나 컴파일됩니다. 결제 승인 콜백은 레시피 바깥에서 앱이 직접 받습니다.

5. SteamID 획득과 상품 목록 조회

  • 앱 코드  앱에서 직접 구현합니다.

    Hive Axyl SDK  Hive Axyl SDK를 앱에서 호출합니다.

상품 목록 조회에는 레시피가 없습니다. Steam은 사용자의 SteamID를 기준으로 Hive Axyl 서버가 국가와 통화까지 결정하므로 아래 순서대로 직접 호출하세요.

순서 구분 호출 확인할 곳
1 앱 코드 Steamworks에서 사용자의 64비트 SteamID 획득 Steam 사용자 ID 획득
2 Hive Axyl SDK FetchSteamProductsAsync()로 상품 목록 조회 상품 상세 정보 조회

조회 결과의 ProductId, Price, Currency와 1단계의 SteamID를 그대로 6단계의 PurchaseOrder에 넣으세요. Price가 비어 있는 상품은 가격을 확인하지 못한 상품이므로 판매하지 마세요.

6. PurchaseOrder 생성

  • 레시피 코드  레시피 코드를 앱에서 호출합니다.

PurchaseOrder는 사용자가 어떤 상품을 얼마에 구매하려는지를 담는 레시피 타입이며, 모든 결제 레시피의 시작점입니다.

using Hive.Axyl.Samples.Recipes;

// 앱이 한 번 정하고 절대 바꾸지 않는 네임스페이스 UUID
const string k_Namespace = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";

AccountUuid.TryCompute(k_Namespace, playerId, out var accountUuid);

if (product.Price == null)
{
    // 가격을 확인하지 못한 상품은 판매하지 않습니다.
    return;
}

var order = new PurchaseOrder(
    productId:     product.ProductId,     // 5단계에서 조회한 값
    price:         product.Price.Value,
    currency:      product.Currency,
    country:       "KR",
    language:      "ko",
    storePlayerId: steamId,               // 5단계에서 획득한 64비트 SteamID
    serverId:      "server01",
    iapPayload:    "{\"character\":\"A\"}",
    appVersion:    Application.version,
    accountUuid:   accountUuid);

storePlayerId는 Steam 결제에서 필수입니다. Hive Axyl 서버가 이 값으로 Steam에 주문을 생성합니다.

AccountUuid.TryCompute()는 로그인한 사용자의 playerId로 UUIDv5를 만드는 레시피 헬퍼입니다. Steam에는 대조할 마켓 계정 토큰이 없으므로 검증 응답의 대조 결과는 언제나 9로 돌아옵니다. 다만 이 값은 결제 내역에 저장되어 어느 사용자의 결제인지 확인하는 근거가 됩니다. 생성 규칙은 AccountUuid 생성을 참조하세요.

7. 결제 승인 콜백 수신 시작

구매를 시작하기 전에 Steam 결제 승인 콜백을 먼저 구독하세요. 8단계를 호출한 직후에 승인 결과가 도착할 수 있습니다.

아래 예제 코드는 MicroTxnAuthorizationResponse 이벤트를 먼저 구독한 뒤 콜백 수신을 시작합니다. 8단계가 끝나기 전에 도착한 승인 결과도 놓치지 않도록, 승인 여부 Authorized를 주문 번호 OrderId별로 모아 둡니다. 콜백 수신을 시작하지 못하면 승인 결과를 받을 수 없으므로 구매를 시작하지 마세요. 사용 예제에서는 IPurchaseApplication.ObservePayment()가 같은 역할을 합니다.

using System;
using System.Collections.Concurrent;
using Hive.Axyl.Core;
using Hive.Axyl.Payments.Addon.Steam;

var steamPlugin = HiveCore.Resolve<ISteamMicrotransactionsPlugin>();

// 주문 번호별 승인 여부를 모아 둡니다.
var approvals = new ConcurrentDictionary<ulong, bool>();
Action<SteamMicroTxnResponse> onResponse =
    response => approvals[response.OrderId] = response.Authorized;
steamPlugin.MicroTxnAuthorizationResponse += onResponse;

var startResult = await steamPlugin.StartCallbackListenerAsync(CancellationToken.None);
switch (startResult)
{
    case SteamMicrotransactionsServiceStartCallbackListenerResult.Success:
    case SteamMicrotransactionsServiceStartCallbackListenerResult.AlreadyStarted:
        // 8단계로 진행합니다.
        break;

    default:
        // 콜백 수신을 시작하지 못했습니다. 구매를 시작하지 않습니다.
        return;
}

8. 구매 시작

  • 레시피 코드  레시피 코드를 앱에서 호출합니다.

사용자가 결제 버튼을 누르면 레시피의 InitiatePurchaseAsync()를 호출하세요. Hive Axyl 서버가 Steam에 주문을 만들고 영수증을 돌려줍니다.

started.Pending에는 영수증과 주문 정보가 담깁니다. 아래 예제 코드처럼 결과 상태를 확인하기 전에 이 값을 앱의 구매 정보 저장소에 먼저 저장하세요. 저장해 두면 검증이나 종료가 실패해도 이 구매의 영수증과 주문 정보를 잃지 않습니다.

예제 코드의 pendingStore는 앱이 만드는 저장소로, 앱을 다시 실행해도 남아 있어야 합니다. 계정과 OrderId를 키로 삼아 저장하고, 거래 종료에 성공한 뒤에만 지우세요. 사용 예제에서는 IPurchaseApplication의 SavePendingAsync()와 MarkClosedAsync()가 같은 역할을 합니다. 영수증과 토큰 값은 로그에 남기지 마세요.

var recipe = new ConsumablePurchaseRecipe(new SteamPurchaseSource());

InitiatePurchaseOutcome started = await recipe.InitiatePurchaseAsync(order, token);

if (started.Pending != null)
{
    // 결과 상태와 관계없이 먼저 저장합니다.
    await pendingStore.SaveAsync(started.Pending);
}

if (started.Status == InitiatePurchaseStatus.UserCanceled)
{
    // 주문이 만들어지지 않았습니다. 상점으로 돌아가세요.
    return;
}

if (started.Status != InitiatePurchaseStatus.Success)
{
    Debug.LogError($"{started.FailedStep}: {started.BusinessOutcome} {started.Error?.Message}");
    return;
}

// 아직 사용자가 승인하지 않은 상태입니다. 9단계에서 승인 결과를 확인합니다.

레시피가 내부에서 수행하는 작업은 아래와 같습니다.

구분 호출 확인할 곳
Hive Axyl SDK InitiatePurchaseAsync()로 Steam 주문 생성 Steam 결제 세션 초기화
영수증을 받아도 결제가 끝난 것은 아닙니다

Steam은 사용자가 승인하기 전에 영수증을 발급합니다. 다른 마켓과 달리 이 시점에는 아직 청구되지 않았습니다. 9단계에서 승인 결과를 받기 전에 상품을 지급하지 마세요.

Steam 결제에는 구매 사전 정보 저장 단계가 없습니다. 주문 생성 호출이 그 기록까지 함께 처리하기 때문입니다.

9. 사용자 승인 결과 수신

사용자가 Steam 오버레이에서 결제를 승인하거나 취소하면 MicroTxnAuthorizationResponse 이벤트가 주문 번호와 승인 여부를 전달합니다. 이번 주문이 승인된 것을 확인한 뒤에만 다음 단계로 진행하고, 승인되지 않았다면 10단계를 호출하지 마세요.

7단계에서 모아 둔 결과 가운데 OrderId가 started.Pending.OrderId와 같은 결과만 이번 주문의 결과입니다. 이벤트의 OrderId는 ulong이고 started.Pending.OrderId는 문자열이므로 형식을 맞춰 비교하세요. 승인 결과는 8단계가 끝나기 전에 이미 도착했을 수 있으므로, 모아 둔 결과를 먼저 확인하고 없을 때만 도착을 기다리세요. 레시피는 이 이벤트를 기다리지 않으므로 대기 시간과 화면 처리는 앱이 결정합니다. 사용 예제에서는 IPurchaseApplication.WaitUntilVerifiableAsync()가 이번 주문의 승인 결과를 기다리는 역할을 합니다. 승인되지 않은 주문은 청구되지 않으므로 8단계에서 저장한 구매 정보를 지우세요.

10. 구매 정보 준비

  • 레시피 코드  레시피 코드를 앱에서 호출합니다.

승인을 확인한 뒤 PreparePurchaseAsync()를 호출해 구매 결과를 Hive Axyl 서버에 기록하고, 앱 서버에 보낼 구매 정보를 준비하세요. Hive Axyl 서버는 이 기록 요청을 받을 때 Steam에서 사용자의 승인을 확인합니다. 레시피는 이 단계에서 영수증 검증을 요청하지 않으므로, 성공 결과를 받아도 아직 상품을 지급하면 안 됩니다.

PreparePurchaseOutcome prepared = await recipe.PreparePurchaseAsync(started.Pending, token);

if (prepared.Pending != null)
{
    // 준비 단계가 돌려준 값으로 저장한 구매 정보를 교체합니다.
    await pendingStore.SaveAsync(prepared.Pending);
}

if (prepared.Status != PreparePurchaseStatus.Success)
{
    // 저장한 구매 정보는 지우지 않습니다. 미지급 구매 복구에서 마무리합니다.
    return;
}

// 11단계에서 prepared.Pending을 앱 서버에 보냅니다.

레시피가 내부에서 수행하는 작업은 아래와 같습니다.

구분 호출 확인할 곳
Hive Axyl SDK RecordStorePurchaseAsync()로 구매 결과 저장 결제 결과 데이터 저장 및 승인 확인

11. 영수증 검증과 상품 지급

  • 앱 코드  앱에서 직접 구현합니다.

    앱 서버  앱 서버에서 직접 구현합니다.

    Hive Axyl 서버 API  앱 서버에서 Hive Axyl 서버 API를 호출합니다.


    상세 절차: Hive Axyl Server API로 영수증 검증

영수증 검증과 상품 지급은 앱 서버가 처리하며, 레시피는 이 단계에 관여하지 않습니다. 앱이 10단계의 prepared.Pending을 앱 서버에 보내면, 앱 서버는 Hive Axyl 서버 API로 영수증을 검증하고 상품을 한 번만 지급한 뒤 그 결과를 앱에 응답합니다.

11.1. 앱 서버에 검증과 지급 요청

앱에서 앱 서버를 호출해 영수증 검증과 상품 지급을 요청하세요. 앱 서버에는 prepared.Pending의 Market, AxylReceipt, VerifyToken, OrderId, StoreTransactionId와 Order에 담긴 주문 정보를 보내세요. 앱 서버를 호출하는 방법과 응답 형식은 앱이 정합니다.

예제 코드의 VerifyAndGrantOnceAsync()는 앱 서버를 호출하는 앱의 메서드입니다. 사용 예제에서는 IPurchaseApplication.VerifyAndGrantOnceAsync()가 같은 역할을 합니다. 이 메서드는 아래와 같이 구현하세요.

  • 두 번째 인자 requestType: 신규 구매인지 구매 복구인지를 나타내는 값. 인자 형식은 앱이 정함
    • 예제 코드: 영수증 검증 요청의 requestType에 넣을 값 1을 그대로 전달
    • 사용 예제: PurchaseVerificationKind.NewPurchase 또는 PurchaseVerificationKind.Recovery를 전달하고, 앱 서버 연동 코드가 이 값을 각각 1과 2로 바꿈
  • 반환값: 앱 서버가 지급 완료로 응답하면 new PurchaseDeliveryConfirmation(), 거절이나 실패로 지급을 확인하지 못하면 null
  • hiveAxylTransactionId 보관: PurchaseDeliveryConfirmation에는 이 값을 담는 필드가 없으므로, 앱 서버 응답에서 따로 보관해 13단계의 지급 결과 기록에 사용
// 앱 서버에 영수증 검증과 상품 지급을 요청합니다.
PurchaseDeliveryConfirmation delivery = await VerifyAndGrantOnceAsync(
    prepared.Pending,
    requestType: 1,   // 1: 신규 구매. 사용 예제의 PurchaseVerificationKind.NewPurchase
    token);

if (delivery == null)
{
    // 앱 서버가 지급을 확인하지 않았습니다.
    // 저장한 구매 정보를 그대로 두고 거래를 종료하지 않습니다.
    return;
}

// 앱 서버 응답의 hiveAxylTransactionId는 VerifyAndGrantOnceAsync()가 따로 보관합니다.
// 13단계에서 axylTransactionId로 사용합니다.

11.2. Hive Axyl 서버 API로 영수증 검증

앱 서버는 Hive Axyl 서버 API의 POST /payment/v1/purchase/verify를 호출해 영수증을 검증하세요. 요청 헤더 X-App-Id에는 Hive 콘솔에 등록한 App ID를 넣고, 요청을 보낼 주소는 기본 URL을 참조하세요. 호출에 필요한 앱 서버용 액세스 토큰은 토큰 발급으로 받습니다. 요청과 응답의 모든 필드는 소모성 상품 영수증 검증을 참조하세요.

요청 필드에는 앱이 보낸 PendingPurchase 값을 아래와 같이 넣습니다.

  • providerId: STEAM
  • axylReceipt: VerifyToken에 담긴 Hive Axyl 서버 발급 영수증
  • productId, price, currency, country, language, serverId, iapPayload, accountUuid, appVersion: Order의 같은 이름 값
  • orderId: OrderId
  • storeTransactionId: StoreTransactionId
  • requestType: 신규 구매를 나타내는 1
Steam 결제는 영수증 검증 시점에 청구됩니다

Hive Axyl 서버는 앱 서버의 영수증 검증 요청을 받으면 Steam에 주문을 확인한 뒤 실제 청구를 진행합니다. 같은 영수증으로 검증 요청을 불필요하게 반복하지 마세요. 응답을 받지 못해 처리 여부를 알 수 없으면 같은 요청을 다시 보내고, 응답의 hiveAxylDuplicated 값으로 이미 처리된 건인지 확인하세요.

11.3. 상품 지급과 지급 완료 응답

앱 서버는 검증 응답을 확인한 뒤 상품을 한 번만 지급하고 그 결과를 앱에 응답하세요. 앱 서버가 해야 할 일은 아래와 같습니다.

  1. 검증 응답의 hiveAxylProductId, hiveAxylPrice, hiveAxylCurrency가 사용자에게 판매한 상품, 금액과 같은지 확인합니다. hiveAxylPurchaseCancelState가 1이면 취소된 결제이므로 지급하지 않습니다.
  2. 앱 서버의 지급 기록에서 이미 지급한 구매인지 확인합니다. hiveAxylDuplicated가 true이면 반드시 확인해야 합니다. 이미 지급한 구매라면 3번을 건너뜁니다.
  3. 상품을 지급하고 지급 완료를 기록합니다.
  4. 앱에 지급 완료로 응답합니다. 이미 지급한 구매도 지급 완료로 응답해야 앱이 12단계에서 거래를 종료합니다. 13단계의 지급 결과 기록에 쓰도록 검증 응답의 hiveAxylTransactionId도 함께 돌려줍니다.

지급 대상은 검증 응답의 hiveAxylPayload로 판단하세요. 6단계에서 전달한 iapPayload가 그대로 돌아오는 값입니다.

앱이 보낸 값만 믿고 지급하지 마세요

앱 서버는 요청한 사용자의 계정을 직접 인증하고, 상품과 금액은 검증 응답으로 확인하세요. 앱이 만드는 PurchaseDeliveryConfirmation은 결제를 증명하는 값이 아닙니다. 지급 여부는 언제나 앱 서버가 판단합니다.

12. 거래 종료

  • 레시피 코드  레시피 코드를 앱에서 호출합니다.

앱 서버가 지급 완료로 응답한 뒤에 ClosePurchaseAsync()를 호출하세요. 11단계에서 만든 delivery가 없으면 레시피는 거래를 종료하지 않고 Failure를 돌려줍니다.

ClosePurchaseOutcome closed = await recipe.ClosePurchaseAsync(
    prepared.Pending,   // 10단계가 돌려준 값
    delivery,           // 11단계에서 앱 서버의 지급 완료 응답으로 만든 값
    token);

if (closed.Status == ClosePurchaseStatus.Success)
{
    // 구매가 끝났으므로 저장한 구매 정보를 지웁니다.
    await pendingStore.DeleteAsync(prepared.Pending);
}
else
{
    // 검증과 지급은 이미 끝났고 구매만 열려 있는 상태입니다.
    // 저장한 구매 정보를 그대로 두고 다시 호출하거나 미지급 구매 복구에서 마무리합니다.
}

Steam 결제는 기기가 아니라 Hive Axyl 서버에서 거래를 종료하므로 스토어 플러그인을 호출하지 않습니다. 레시피가 내부에서 수행하는 작업은 아래와 같습니다.

구분 호출 확인할 곳
Hive Axyl SDK FinalizePurchaseAsync()로 서버에 구매 완료 처리 요청 구매 완료 처리

13. 지급 결과 기록

  • Hive Axyl SDK  Hive Axyl SDK를 앱에서 호출합니다.

    스토어 플러그인  스토어 결제 플러그인을 앱에서 호출합니다.


    상세 절차: 상품 지급 결과 저장

지급이 끝나면 그 결과를 Hive Axyl 서버에 기록하세요. 이 호출은 결제를 확정하거나 지급 여부를 결정하지 않고 운영용 기록만 남깁니다. AxylTransactionId에는 11.1의 VerifyAndGrantOnceAsync()가 앱 서버 응답에서 따로 보관한 hiveAxylTransactionId를 넣으세요.

using Hive.Axyl.Payments;

var payments = HiveCore.Resolve<IPaymentsService>();

await payments.ItemResultAsync(new ItemResultBody
{
    AxylTransactionId = axylTransactionId,   // 11.1에서 앱 서버 응답으로 받아 따로 보관한 hiveAxylTransactionId
    Status = 1,   // 1: 지급 성공
    Assets = new[]
    {
        new ItemResultAsset { AssetId = "gold", AssetName = "골드", Quantity = 100 },
    },
});

결제 화면을 닫고 더 이상 승인 콜백이 필요하지 않으면 7단계에서 등록한 onResponse를 MicroTxnAuthorizationResponse에서 -=로 해제하고, 스토어 플러그인의 콜백 수신도 해제하세요. 방법은 Steam 콜백 수신 해제를 참조하세요.

14. 구매 내역 확인

  • Hive 콘솔  Hive 콘솔에서 설정하거나 확인합니다.

    Hive Axyl 서버 API  앱 서버에서 Hive Axyl 서버 API를 호출합니다.

운영 중에는 구매 내역을 조회해 결제 상태와 지급 상태를 확인하세요.

구분 방법 확인할 곳
Hive 콘솔 콘솔에서 조회 조건을 지정해 확인 조회 조건 지정
Hive Axyl 서버 API 앱 서버에서 구매 내역 조회 API 호출 구매 내역 조회

실패 처리

레시피 메서드는 예외를 던지지 않고 결과 객체를 돌려줍니다. 언제나 Status부터 확인하세요.

Status 의미 앱이 할 일
Success 해당 단계가 정상적으로 끝났습니다. 다음 단계로 진행합니다.
BusinessOutcome Hive Axyl 서버나 마켓이 요청을 거절했습니다. BusinessOutcome 값에 따라 분기합니다. 값별 대응 방법은 결제 레시피의 거절 사유를 참조하세요.
Failure 네트워크 오류나 타임아웃 같은 기술적 실패입니다. Error를 기록하고 재시도 여부를 판단합니다.
UserCanceled SDK가 결제를 취소로 보고했습니다. 오류가 아니므로 상점으로 돌아갑니다.

UserCanceled는 구매를 시작하는 단계에만 있습니다. 준비와 종료 단계의 결과 타입에는 없으므로 그 값으로 분기하면 컴파일되지 않습니다.

실패해도 PendingPurchase를 버리지 마세요

PreparePurchaseOutcome과 ClosePurchaseOutcome은 실패할 때도 전달받은 Pending을 그대로 돌려줍니다. 돌아온 Pending으로 8단계에서 저장한 구매 정보를 교체해 두어야 나중에 그 구매를 마무리할 수 있습니다. 11단계에서 앱 서버가 지급을 확인하지 못한 경우에도 구매 정보를 그대로 두세요. 저장한 구매 정보는 거래 종료에 성공한 뒤에만 지우세요.

다음 단계

결제는 끝났지만 지급이 마무리되지 않은 구매를 처리하려면 Steam 미지급 구매 복구를 참조하세요.