3단계. 상품 구매
사용자가 선택한 상품의 결제 페이지 URL을 생성하고 외부 브라우저에서 결제를 진행합니다. 사용자가 앱으로 돌아온 뒤 미지급 주문을 조회하여 결제 결과와 영수증 데이터를 확인합니다.
아래 과정을 따라 PG 상품 구매를 진행합니다.
1. 인앱 상점 UI 노출
앱에서 인앱 상점 UI를 구현하고 사용자에게 노출합니다. 사용자가 상품을 선택하면 결제 버튼을 누를 수 있도록 합니다. 사용자가 결제 버튼을 누르면 다음 단계로 진행합니다.
2. 선택: 구매 사전 정보 저장
사용자가 결제 버튼을 누른 뒤 결제 페이지를 열기 전에 구매 시도 정보를 저장합니다. 전체 흐름은 구매 정보 기록을 참조하세요. 이 단계는 선택 사항입니다.
CreatePrePurchaseAsync
CreatePrePurchaseAsync()는 상품, 결제 예정 금액, 통화, 국가와 언어, 앱 서버, IapPayload를 사전 구매 추적 레코드로 저장합니다.
호출 파라미터
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
| request | PrePurchase | Required | 구매 사전 정보 저장 요청 데이터 객체입니다. |
| context | ApiCallContext | Optional | 호출 단위 설정 객체입니다. 멱등키·취소 토큰·요청 정책을 지정하며, 생략하면 기본값이 사용됩니다. |
PrePurchase
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
Country | string | Required | 국가 코드 (ISO 3166-1 두 자리) |
Currency | string | Required | 결제 통화 (ISO 4217 세 자리) |
Language | string | Required | 언어 코드 (ISO 639-1 두 자리) |
Price | decimal | Required | 결제 예정 금액입니다. 통화에 따라 소수점이 포함될 수 있습니다. |
ProductId | string | Required | 마켓에 등록된 인앱 상품 ID |
ProviderId | PrePurchaseProviderId | Required | 마켓·결제 수단 식별자(enum)입니다. PG 결제 전용 요청이므로 Pg만 지정합니다. |
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.Pg,
ServerId = "server01",
RequestDate = DateTimeOffset.UtcNow
};
PaymentsCreatePrePurchaseResult result = await payments.CreatePrePurchaseAsync(request);
switch (result)
{
case PaymentsCreatePrePurchaseResult.Success success:
// 사전 저장 성공. 반환 데이터는 없습니다. 결제 페이지 URL 생성을 진행하세요.
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;
}
응답 데이터
성공 시 별도 반환 데이터는 없습니다.
응답 예시
응답 상태
아래 표에는 PaymentsCreatePrePurchaseResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)를 정리했습니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요. 성공 시 별도의 반환 데이터는 없습니다.
| 응답 케이스 | 설명 | 앱 클라이언트 대응 |
|---|---|---|
Success | 사전 저장 성공 | 결제 페이지 URL 생성 진행 |
PaymentBadRequest | 결제 요청을 처리할 수 없습니다. | 요청 값과 호출 조건을 점검 |
PaymentInvalidParameter | 결제 요청 파라미터가 유효하지 않습니다. | 요청 필드 값을 점검 |
UnknownOutcome | SDK가 알 수 없는 도메인별 결과입니다. | 실패로 처리하고 결과 코드를 기록 |
Failure | 공통 Failure입니다. 공통 오류 처리를 참조하세요. | 공통 오류 처리 기준에 따라 처리 |
3. 결제 페이지 URL 생성
주문 정보를 기반으로 사용자가 접근할 수 있는 결제 페이지 URL을 생성합니다. 생성된 URL을 외부 브라우저로 열면 Hive Axyl이 제공하는 결제 수단 선택 페이지가 노출됩니다.
사용자는 이 페이지에서 실제 PG 결제 수단을 선택하고 결제를 진행합니다.
CreatePaymentUrlAsync
결제 페이지 URL 생성을 구현하려면 Hive Axyl SDK가 제공하는 CreatePaymentUrlAsync()를 호출하세요. 주문 정보를 바탕으로 사용자가 접근할 수 있는 결제 페이지 URL을 생성해 반환합니다.
호출 파라미터
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
| request | OrderRequest | Required | 주문(결제 페이지 생성) 요청 데이터입니다. |
| context | ApiCallContext | Optional | 호출 단위 설정 객체입니다. 멱등키·취소 토큰·요청 정책을 지정하며, 생략하면 기본값이 사용됩니다. |
OrderRequest
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
AppVersion | string | Optional | 앱 버전입니다. |
Country | string | Required | 국가 코드입니다(ISO 3166-1 두 자리). |
Language | string | Required | 언어 코드입니다(ISO 639-1 두 자리). 결제 수단 이름의 다국어 표시에 사용합니다. |
Os | OrderRequestOs (enum) | Required | 앱 클라이언트가 실행 중인 OS입니다. Windows, Macos, Android, Ios 중 빌드 대상에 맞는 값을 지정합니다. |
ProductId | string | Required | 마켓에 등록된 인앱 상품 PID입니다. |
Quantity | int | Required | 구매 수량입니다. 1부터 999까지 지정할 수 있습니다. |
ServerId | string | Optional | Hive 콘솔 앱 서버를 따라 앱 정보 > 앱 서버에서 앱 서버를 등록한 뒤 앱 서버 탭에서 확인하는 서버 ID입니다. |
ProviderId | OrderRequestProviderId | Required | 결제 제공자입니다. PG 결제 전용 요청이므로 Pg만 지정합니다. |
CustomPrice | string | Optional | 사용자 정의 결제 금액입니다. 상품 PID에 설정된 금액 대신 앱 서버가 지정한 금액으로 결제를 요청할 때 사용하며, FixedCurrency·GameServerPriceVerifyKey와 반드시 함께 사용합니다. |
FixedCurrency | string | Optional | 결제 수단에 표시할 통화입니다(ISO 4217 세 자리). 사용자 정의 금액(CustomPrice) 결제 사용 시 필수입니다. |
GameServerPriceVerifyKey | string | Optional | 앱 서버 결제 금액 검증 키입니다. 사용자 정의 금액 결제의 금액 변조를 막기 위해 앱 서버가 발급하며, CustomPrice 사용 시 필수입니다. |
IapPayload | string | Optional | 앱 서버로 전달할 개발자 정의 메타데이터입니다(JSON 문자열). 구매 완료 후 앱 서버 콜백에 그대로 전달됩니다. |
호출 예시
PaymentsCreatePaymentUrlResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)는 아래 예시와 응답 상태에서 확인합니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.
using Hive.Axyl.Payments;
using Hive.Axyl.Core;
// payments: 초기화 시 등록된 IPaymentsService (자세한 획득은 [모듈 설치 및 초기화](../init.md) 참고)
IPaymentsService payments = HiveCore.Resolve<IPaymentsService>();
var request = new OrderRequest
{
AppVersion = "1.0.0",
Country = "KR",
Language = "ko",
Os = OrderRequestOs.Android,
ProductId = "com.example.game.gold100",
Quantity = 1,
ServerId = "server01",
ProviderId = OrderRequestProviderId.Pg
};
PaymentsCreatePaymentUrlResult result = await payments.CreatePaymentUrlAsync(request);
switch (result)
{
case PaymentsCreatePaymentUrlResult.Success success:
// 결제 페이지 URL 생성 성공. PayUrl을 열어 결제 페이지 표시
Debug.Log($"payUrl: {success.Data.PayUrl}");
break;
case PaymentsCreatePaymentUrlResult.PaymentBadRequest:
case PaymentsCreatePaymentUrlResult.PaymentInvalidParameter:
Debug.LogError("요청 필드와 필수값을 확인하세요.");
break;
// 공통 Failure 처리
case PaymentsCreatePaymentUrlResult.Failure failure:
HiveError err = failure.Problem;
Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
break;
// 안전망: 처리하지 않은 결과 및 알 수 없는 신규 결과(UnknownOutcome)
default:
Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
break;
}
응답 데이터
성공 시 PaymentsCreatePaymentUrlResult.Success의 Data(OrderPayUrlResponseData)에 결과가 담깁니다.
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
Data.PayUrl | string | Optional | 결제 페이지 URL입니다. |
Data.CreatedAt | DateTimeOffset | Optional | 생성 일시입니다. |
Data.Meta | string? | Optional | 응답 메타 정보입니다. |
응답 예시
응답 상태
아래 표에는 PaymentsCreatePaymentUrlResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)를 정리했습니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.
| 응답 케이스 | 설명 | 앱 클라이언트 대응 |
|---|---|---|
Success | 결제 페이지 URL이 생성되었습니다. | Data.PayUrl을 열어 사용자에게 결제 페이지 표시 |
PaymentBadRequest | 요청을 처리할 수 없습니다. | 요청 값과 호출 조건을 점검 |
PaymentInvalidParameter | 유효하지 않은 파라미터입니다. | 요청 필드를 점검 후 재요청 |
UnknownOutcome | SDK가 알 수 없는 도메인별 결과입니다. | 실패로 처리하고 결과 코드를 기록 |
Failure | 공통 Failure입니다. 공통 오류 처리를 참조하세요. | 공통 오류 처리 기준에 따라 처리 |
4. 결제 진행
생성한 결제 페이지 URL을 외부 브라우저에서 열어 사용자가 결제하도록 합니다. 사용자는 이 페이지에서 신용카드, 소액 결제 등 결제 수단을 선택한 뒤 PG 결제를 완료합니다.
PG 결제는 외부 브라우저에서 진행되므로, 스토어 결제와 달리 앱이 결제 완료 사실을 바로 전달받지 못합니다. 사용자가 결제를 마치고 앱으로 돌아오면 구매 완료를 알리는 UI를 노출하고, 미지급 주문을 조회한 뒤 앱 서버에 영수증 검증을 요청해 결제 결과를 확인하세요.
5. 선택: 결제 결과 데이터 저장
사용자가 결제를 마치고 앱으로 돌아온 뒤 결제 완료 정보 조회로 확인한 영수증과 거래 정보를 저장합니다. 영수증 검증 전에 결제 사실을 보관하므로, 이후 처리가 중단되어도 검증, 상품 지급, 고객 지원과 정산에 사용할 수 있습니다. 전체 흐름은 구매 정보 기록을 참조하세요. 이 단계는 선택 사항입니다.
RecordStorePurchaseAsync
RecordStorePurchaseAsync()는 영수증, 거래 ID 등 결제 결과를 Hive Axyl 서버에 저장합니다.
호출 파라미터
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
| request | PurchaseRequest | Required | 결제 결과 저장 요청 데이터 객체입니다. |
| context | ApiCallContext | Optional | 호출 단위 설정 객체입니다. 멱등키·취소 토큰·요청 정책을 지정하며, 생략하면 기본값이 사용됩니다. |
PurchaseRequest
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
AccountUuid | string | Optional | 로그인한 사용자의 playerId로 생성한 UUIDv5 값입니다. 결제 결과를 기록할 때 전달합니다. 결제 시작 단계에 전달한 경우 같은 값을 사용하세요. AccountUuid 생성을 참조하세요. |
AxylReceipt | string | Required | Hive Axyl 서버가 발급한 봉인 영수증입니다. 결제 완료 정보 조회가 반환한 AxylReceipt를 값 그대로 전달합니다. |
Country | string | Required | 국가 코드(ISO 3166-1 두 자리)입니다. 예: KR |
Currency | string | Optional | 결제 통화(ISO 4217 세 자리)입니다. Price와 짝을 이뤄 서버가 기록한 값과 대조하는 데 사용합니다. 둘 중 하나만 보내면 통화는 대조하지 않고 금액만 대조합니다. |
IapPayload | string | Optional | 개발자가 마켓 결제 시 첨부한 페이로드(JSON 문자열). 앱 서버 검증과 구매 완료 콜백에 그대로 전달됩니다. |
Language | string | Required | 언어 코드(ISO 639-1 두 자리)입니다. 예: ko |
OrderId | string | Optional | Hive Axyl 내부 주문 번호입니다. |
Price | decimal | Optional | 결제 금액입니다. 통화에 따라 소수점이 포함될 수 있습니다. 보내면 서버가 기록한 금액과 대조하고, 생략하면 대조하지 않습니다. PG 결제는 금액이 다르면 요청을 거절합니다. 결제 내역에 남는 금액은 서버가 보관한 주문 정보의 값입니다. |
ProductId | string | Required | 마켓에 등록한 인앱 상품 ID입니다. PG 결제는 서버에 저장된 주문 정보를 기준으로 처리하므로 이 값을 대조에 사용하지 않습니다. |
ProjectInfo | string | Optional | 앱별 자유 형식 JSON 문자열입니다. 값은 저장만 하며 앱 서버로 전달하지 않습니다. 앱 서버로 전달할 값은 IapPayload에 설정하세요. |
ProviderId | PurchaseRequestProviderId | Required | PG 결제 결과 저장 전용 요청이므로 Pg를 지정합니다. |
Quantity | int | Optional | 구매 수량 |
RequestDate | DateTimeOffset | Optional | 클라이언트 요청 시각(UTC)입니다. 생략하면 서버의 현재 시각을 사용합니다. |
RequestType | int | Optional | 요청 유형입니다. 1: 신규 구매, 2: 구매 복원 |
ServerId | string | Optional | Hive 콘솔 앱 서버를 따라 등록한 앱 서버 ID입니다. |
StoreTransactionId | string | Optional | PG 스토어 거래 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 = axylReceipt, // 미지급 주문 조회가 반환한 봉인 영수증
ProviderId = PurchaseRequestProviderId.Pg,
ProductId = "com.game.item.gold_100",
Price = 1200.0m,
Currency = "KRW",
Country = "KR",
Language = "ko",
Quantity = 1,
StoreTransactionId = "imp_448280090638",
RequestType = 1, // 1: 신규 구매
RequestDate = DateTimeOffset.UtcNow,
ServerId = "server01"
};
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 | 응답 메타 정보 |
응답 예시
응답 상태
아래 표에는 PaymentsRecordStorePurchaseResult의 성공 결과와 이 메서드에서 정의한 도메인별 결과(Outcome)를 정리했습니다. 요청 수행이 불가능한 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.
| 응답 케이스 | 설명 | 앱 클라이언트 대응 |
|---|---|---|
Success | 결제 결과 저장 성공 | 앱 서버에 영수증 정보를 전달해 영수증 검증 단계로 진행 |
PaymentBadRequest | 결제 요청을 처리할 수 없습니다. | 요청 값과 호출 조건을 점검 |
PaymentInvalidParameter | 결제 요청 파라미터가 유효하지 않습니다. | AxylReceipt 등 요청 필드를 점검 |
PaymentResourceNotFound | 저장할 결제 정보를 찾을 수 없습니다. | 영수증과 거래 정보를 점검 |
PaymentUnauthorized | 결제 요청 권한이 없습니다. | 앱과 인증 상태를 점검 |
VerifyError | 결제 검증 중 오류가 발생했습니다. | 영수증과 마켓 결제 상태를 점검 |
UnknownOutcome | SDK가 알 수 없는 도메인별 결과입니다. | 실패로 처리하고 결과 코드를 기록 |
Failure | 공통 Failure입니다. 공통 오류 처리를 참조하세요. | 공통 오류 처리 기준에 따라 처리 |
다음 단계
4단계. 영수증 검증을 진행합니다.