결제 API
'결제'에서 앱 서버가 직접 호출하는 Hive Axyl Server API를 설명합니다. 앱 서버가 결제 영수증을 마켓에 다시 확인하는 영수증 검증 API와, 결제 제공자별 구매 내역을 조회하는 API가 있습니다.
소모성 상품 영수증 검증
POST /payment/v1/purchase/verify
소모성 상품의 결제 영수증을 Apple App Store, Google Play, Steam, PG의 공식 API로 다시 확인합니다. 위·변조된 영수증이나 실제 결제가 없는 요청으로 상품이 부정 지급되는 것을 막는 단계이며, 이 검증을 통과한 경우에만 상품을 지급합니다. Steam 결제는 서버가 이 API를 처리하면서 Steam에 주문을 확인한 뒤 실제 청구를 진행하므로, 이 API를 호출하는 시점에 확정됩니다.
영수증 검증은 이 API로만 요청합니다. 앱 클라이언트가 결제 후 영수증 정보를 앱 서버에 전달하면, 앱 서버가 이 API를 호출하고 검증 결과에 따라 상품을 지급합니다. 결제 제공자별 구현 절차는 Apple 소모성 상품 영수증 검증, Google Play 소모성 상품 영수증 검증, Steam 소모성 상품 영수증 검증, PG 소모성 상품 영수증 검증을 참조하세요.
API 호출 전 준비
- 호출 주체:
앱 서버 - 기본 URL
- 운영:
https://commerce-api.hiveaxyl.com - 샌드박스:
https://sandbox-commerce-api.hiveaxyl.com
- 운영:
- 인증:
Authorization: Bearer {access-token}
Warning
인증 헤더에는 토큰 발급으로 받은 앱 서버용 토큰을 넣습니다. 액세스 토큰과 토큰 발급에 사용하는 Client Secret은 앱 서버에서만 보관하고 앱 클라이언트에 포함하지 마세요.
호출 Parameters
| 이름 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
X-App-Id | header | string | true | Hive 콘솔에 등록한 App ID입니다. |
X-SDK-Version | header | string | false | 클라이언트 SDK 버전 정보입니다. |
X-Platform | header | string | false | 플랫폼 정보입니다. |
X-OS-Version | header | string | false | 운영 체제 버전 정보입니다. |
Accept-Language | header | string | false | 클라이언트 언어 설정입니다. |
traceparent | header | string | false | 분산 추적을 위한 W3C Trace Context 헤더입니다. |
User-Agent | header | string | false | 클라이언트 애플리케이션의 User-Agent 정보입니다. |
| body | body | PurchaseVerifyRequest | true | 영수증 검증 요청 정보입니다. |
요청 본문 PurchaseVerifyRequest
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
accountUuid | string(uuid) | true | 로그인한 사용자를 이 구매 기록에 연결하는 값입니다. AccountUuid 생성에서 앱 클라이언트가 만든 값을 넣으세요. 결제한 사용자와 검증을 요청한 사용자가 같은지 확인하는 데 사용하며, UUID 형식이어야 합니다. |
appVersion | string | false | 앱 버전입니다. 생략하면 X-SDK-Version 헤더 값이 저장됩니다. 앱 서버는 이 헤더를 보내지 않으므로, 앱 버전을 기록하려면 이 필드로 전달하세요. |
axylReceipt | string | true | 구매 영수증입니다. 마켓마다 넣는 값이 다르므로 마켓별 요청 값을 참조하세요. |
country | string | false | 국가 코드입니다. ISO 3166-1 두 자리 형식을 사용합니다. |
currency | string | false | 결제 통화입니다. ISO 4217 세 자리 형식을 사용합니다. price와 짝을 이뤄 서버가 가진 결제 정보와 대조하는 데 사용합니다. 둘 중 하나만 보내면 통화는 대조하지 않고 금액만 대조합니다. |
iapPayload | string | false | 앱이 정의하는 페이로드입니다. 보낸 값이 그대로 저장되고 응답의 hiveAxylPayload로 반환됩니다. |
language | string | false | 언어 코드입니다. ISO 639-1 두 자리 형식을 사용합니다. |
orderId | string | false | 주문 번호입니다. 서버는 storeTransactionId, orderId, axylReceipt 순서로 주문을 찾습니다. |
price | number | false | 결제 금액입니다. 통화에 따라 소수점이 포함됩니다. 보내면 서버가 가진 결제 금액과 대조하고, 생략하면 대조하지 않습니다. 금액이 다를 때의 처리는 마켓마다 다릅니다. 결제 내역에는 이 값이 아니라 서버가 마켓 검증 결과나 주문 정보에서 확인한 금액이 저장됩니다. |
productId | string | true | 마켓에 등록한 인앱 상품 ID입니다. |
projectInfo | object | false | 앱별로 자유롭게 정의하는 추가 데이터입니다. 저장만 하고 응답으로 돌려주지 않으므로, 응답으로 값을 돌려받으려면 iapPayload를 사용하세요. |
providerId | string | true | 마켓 구분입니다. APPLE, GOOGLE, STEAM, PG 중 하나를 지정합니다. |
requestType | integer | true | 요청 유형입니다. 1은 신규 구매, 2는 구매 복원이며 두 값만 허용합니다. |
serverId | string | false | Hive 콘솔 앱 정보 > 앱 서버에 등록한 서버 ID입니다. 자세한 내용은 앱 서버를 참조하세요. |
storeTransactionId | string | false | 스토어 거래 ID입니다. 주문을 찾는 키로 가장 먼저 사용합니다. |
마켓별 요청 값
아래는 마켓에 따라 넣는 값이나 서버의 처리 방식이 달라지는 필드입니다.
providerId:APPLEaxylReceipt: Apple App Store가 발급한 StoreKit 2 거래 JWS 원문. StoreKit 2는 Apple이 iOS와 macOS 앱에 제공하는 인앱 결제 기능 모음이며, 결제가 끝나면 거래 정보를 서명한 문자열인 JWS를 발급합니다. StoreKit 2의jwsRepresentation이 반환하는 값을 헤더, 페이로드, 서명 세 조각 그대로 전달하세요. 앱 클라이언트가 준비하는 방법은 Apple 영수증 정보 준비를 참조하세요.accountUuid: Apple 구매 요청의appAccountToken에 넣은 값과 같은 값을 전달하세요. 서버가 두 값을 대조한 결과는 응답의hiveAxylAccountUuidCompare로 반환됩니다.price: 금액이 다르면PRICE_VERIFY_FAIL로 요청을 거절합니다.storeTransactionId: Apple 거래 ID
providerId:GOOGLEaxylReceipt: Google Play가 발급한purchaseToken문자열.purchase_data와signature를 담은 JSON 문자열도 받으며, 이때purchase_data에는 Google Play Billing Library의getOriginalJson()이 반환한 원문을 그대로 넣으세요. 값을 다시 직렬화하면 서명 검증에 실패합니다. 앱 클라이언트가 준비하는 방법은 Google 영수증 정보 준비를 참조하세요.productId: 구매 토큰에는 상품 정보가 없으므로 반드시 전달하세요. 생략하면INVALID_REQUEST로 응답합니다.accountUuid: Google 구매 요청의ObfuscatedAccountId에 넣은 값과 같은 값을 전달하세요. 서버가 두 값을 대조한 결과는 응답의hiveAxylAccountUuidCompare로 반환됩니다.price: 금액이 달라도 요청을 거절하지 않습니다.storeTransactionId: Google Play 스토어 거래 ID
providerId:STEAMaxylReceipt: Hive Axyl 서버가 발급한 봉인 영수증. 앱 클라이언트가 구매를 시작하거나 복구할 때 응답으로 받은AxylReceipt값을 가공하지 않고 그대로 전달하세요. 서버는 저장된 주문 정보로 영수증을 다시 봉인해 대조하므로, 값이 위·변조되면RECEIPT_VERIFY_FAIL로 응답합니다. 앱 클라이언트가 준비하는 방법은 Steam 영수증 정보 준비를 참조하세요.productId: 서버에 저장된 주문 정보를 기준으로 검증하므로 대조에 사용하지 않습니다.accountUuid: 전달한 값은 결제 내역에 저장되어 어느 사용자의 결제인지 확인하는 근거가 됩니다. Steam은 대조할 결제 측 계정 정보가 없으므로 응답의hiveAxylAccountUuidCompare는 항상9입니다.price: 금액이 달라도 요청을 거절하지 않습니다.orderId,storeTransactionId: 숫자로 이루어진 Steam 주문 번호. 두 값을 모두 보내지 않으면 서버가axylReceipt에서 주문 번호를 꺼내 쓰므로 생략해도 됩니다.
providerId:PGaxylReceipt: Hive Axyl 서버가 발급한 봉인 영수증. 앱 클라이언트가 결제 완료 정보 조회에서 받은 미지급 주문의AxylReceipt값을 가공하지 않고 그대로 전달하세요. 서버는 저장된 주문 정보로 영수증을 다시 봉인해 대조하므로, 값이 위·변조되면RECEIPT_VERIFY_FAIL로 응답합니다.productId: 서버에 저장된 주문 정보를 기준으로 검증하므로 대조에 사용하지 않습니다.accountUuid: 전달한 값은 결제 내역에 저장되어 어느 사용자의 결제인지 확인하는 근거가 됩니다. PG는 대조할 결제 측 계정 정보가 없으므로 응답의hiveAxylAccountUuidCompare는 항상9입니다.price: 금액이 다르면PRICE_VERIFY_FAIL로 요청을 거절합니다.orderId,storeTransactionId:H로 시작하는 PG 주문 번호. 두 값을 모두 보내지 않으면 서버가axylReceipt에서 주문 번호를 꺼내 쓰므로 생략해도 됩니다.
호출 예시
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/purchase/verify' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "APPLE",
"requestType": 1,
"axylReceipt": "{apple-transaction-jws}",
"productId": "com.game.item.gold_100",
"price": 1200,
"currency": "KRW",
"accountUuid": "123e4567-e89b-12d3-a456-426614174000",
"storeTransactionId": "2000000123456789",
"iapPayload": "iap_payload_data"
}'
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/purchase/verify' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "GOOGLE",
"requestType": 1,
"axylReceipt": "{google-purchase-token}",
"productId": "com.game.item.gold_100",
"price": 1200,
"currency": "KRW",
"accountUuid": "123e4567-e89b-12d3-a456-426614174000",
"storeTransactionId": "GPA.3389-9543-8198-17604",
"iapPayload": "iap_payload_data"
}'
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/purchase/verify' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "STEAM",
"requestType": 1,
"axylReceipt": "{steam-axyl-receipt}",
"productId": "com.game.item.gold_100",
"price": 1200,
"currency": "KRW",
"accountUuid": "123e4567-e89b-12d3-a456-426614174000",
"storeTransactionId": "421799706624185538",
"iapPayload": "iap_payload_data"
}'
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/purchase/verify' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "PG",
"requestType": 1,
"axylReceipt": "{pg-axyl-receipt}",
"productId": "com.game.item.gold_100",
"price": 1200,
"currency": "KRW",
"accountUuid": "123e4567-e89b-12d3-a456-426614174000",
"storeTransactionId": "H517815844374710159",
"iapPayload": "iap_payload_data"
}'
응답
공통 data, meta, 오류 본문, 제품 공통 오류 코드, 영수증 검증 outcome.message 값은 결제 응답 및 오류를 참조하세요. 이 섹션에서는 이 API가 실제로 반환하는 객체와 API별 처리 방법을 설명합니다.
성공 응답 data 객체
| 필드 | 타입 | 설명 |
|---|---|---|
data.hiveAxylAccountUuidCompare | integer | 요청의 accountUuid와 마켓이 알려준 구매 계정 식별자를 대조한 결과입니다. 1은 일치, 2는 불일치, 9는 대조 불가입니다. 2가 반환되면 앱의 보안 정책에 따라 처리하며 Hive Axyl이 결제나 상품 지급을 자동으로 차단하지는 않습니다. 9는 불일치가 아닙니다. Steam과 PG는 항상 9입니다. |
data.hiveAxylCurrency | string 또는 null | 검증된 결제 통화입니다. ISO 4217 세 자리 형식입니다. |
data.hiveAxylDuplicated | boolean | 영수증 검증 중복 여부입니다. true이면 이미 검증한 영수증이라 새 검증 기록을 만들지 않고 기존 결과를 그대로 반환한 경우입니다. |
data.hiveAxylGameServerPriceVerifyKey | string 또는 null | 앱 서버 결제 금액 검증 키입니다. 사용자 정의 금액으로 결제한 경우 앱 서버가 발급한 검증 키가 그대로 반환됩니다. |
data.hiveAxylPayload | string 또는 null | 요청의 iapPayload 값이 그대로 반환됩니다. |
data.hiveAxylPrice | number 또는 null | 검증된 결제 금액입니다. 현지 통화 기준이며 통화에 따라 소수점이 포함됩니다. |
data.hiveAxylProductId | string | 마켓에 등록된 인앱 상품 ID입니다. |
data.hiveAxylProviderId | string | 마켓 구분입니다. APPLE, GOOGLE, STEAM, PG 중 하나입니다. |
data.hiveAxylProviderTransactionId | string | 마켓 측 거래 ID입니다. Apple은 transactionId, Google과 Steam은 orderId 값입니다. |
data.hiveAxylPurchaseCancelState | integer | 결제 취소 상태입니다. 0은 정상, 1은 취소된 결제입니다. |
data.hiveAxylPurchaseTest | string | 테스트 결제 여부입니다. N은 실제 결제, Y는 테스트 결제입니다. Apple은 검증 결과의 environment가 Sandbox일 때, Google은 구매 유형이 테스트 구매일 때, Steam과 PG는 서버의 샌드박스 설정에 따라 Y가 됩니다. |
data.hiveAxylQuantity | integer | 구매 수량입니다. |
data.hiveAxylReceipt | string | 요청에 보낸 axylReceipt를 서버가 가공하지 않고 그대로 반환한 값입니다. |
data.hiveAxylReceiptVerifyResult | object 또는 null | 마켓 영수증 검증의 원본 결과 객체입니다. 앱 서버에서 추가 검증이 필요할 때 사용합니다. Apple 결과의 날짜 필드는 모두 Unix epoch 밀리초입니다. Steam은 항상 null입니다. |
data.hiveAxylStoreTransactionId | string 또는 null | 스토어 거래 ID입니다. Apple은 transactionId, Google은 orderId 값입니다. Steam은 hiveAxylProviderTransactionId와 다른 값이 반환됩니다. |
data.hiveAxylTransactionId | string | Hive Axyl 결제 트랜잭션 ID입니다. 접두사와 번호를 밑줄로 이은 형식입니다. 앱 클라이언트가 ItemResultAsync로 상품 지급 결과를 저장할 때 axylTransactionId로 사용하므로, 앱 서버는 이 값을 앱 클라이언트에 돌려주세요. |
응답 예시
{
"data": {
"hiveAxylAccountUuidCompare": 1,
"hiveAxylCurrency": "KRW",
"hiveAxylDuplicated": false,
"hiveAxylGameServerPriceVerifyKey": "verify-key-001",
"hiveAxylPayload": "iap_payload_data",
"hiveAxylPrice": 1200,
"hiveAxylProductId": "com.game.item.gold_100",
"hiveAxylProviderId": "APPLE",
"hiveAxylProviderTransactionId": "2000000123456789",
"hiveAxylPurchaseCancelState": 0,
"hiveAxylPurchaseTest": "N",
"hiveAxylQuantity": 1,
"hiveAxylReceipt": "{apple-transaction-jws}",
"hiveAxylReceiptVerifyResult": { ... },
"hiveAxylStoreTransactionId": "2000000123456789",
"hiveAxylTransactionId": "{axyl-transaction-id}"
},
"meta": null
}
{
"data": {
"hiveAxylAccountUuidCompare": 1,
"hiveAxylCurrency": "KRW",
"hiveAxylDuplicated": false,
"hiveAxylGameServerPriceVerifyKey": "verify-key-001",
"hiveAxylPayload": "iap_payload_data",
"hiveAxylPrice": 1200,
"hiveAxylProductId": "com.game.item.gold_100",
"hiveAxylProviderId": "GOOGLE",
"hiveAxylProviderTransactionId": "GPA.3389-9543-8198-17604",
"hiveAxylPurchaseCancelState": 0,
"hiveAxylPurchaseTest": "N",
"hiveAxylQuantity": 1,
"hiveAxylReceipt": "{google-purchase-token}",
"hiveAxylReceiptVerifyResult": { ... },
"hiveAxylStoreTransactionId": "GPA.3389-9543-8198-17604",
"hiveAxylTransactionId": "{axyl-transaction-id}"
},
"meta": null
}
{
"data": {
"hiveAxylAccountUuidCompare": 9,
"hiveAxylCurrency": "KRW",
"hiveAxylDuplicated": false,
"hiveAxylGameServerPriceVerifyKey": "verify-key-001",
"hiveAxylPayload": "iap_payload_data",
"hiveAxylPrice": 1200,
"hiveAxylProductId": "com.game.item.gold_100",
"hiveAxylProviderId": "STEAM",
"hiveAxylProviderTransactionId": "2026010100001",
"hiveAxylPurchaseCancelState": 0,
"hiveAxylPurchaseTest": "N",
"hiveAxylQuantity": 1,
"hiveAxylReceipt": "{steam-axyl-receipt}",
"hiveAxylReceiptVerifyResult": null,
"hiveAxylStoreTransactionId": "421799706624185538",
"hiveAxylTransactionId": "{axyl-transaction-id}"
},
"meta": null
}
{
"data": {
"hiveAxylAccountUuidCompare": 9,
"hiveAxylCurrency": "KRW",
"hiveAxylDuplicated": false,
"hiveAxylGameServerPriceVerifyKey": "verify-key-001",
"hiveAxylPayload": "iap_payload_data",
"hiveAxylPrice": 1200,
"hiveAxylProductId": "com.game.item.gold_100",
"hiveAxylProviderId": "PG",
"hiveAxylProviderTransactionId": "{pg-transaction-id}",
"hiveAxylPurchaseCancelState": 0,
"hiveAxylPurchaseTest": "N",
"hiveAxylQuantity": 1,
"hiveAxylReceipt": "{pg-axyl-receipt}",
"hiveAxylReceiptVerifyResult": { ... },
"hiveAxylStoreTransactionId": "H517815844374710159",
"hiveAxylTransactionId": "{axyl-transaction-id}"
},
"meta": null
}
API별 처리 시 유의 사항
hiveAxylDuplicated가 true이면 같은 영수증을 이미 검증한 상태입니다. 이때 반환되는 값은 최초 검증 결과이므로, 같은 상품을 두 번 지급하지 않도록 지급 이력을 확인한 뒤 지급 여부를 결정하세요.
hiveAxylPurchaseCancelState가 1이면 취소된 결제입니다. 이 경우 상품을 지급하지 마세요.
hiveAxylPurchaseTest가 Y이면 테스트 결제입니다. 운영 환경에서 테스트 결제로 상품을 지급할지는 앱의 운영 정책에 따라 결정하세요.
Steam은 이 API를 호출하는 시점에 결제가 확정되므로 같은 영수증으로 불필요하게 반복 호출하지 마세요. 네트워크 오류 등으로 응답을 받지 못해 처리 여부를 알 수 없으면, 같은 요청을 다시 보낸 뒤 응답의 hiveAxylDuplicated가 true인지로 이미 처리된 건인지 확인하세요. Steam은 hiveAxylReceiptVerifyResult가 항상 null이므로 hiveAxylPrice, hiveAxylProductId, hiveAxylQuantity 값으로 지급 내용을 확인하세요.
PG 미지급 주문이 여러 건이면 주문마다 이 API를 한 번씩 호출하세요. 한 번의 요청으로 여러 주문을 검증할 수 없습니다.
응답 상태
| 상태 | 콘텐츠 유형 | 의미 | 응답 헤더 | 응답 본문 또는 처리 |
|---|---|---|---|---|
200 | application/json | 검증 성공 | - | data에 검증 결과가 담깁니다. |
400 | application/problem+json | 요청 오류 또는 결제 제품 오류 | - | - |
500 | application/problem+json | 서버 오류 | - | - |
API별 오류 코드
| 코드 | 발생 조건 | 처리 방법 |
|---|---|---|
app_not_found | X-App-Id의 앱 정보를 찾을 수 없습니다. | 프로젝트 설정 > App ID에서 App ID를 다시 확인하세요. |
구독 상품 영수증 검증
POST /payment/v1/subscription/verify
구독 영수증을 Apple App Store 또는 Google Play에 다시 확인해 구독이 유효한지 검증합니다. 응답에는 구독 만료 시각과 환불 시각이 함께 담기므로, 구독 혜택을 지급할지 회수할지 이 결과로 결정합니다. 구독 결제는 Apple App Store와 Google Play만 지원합니다.
구독 영수증 검증도 이 API로만 요청합니다. 앱 클라이언트가 PurchaseSubscriptionAsync로 구독 구매 정보를 저장한 뒤 영수증 정보를 앱 서버에 전달하면, 앱 서버가 이 API를 호출합니다. 결제 제공자별 구현 절차는 Apple 구독 상품 영수증 검증과 Google Play 구독 상품 영수증 검증을 참조하세요.
API 호출 전 준비
- 호출 주체:
앱 서버 - 기본 URL
- 운영:
https://commerce-api.hiveaxyl.com - 샌드박스:
https://sandbox-commerce-api.hiveaxyl.com
- 운영:
- 인증:
Authorization: Bearer {access-token}
Warning
인증 헤더에는 토큰 발급으로 받은 앱 서버용 토큰을 넣습니다. 액세스 토큰과 토큰 발급에 사용하는 Client Secret은 앱 서버에서만 보관하고 앱 클라이언트에 포함하지 마세요.
호출 Parameters
| 이름 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
X-App-Id | header | string | true | Hive 콘솔에 등록한 App ID입니다. |
X-SDK-Version | header | string | false | 클라이언트 SDK 버전 정보입니다. |
X-Platform | header | string | false | 플랫폼 정보입니다. |
X-OS-Version | header | string | false | 운영 체제 버전 정보입니다. |
Accept-Language | header | string | false | 클라이언트 언어 설정입니다. |
traceparent | header | string | false | 분산 추적을 위한 W3C Trace Context 헤더입니다. |
User-Agent | header | string | false | 클라이언트 애플리케이션의 User-Agent 정보입니다. |
| body | body | SubscriptionPurchaseVerifyRequest | true | 구독 영수증 검증 요청 정보입니다. |
요청 본문 SubscriptionPurchaseVerifyRequest
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
accountUuid | string(uuid) | true | 로그인한 사용자를 이 구독 기록에 연결하는 값입니다. AccountUuid 생성에서 앱 클라이언트가 만든 값을 넣으세요. 자동 갱신 알림에는 사용자 정보가 없으므로, 갱신 시 혜택을 지급할 대상을 찾는 키로도 사용합니다. 요청마다 다른 값을 보내면 자동 갱신이나 구매 복원 때 이전 결제 기록을 찾지 못해 iapPayload를 복원할 수 없습니다. |
appVersion | string | false | 앱 버전입니다. |
axylReceipt | string | true | 구독 구매 영수증입니다. 마켓마다 넣는 값이 다르므로 마켓별 요청 값을 참조하세요. |
country | string | true | 국가 코드입니다. ISO 3166-1 두 자리 형식을 사용합니다. |
currency | string | false | 통화입니다. ISO 4217 세 자리 형식을 사용합니다. |
iapPayload | string | false | 앱이 정의하는 페이로드입니다. 보낸 값이 그대로 저장되고 응답의 hiveAxylPayload로 반환됩니다. |
language | string | true | 언어 코드입니다. ISO 639-1 두 자리 형식을 사용합니다. |
projectInfo | object | false | 앱별 추가 정보입니다. |
providerId | string | true | 마켓 구분입니다. 구독은 APPLE과 GOOGLE만 지원합니다. |
requestType | integer | true | 요청 유형입니다. 1은 신규 구매, 2는 구매 복원이며 두 값만 허용합니다. |
serverId | string | false | Hive 콘솔 앱 정보 > 앱 서버에 등록한 서버 ID입니다. 자세한 내용은 앱 서버를 참조하세요. |
storeTransactionId | string | false | 스토어 거래 ID입니다. 마켓마다 사용 방식이 다르므로 마켓별 요청 값을 참조하세요. |
마켓별 요청 값
아래는 마켓에 따라 넣는 값이나 서버의 처리 방식이 달라지는 필드입니다.
providerId:APPLEaxylReceipt: Apple App Store가 발급한 StoreKit 2 거래 JWS 원문. 헤더, 페이로드, 서명 세 조각으로 이루어진 문자열을 그대로 전달하세요.accountUuid: Apple 구매 요청의appAccountToken에 넣은 값과 같은 값을 전달하세요. 서버가 두 값을 대조한 결과는 응답의hiveAxylAccountUuidCompare로 반환됩니다.storeTransactionId: 거래 JWS를 전달하면 조회 키인originalTransactionId가 영수증 안에 있으므로 생략해도 됩니다. 값을 함께 보내더라도 영수증 안의 값이 우선합니다.
providerId:GOOGLEaxylReceipt: Google Play가 발급한purchaseToken문자열accountUuid: Google 구매 요청의ObfuscatedAccountId에 넣은 값과 같은 값을 전달하세요. 서버가 두 값을 대조한 결과는 응답의hiveAxylAccountUuidCompare로 반환됩니다.storeTransactionId: 전달하지 않아도 됩니다. 서버가 마켓 재검증 결과에서 조회 키를 만들며, 전달하더라도 이 값을 사용하지 않습니다.
호출 예시
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/subscription/verify' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "APPLE",
"axylReceipt": "{apple-transaction-jws}",
"country": "KR",
"language": "ko",
"currency": "KRW",
"accountUuid": "123e4567-e89b-12d3-a456-426614174000",
"requestType": 1,
"serverId": "server01",
"iapPayload": "iap_payload_data"
}'
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/subscription/verify' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "GOOGLE",
"axylReceipt": "{google-purchase-token}",
"country": "KR",
"language": "ko",
"currency": "KRW",
"accountUuid": "123e4567-e89b-12d3-a456-426614174000",
"requestType": 1,
"serverId": "server01",
"iapPayload": "iap_payload_data"
}'
응답
공통 data, meta, 오류 본문, 제품 공통 오류 코드, 영수증 검증 outcome.message 값은 결제 응답 및 오류를 참조하세요. 이 섹션에서는 이 API가 실제로 반환하는 객체와 API별 처리 방법을 설명합니다.
성공 응답 data 객체
| 필드 | 타입 | 설명 |
|---|---|---|
data.hiveAxylAccountUuidCompare | integer | 요청의 accountUuid와 마켓 검증 결과의 계정 식별자를 대조한 결과입니다. 1은 일치, 2는 불일치, 9는 대조 불가입니다. 2가 반환되면 앱의 보안 정책에 따라 처리하며 Hive Axyl이 결제나 혜택 지급을 자동으로 차단하지는 않습니다. 9는 불일치가 아닙니다. |
data.hiveAxylAutoRenewProductId | string 또는 null | 다음 주기에 갱신될 상품 ID입니다. hiveAxylProductId와 다르면 다음 주기에 상품이 바뀌고, 같으면 그대로 갱신됩니다. 자동 갱신이 꺼져 있으면 null입니다. Apple은 renewalInfo.autoRenewProductId 값이고, Google은 예약된 상품 교체가 없으면 현재 상품 ID가 반환됩니다. |
data.hiveAxylCurrency | string 또는 null | 통화 코드입니다. 서버가 마켓에서 받은 값이므로 요청 값과 다를 수 있으며, 마켓에서 통화를 구하지 못하면 null입니다. |
data.hiveAxylDuplicated | boolean | 이미 검증한 영수증이면 true입니다. true여도 검증 자체는 성공이며 중복 저장만 건너뜁니다. |
data.hiveAxylExpiresDate | integer 또는 null | 구독 만료 시각입니다. Unix epoch 밀리초이며, 마켓이 값을 알려주지 않으면 null입니다. |
data.hiveAxylOriginalStoreTransactionId | string 또는 null | 처음 결제한 거래 ID입니다. 이 구독의 모든 주기가 같은 값을 가지므로, hiveAxylStoreTransactionId와 함께 보면 갱신인지 새 구독인지 구분합니다. Apple은 originalTransactionId, Google은 최초 결제의 주문 ID입니다. |
data.hiveAxylPayload | string 또는 null | 요청의 iapPayload 값이 그대로 반환됩니다. |
data.hiveAxylPrice | number 또는 null | 검증된 결제 금액입니다. 서버가 마켓에서 받은 값이며, Apple은 App Store Connect에 설정한 단가, Google은 세금이 포함된 총액이라 두 마켓의 값은 의미가 다릅니다. 마켓에서 금액을 구하지 못하면 null입니다. |
data.hiveAxylProductId | string | 검증된 구독 상품 ID입니다. 마켓 검증 결과를 기준으로 하므로 요청 값과 다를 수 있습니다. |
data.hiveAxylQuantity | integer | 구매 수량입니다. 구독은 수량을 묶어 판매할 수 없으므로 1입니다. |
data.hiveAxylReceiptVerifyResult | object | 마켓 검증 결과 원본입니다. 서버가 마켓에서 받아 정규화한 값 전체이며, 앱 서버에서 추가 판단이 필요할 때 사용합니다. |
data.hiveAxylRefundDate | integer 또는 null | 환불 시각입니다. Unix epoch 밀리초이며, 환불되지 않았으면 null입니다. Google은 마켓이 환불 시각을 알려주지 않으므로 항상 null입니다. |
data.hiveAxylStoreTransactionId | string | 마켓 거래 ID입니다. Apple은 originalTransactionId, Google은 orderId 값이며, 구독 건을 식별하고 대사할 때 사용합니다. |
data.hiveAxylTransactionId | string(uuid) | 검증 기록의 거래 ID입니다. hiveAxylDuplicated가 true이면 최초 검증 때 발급된 값이 그대로 반환됩니다. |
응답 예시
{
"data": {
"hiveAxylAccountUuidCompare": 1,
"hiveAxylAutoRenewProductId": "com.test.sub.monthly",
"hiveAxylCurrency": "KRW",
"hiveAxylDuplicated": false,
"hiveAxylExpiresDate": 1785376709000,
"hiveAxylOriginalStoreTransactionId": "2000000000000001",
"hiveAxylPayload": "iap_payload_data",
"hiveAxylPrice": 1200,
"hiveAxylProductId": "com.test.sub.monthly",
"hiveAxylQuantity": 1,
"hiveAxylReceiptVerifyResult": { ... },
"hiveAxylRefundDate": null,
"hiveAxylStoreTransactionId": "2000000000000001",
"hiveAxylTransactionId": "019fc59f-8340-7656-b91e-3a47d465e594"
},
"meta": null
}
{
"data": {
"hiveAxylAccountUuidCompare": 1,
"hiveAxylAutoRenewProductId": "com.test.sub.monthly",
"hiveAxylCurrency": "KRW",
"hiveAxylDuplicated": false,
"hiveAxylExpiresDate": 1785376709000,
"hiveAxylOriginalStoreTransactionId": "GPA.3301-9758-9251-77321",
"hiveAxylPayload": "iap_payload_data",
"hiveAxylPrice": 1200,
"hiveAxylProductId": "com.test.sub.monthly",
"hiveAxylQuantity": 1,
"hiveAxylReceiptVerifyResult": { ... },
"hiveAxylRefundDate": null,
"hiveAxylStoreTransactionId": "GPA.3389-9543-8198-17604",
"hiveAxylTransactionId": "019fc59f-8340-7656-b91e-3a47d465e594"
},
"meta": null
}
API별 처리 시 유의 사항
hiveAxylRefundDate에 값이 있으면 환불된 구독입니다. 이 경우 구독 혜택을 회수하세요. Google 구독은 hiveAxylRefundDate가 항상 null이므로 이 값으로 환불 여부를 판단하지 마세요. 마켓이 알려준 원본 정보가 필요하면 hiveAxylReceiptVerifyResult를 확인하세요.
hiveAxylExpiresDate는 구독이 만료되는 시각입니다. 이 시각이 지나면 구독 혜택을 유지하지 마세요.
hiveAxylDuplicated가 true이면 이미 검증한 영수증입니다. 검증 자체는 성공이므로 오류로 처리하지 말고, 같은 구독 혜택을 다시 지급하지 않도록 지급 이력을 확인하세요.
응답 상태
| 상태 | 콘텐츠 유형 | 의미 | 응답 헤더 | 응답 본문 또는 처리 |
|---|---|---|---|---|
200 | application/json | 검증 성공 | - | data에 검증된 구독 정보가 담깁니다. |
400 | application/problem+json | 요청 오류 또는 결제 제품 오류 | - | - |
500 | application/problem+json | 서버 오류 | - | - |
구매 내역 조회
POST /payment/v1/transactions
Google Play, Apple App Store, Steam, PG에서 발생한 구매 내역을 조회합니다. 사용자별 구매 이력을 확인해 결제 문의 대응과 운영 확인에 활용하세요. 요청 하나에는 결제 제공자 하나만 지정할 수 있으므로, 여러 결제 제공자의 구매 내역이 필요하면 제공자별로 조회하세요.
검증 처리 시각을 기준으로 최신 항목부터 반환하며, 결과가 많으면 커서를 사용해 다음 페이지를 이어서 조회합니다.
API 호출 전 준비
- 호출 주체:
앱 서버 - 기본 URL
- 운영:
https://commerce-api.hiveaxyl.com - 샌드박스:
https://sandbox-commerce-api.hiveaxyl.com
- 운영:
- 인증:
Authorization: Bearer {access-token}
Warning
인증 헤더에는 토큰 발급으로 받은 앱 서버용 토큰을 넣습니다. 액세스 토큰과 토큰 발급에 사용하는 Client Secret은 앱 서버에서만 보관하고 앱 클라이언트에 포함하지 마세요.
호출 Parameters
| 이름 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
X-App-Id | header | string | true | Hive 콘솔에 등록한 App ID입니다. |
X-SDK-Version | header | string | false | 클라이언트 SDK 버전 정보입니다. |
X-Platform | header | string | false | 플랫폼 정보입니다. |
X-OS-Version | header | string | false | 운영 체제 버전 정보입니다. |
Accept-Language | header | string | false | 클라이언트 언어 설정입니다. |
traceparent | header | string | false | 분산 추적을 위한 W3C Trace Context 헤더입니다. |
User-Agent | header | string | false | 클라이언트 애플리케이션의 User-Agent 정보입니다. |
| body | body | TransactionRequest | true | 구매 내역 조회 조건입니다. |
요청 본문 TransactionRequest
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
cursor | string | false | 다음 페이지를 조회할 때 이전 응답의 meta.page.nextCursor 값을 가공하지 않고 그대로 전달합니다. 첫 페이지에서는 생략하세요. |
endDate | string(date-time) | false | 조회 종료 시각입니다. UTC 기준이며 생략하면 현재 시각을 사용합니다. startDate보다 뒤여야 합니다. |
providerId | string | true | 조회할 결제 제공자입니다. APPLE, GOOGLE, PG, STEAM 중 하나를 지정합니다. |
size | integer | false | 한 페이지에 담을 항목 수입니다. 1부터 100까지 지정하며 기본값은 20입니다. |
startDate | string(date-time) | true | 조회 시작 시각입니다. UTC 기준입니다. |
targetPlayerId | integer(int64) | false | 특정 사용자의 Player ID로 결과를 거릅니다. 앱 서버용 토큰으로 호출할 때만 사용할 수 있으며, 생략하면 인증 토큰의 Player ID를 사용합니다. |
transactionId | string | false | 스토어 구매 번호로 단건을 조회합니다. 응답의 storeTransactionId와 정확히 일치하는 거래를 반환합니다. |
호출 예시
curl -X POST 'https://commerce-api.hiveaxyl.com/payment/v1/transactions' \
-H 'Authorization: Bearer {access-token}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-App-Id: {app-id}' \
-d '{
"providerId": "GOOGLE",
"startDate": "2026-04-16T00:00:00",
"endDate": "2026-05-16T23:59:59",
"size": 20,
"targetPlayerId": 12345
}'
응답
공통 data, meta, 오류 본문, 제품 공통 오류 코드는 결제 응답 및 오류를 참조하세요. 이 섹션에서는 이 API가 실제로 반환하는 객체와 API별 처리 방법을 설명합니다.
성공 응답 data 객체
| 필드 | 타입 | 설명 |
|---|---|---|
data | array | 구매 내역 항목 목록입니다. verifiedDate를 기준으로 최신 항목부터 담깁니다. |
중첩 성공 응답 객체 data[]
| 필드 | 타입 | 설명 |
|---|---|---|
providerId | string | 결제 제공자입니다. APPLE, GOOGLE, PG, STEAM 중 하나입니다. |
purchaseAmount | string | 구매 금액입니다. |
purchaseCurrency | string | 구매 통화입니다. |
purchaseDate | string(date-time) | 구매와 관련된 시각입니다. UTC 기준이며, 어떤 사건의 시각인지는 결제 제공자마다 다릅니다. Apple과 Google은 스토어 결제 시각, PG는 결제 확인 시각, Steam은 주문 생성 시각입니다. Steam의 값은 실제 결제 시각보다 이르므로 정산 대조에 그대로 쓰지 마세요. 값을 확인할 수 없으면 verifiedDate와 같은 값이 담기며, 어떤 사건인지는 purchaseDateSource로 확인합니다. |
purchaseDateSource | string | purchaseDate가 어떤 사건의 시각인지 알려줍니다. STORE_PAYMENT는 스토어 결제 시각, PAYMENT_CONFIRMED는 결제 확인 시각, ORDER_CREATED는 주문 생성 시각, VERIFIED는 실제 구매 시각을 알 수 없어 verifiedDate를 그대로 사용한 경우입니다. |
storeTransactionId | string | 스토어별 구매 번호입니다. Apple은 transactionId, Google과 PG, Steam은 orderId 값입니다. |
transactionId | string(uuid) | Hive Axyl 거래 ID입니다. |
verifiedDate | string(date-time) | 검증 처리 시각입니다. UTC 기준이며 목록 정렬과 커서의 기준값입니다. |
성공 응답 meta 객체
| 필드 | 타입 | 설명 |
|---|---|---|
meta.page.hasNext | boolean | 다음 페이지가 있으면 true입니다. |
meta.page.nextCursor | string 또는 null | 다음 페이지를 조회할 때 사용하는 커서입니다. |
meta.page.hasPrevious | null | 이 API는 이전 페이지 조회를 지원하지 않으므로 항상 null입니다. |
meta.page.previousCursor | null | 이 API는 이전 페이지 조회를 지원하지 않으므로 항상 null입니다. |
API별 오류 추가 객체
400 오류 응답에서는 아래 outcome.message 값으로 실패 원인을 구분합니다.
UNAUTHORIZED_REQUEST: 인증 실패FORBIDDEN_REQUEST: 사용자 로그인 토큰으로 호출하면서targetPlayerId를 지정한 요청INVALID_CURSOR: 올바르지 않은cursor형식CURSOR_CONTEXT_MISMATCH: 페이지를 넘기는 도중 바뀐 조회 조건
응답 예시
{
"data": [
{
"providerId": "GOOGLE",
"purchaseAmount": "1200",
"purchaseCurrency": "KRW",
"purchaseDate": "2026-05-16T12:34:56",
"purchaseDateSource": "STORE_PAYMENT",
"storeTransactionId": "GPA.3312-1234-5678-90123",
"transactionId": "019fc59f-8340-7656-b91e-3a47d465e594",
"verifiedDate": "2026-05-16T12:35:10"
}
],
"meta": {
"page": {
"hasNext": true,
"nextCursor": "{next-cursor}",
"hasPrevious": null,
"previousCursor": null
}
}
}
API별 처리 시 유의 사항
조회 기간은 최대 30일입니다. endDate를 생략해도 이 제한이 적용됩니다. 단, transactionId로 단건을 조회할 때는 기간 제한이 없으므로 오래된 주문도 찾을 수 있습니다.
첫 번째 요청에서는 cursor를 생략합니다. 응답의 meta.page.hasNext가 true이면 meta.page.nextCursor 값을 다음 요청의 cursor에 그대로 넣어 호출하세요. 커서에는 첫 번째 요청의 조회 조건이 함께 담겨 있으므로, 다음 요청에서 providerId나 조회 기간, transactionId, targetPlayerId를 바꾸면 CURSOR_CONTEXT_MISMATCH 오류가 반환됩니다. 조건을 바꾸려면 첫 페이지부터 다시 조회하세요.
이 API는 최신 항목부터 한 방향으로만 조회합니다. 이전 페이지로 돌아가는 커서는 제공하지 않으므로, 앞선 페이지를 다시 확인하려면 첫 페이지부터 조회하세요.
Caution
구매 내역 항목은 결제 금액과 시각, 거래 번호를 알려줍니다. 환불과 취소 여부는 이 응답으로 판단하지 마세요.
응답 상태
| 상태 | 콘텐츠 유형 | 의미 | 응답 헤더 | 응답 본문 또는 처리 |
|---|---|---|---|---|
200 | application/json | 조회 성공 | - | data에 구매 내역 목록이, meta.page에 커서 정보가 담깁니다. |
400 | application/problem+json | 요청 오류 또는 결제 제품 오류 | - | - |
500 | application/problem+json | 서버 오류 | - | - |
API별 오류 코드
| 코드 | 발생 조건 | 처리 방법 |
|---|---|---|
payment_forbidden | 요청이 허용되지 않습니다. | 응답의 outcome.message로 원인을 확인하세요. |