PG 정기 결제¶
'PG 정기 결제'는 사용자가 PG 결제창에서 결제수단을 한 번 등록하면, 앱 서버가 원하는 시점에 해당 결제수단으로 결제를 요청하는 방식입니다. 월정액 상품처럼 같은 상품을 주기적으로 결제할 때 사용합니다.
이 문서는 'PG 정기 결제'의 연동 과정과 앱 서버에서 호출할 API의 사용 방법을 설명합니다. 주요 API는 아래와 같습니다.
- 결제수단 목록 조회: 정기 결제용 결제수단 조회
- 정기 결제 등록: 결제수단 등록과 1회차 결제를 위한 결제창 요청
- 재결제: 등록한 결제수단을 이용한 다음 회차 결제 요청
- 해지: 정기 결제 해지
개요¶
결제 주기와 회차는 앱 서버에서 관리합니다. 앱 서버는 상품의 이용 기간에 맞춰 결제를 요청해야 하며, Hive는 정해진 날짜에 자동으로 결제하지 않습니다.
지원하는 PG와 결제수단은 아래와 같습니다. 이 목록에 없는 PG와 결제수단은 Hive 콘솔에 연결해도 정기 결제용 결제수단 목록에 포함되지 않습니다.
- 카카오페이: 카카오페이 간편결제
- 다날: 신용카드
- 페이먼트월: 해외 신용카드. 등록 시 구매자 이메일 필수
- NHN KCP: 신용카드
연동 흐름¶
앱 서버는 결제수단 조회와 등록을 거쳐 1회차 결제를 진행합니다. 결제가 완료되면 Hive 서버가 앱 서버로 지급 통보를 보내 결제 결과를 알립니다. 앱 서버는 1회차 지급 통보의 order_id를 발급 주문번호로 저장하고, 이후 재결제와 해지 요청에 사용합니다.
앱 서버에서 수행하는 PG 결제 연동 절차는 아래와 같습니다.
- 앱 서버에서 결제수단 목록 조회를 요청해 사용자에게 결제수단을 표시하세요.
- 사용자가 선택한 상품과 결제수단으로 정기 결제 등록을 요청하세요.
- 등록 응답으로 받은 결제창 HTML을 사용자의 웹뷰 또는 브라우저에 표시하세요.
- 사용자가 결제수단을 등록하고 1회차 결제를 완료하면, Hive 서버가 보내는 지급 통보의
order_id를 저장하세요. - 다음 결제 시점에 저장한
order_id와 회차 번호로 재결제를 요청하세요. - 회차별 지급 통보를 기준으로 상품 지급을 처리하세요.
- 정기 결제를 종료할 때 해지를 요청하세요.
2회차 이후의 주문번호는 재결제 응답과 해당 회차의 지급 통보로 전달됩니다. 앱 서버에서 발급 주문번호와 회차별 주문번호를 연결해 관리하세요.
사용자가 결제창을 닫거나 등록에 실패하면 Hive 서버는 지급 통보를 전송하지 않습니다.
사전 준비¶
API를 호출하기 전에 Hive 콘솔에서 결제수단과 지급 통보 URL을 설정하세요. 앱에 보안키를 설정한 경우에는 인증 토큰도 준비해야 합니다.
결제수단 연결¶
Hive 콘솔에서 앱에 정기 결제용 결제수단을 연결하세요. 설정 방법은 PG 설정을 참조하세요.
지급 통보 URL 설정¶
결제 결과를 받을 앱 서버의 URL을 Hive 콘솔 > 빌링 > 결제 설정 > PG 설정 > 부가 기능 설정에 등록하세요. 일반 PG 결제와 같은 설정을 사용합니다. 자세한 설정 방법은 PG 결제 알림 설정을 참조하세요.
인증 토큰 준비¶
앱에 보안키를 설정한 경우, OAuth Token 발급하기를 통해 Access Token을 발급받으세요. API를 호출할 때 요청 헤더의 X-Access-Token에 이 토큰을 포함하세요.
공통 요청과 응답¶
모든 API는 POST 메서드와 JSON 형식의 요청 본문을 사용합니다. 폼 전송은 지원하지 않습니다. 각 API의 경로 앞에 사용할 환경의 호스트를 붙여 요청하세요.
- 상용 호스트:
https://hiveiap.qpyou.cn - Sandbox 호스트:
https://sandbox-hiveiap.qpyou.cn
Request header¶
요청 본문의 형식은 Content-Type으로 지정합니다. X-Access-Token은 앱에 보안키를 설정한 경우에만 검증합니다.
| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
Content-Type | String | 필수 | application/json |
X-Access-Token | String | 조건부 필수 | 앱에 보안키를 설정한 경우 필요한 OAuth 2.0 Access Token |
사용자 식별¶
재결제와 해지를 요청할 때는 정기 결제를 등록한 사용자의 정보를 전달해야 합니다. Hive 서버는 player_type과 player_id를 함께 사용해 사용자를 식별합니다.
player_type이 v4이면 player_id에 Hive Player ID인 vid를 전달하세요. v0이면 Hive 멤버십 UID인 uid를 전달하세요. player_type은 지급 통보의 vid_type과 같은 값입니다.
player_id는 값이 1 이상인 숫자 문자열이어야 합니다. 숫자가 아닌 값을 전달하면 10010002 오류를 반환합니다.
Response body¶
JSON 응답의 code가 문자열 "0"이면 성공입니다. 오류도 HTTP 상태 코드 200으로 응답하므로 본문의 code를 확인하세요. 토큰 인증 실패는 HTTP 상태 코드 401로 응답합니다.
정기 결제 등록에 성공하면 JSON 대신 결제창 HTML을 반환합니다. 등록 응답을 참조하세요.
| 필드 | 타입 | 포함 응답 | 설명 |
|---|---|---|---|
code | String | JSON 응답 | 결과 코드. "0"은 성공, 그 외의 값은 오류 코드 참조 |
message | String | JSON 응답 | 결과 메시지. 오류 발생 시 원인을 포함하며, 내부 오류 메시지는 Internal server error |
공통 성공 응답 예시는 아래와 같습니다.
결제수단 목록 조회 API¶
정기 결제로 등록할 결제수단을 조회합니다. 조회한 목록의 배열 순서대로 결제수단을 표시하고, 사용자가 선택한 항목의 식별자를 정기 결제 등록 요청에 전달하세요.
Request info¶
요청 경로는 /v2/payment/recurring/methods입니다. 요청 방식과 인증 헤더는 공통 요청과 응답을 따릅니다.
- 상용 URL:
https://hiveiap.qpyou.cn/v2/payment/recurring/methods - Sandbox URL:
https://sandbox-hiveiap.qpyou.cn/v2/payment/recurring/methods
Request body¶
티어 가격은 상품에 설정한 통화별 가격입니다. market_pid를 지정하면 해당 상품에 티어 가격이 설정된 통화로 결제할 수 있는 결제수단만 반환합니다.
country를 생략하면 요청한 서버의 IP로 국가를 판단하므로, 사용자의 국가 코드를 전달하는 것을 권장합니다.
| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
appid | String | 필수 | App ID |
market_pid | String | 선택 | 상품 ID. 해당 상품의 티어 가격이 있는 통화로 결제수단을 필터링할 때 사용 |
country | String | 선택, 권장 | 사용자 국가 코드. ISO 3166-1 alpha-2 형식 |
language | String | 선택 | 결제수단 표시명 언어. 기본값은 en |
아래는 한국 사용자를 대상으로 상품 item08의 결제수단을 조회하는 요청 본문입니다.
Response body¶
성공 응답은 공통 응답 필드와 payment_methods 배열을 포함합니다. 배열의 각 항목은 PG와 결제수단 정보입니다.
| 필드 | 타입 | 포함 위치 | 설명 |
|---|---|---|---|
payment_methods | Array | 응답 본문 | 정기 결제용 결제수단 목록. 배열 순서는 표시 순서 |
agency_id | Integer | payment_methods[] | PG 식별자. 정기 결제 등록 요청에 그대로 전달 |
agency_code | String | payment_methods[] | PG 코드. kakaopay, danal_tpay, paymentwall, kcp_billing |
agency_name | String | payment_methods[] | PG 이름 |
pay_method | String | payment_methods[] | 결제수단 코드. kakaopay, card |
payment_method_id | Integer | payment_methods[] | 결제수단 식별자. 정기 결제 등록 요청에 그대로 전달 |
payment_method_name | String | payment_methods[] | language 기준의 결제수단 표시명 |
icon_url | String | payment_methods[] | 결제수단 아이콘 URL |
currency | String | payment_methods[] | 결제 통화 |
아래는 카카오페이 결제수단을 반환하는 응답 예시입니다. icon_url의 https://…는 실제 URL을 생략한 표기입니다.
앱이나 상품을 찾을 수 없거나 판매 중지 상품을 조회하면 10010003을 반환합니다. 국가와 상품 통화 조건에 맞는 정기 결제용 결제수단이 없으면 10010005를 반환합니다.
정기 결제 등록 API¶
사용자가 결제수단을 등록하고 1회차 결제를 진행할 수 있도록 결제창 HTML을 요청합니다. 앱 서버는 받은 HTML을 사용자의 웹뷰 또는 브라우저에 그대로 표시합니다.
결제창에서 등록을 마치면 Hive 결과 화면이 표시됩니다. 1회차 결제 결과는 앱 서버로 보내는 지급 통보로 전달됩니다.
Request info¶
요청 경로는 /v2/payment/recurring/register입니다. 요청 방식과 인증 헤더는 공통 요청과 응답을 따릅니다.
- 상용 URL:
https://hiveiap.qpyou.cn/v2/payment/recurring/register - Sandbox URL:
https://sandbox-hiveiap.qpyou.cn/v2/payment/recurring/register
Request body¶
market_pid를 포함해 결제수단 목록을 조회한 뒤, 응답에 포함된 agency_id와 payment_method_id를 전달하세요. country도 목록 조회 때와 같은 값을 전달해야 합니다.
| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
appid | String | 필수 | App ID |
market_pid | String | 필수 | 정기 결제할 상품 ID. 모든 회차에서 같은 상품 사용 |
server_id | String | 필수 | 앱 서버 ID. 모든 회차의 지급 통보에 그대로 전달 |
player_id | String | 필수 | 사용자 ID. 사용자 식별 참조 |
player_type | String | 필수 | 사용자 유형. v4 또는 v0 |
agency_id | Integer | 필수 | 결제수단 목록 조회 응답의 PG 식별자 |
payment_method_id | Integer | 필수 | 결제수단 목록 조회 응답의 결제수단 식별자 |
email | String | 조건부 필수 | 구매자 이메일. 페이먼트월은 필수이며 다른 PG는 사용하지 않음 |
iap_payload | String | 선택 | 앱 서버에 전달할 추가 정보. 모든 회차의 지급 통보에 그대로 전달하며 재결제 요청으로 변경할 수 없음 |
country | String | 선택, 권장 | 사용자 국가 코드. 목록 조회 시 전달한 값과 같아야 하며, 생략 시 요청한 서버의 IP로 판단 |
language | String | 선택 | 결제창과 결과 화면의 언어. 기본값은 en |
아래는 카카오페이로 정기 결제를 등록하는 요청 본문입니다.
Response body¶
등록 요청의 성공 여부에 따라 응답 형식이 달라지므로 응답 헤더의 Content-Type을 확인하세요. 요청이 실패했을 때 사용자에게 표시할 문구는 앱에서 정합니다.
| 결과 | HTTP 상태 코드 | Content-Type | 응답 처리 |
|---|---|---|---|
| 성공 | 200 | text/html | 받은 결제창 HTML을 사용자에게 그대로 표시 |
| 실패 | 200 | application/json | 공통 응답의 code와 message 확인 |
아래는 페이먼트월 등록 요청에서 이메일이 누락된 경우의 응답입니다.
등록 처리¶
1회차 결제 금액은 등록 시점의 상품 티어 가격입니다. 선택한 결제수단의 통화에 해당하는 가격을 적용합니다.
등록을 요청할 때마다 새 정기 결제가 생성됩니다. 사용자가 결제창을 닫으면 해당 정기 결제는 등록이 완료되지 않은 상태로 남으며, 이 상태에서는 재결제를 요청할 수 없습니다.
1회차 결제가 완료되면 Hive 서버가 type이 paid인 지급 통보를 전송합니다. 이 통보의 order_id를 발급 주문번호로 저장하세요.
10010005 오류가 발생하면 market_pid를 포함해 결제수단 목록을 다시 조회하고, 응답에 포함된 결제수단으로 요청하세요. 그 외 오류의 처리 방법은 오류 코드를 참조하세요.
재결제 API¶
등록한 결제수단으로 2회차 이후 결제를 요청합니다. 성공 응답은 결제 접수를 의미합니다. 페이먼트월처럼 PG 승인이 늦는 경우에는 성공 응답 후에 승인 결과가 나올 수 있으며, 승인되면 Hive 서버가 지급 통보를 전송합니다.
Request info¶
요청 경로는 /v2/payment/recurring/charge입니다. 요청 방식과 인증 헤더는 공통 요청과 응답을 따릅니다.
- 상용 URL:
https://hiveiap.qpyou.cn/v2/payment/recurring/charge - Sandbox URL:
https://sandbox-hiveiap.qpyou.cn/v2/payment/recurring/charge
Request body¶
order_id에는 1회차 지급 통보로 받은 발급 주문번호를 전달합니다. sequence는 같은 정기 결제 안에서 회차를 구분하는 멱등키로, 같은 회차를 재시도할 때 중복 청구를 방지하는 값입니다.
| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
appid | String | 필수 | 등록한 앱의 App ID |
order_id | String | 필수 | 발급 주문번호. 1회차 지급 통보의 order_id |
sequence | Integer | 필수 | 회차 번호. 2 이상의 값이며, 같은 회차를 재시도할 때 같은 값 사용 |
player_id | String | 필수 | 등록한 사용자의 ID |
player_type | String | 필수 | 등록한 사용자의 유형 |
아래는 발급 주문번호로 2회차 결제를 요청하는 본문입니다.
Response body¶
성공 응답은 공통 응답 필드와 이번 회차의 주문번호를 포함합니다. 이 번호를 해당 회차와 연결해 저장하세요.
| 필드 | 타입 | 포함 응답 | 설명 |
|---|---|---|---|
order_id | String | 재결제 성공 응답 | 이번 회차의 주문번호. 해당 회차 지급 통보와 환불 통보의 order_id와 같은 값 |
아래는 2회차 주문번호를 반환하는 성공 응답입니다.
재결제 조건과 재시도¶
모든 회차에서 정기 결제 등록 시 지정한 상품으로 결제합니다. 회차 번호는 앱 서버에서 관리하며, Hive는 회차 번호가 연속되는지 검사하지 않습니다.
상품의 판매를 중지해도 이미 등록한 정기 결제에 대해서는 재결제 요청을 처리합니다. 판매 중지는 신규 등록만 막으므로, 청구를 멈추려면 재결제를 요청하지 마세요.
같은 sequence로 다시 요청했을 때의 처리는 아래와 같습니다.
| 회차 상태 | 응답 | 추가 청구 | 앱 서버 처리 |
|---|---|---|---|
| 결제 완료 | 10010007 | 없음 | 이미 결제된 회차이므로 중복 요청 무시 |
| 승인 대기 | 같은 order_id로 성공 응답 | 없음 | 지급 통보를 기준으로 상품 지급 |
| 이전 요청 실패 | 결제 재시도 결과 | 결제 재시도 | 같은 sequence로 재시도 |
PG 승인 실패 시 10010024와 함께 message에 PG의 실패 사유를 반환합니다. 사용자에게 결제수단 확인을 안내한 후 같은 sequence로 재시도하세요. 내부 오류인 10010001, 10010004, 10010022도 같은 sequence로 재시도합니다.
해지 API¶
정기 결제를 해지하면 Hive 서버가 해당 정기 결제에 등록된 결제수단을 삭제합니다. 해지 후 재결제를 요청하면 10010023 오류를 반환합니다.
Request info¶
요청 경로는 /v2/payment/recurring/cancel입니다. 요청 방식과 인증 헤더는 공통 요청과 응답을 따릅니다.
- 상용 URL:
https://hiveiap.qpyou.cn/v2/payment/recurring/cancel - Sandbox URL:
https://sandbox-hiveiap.qpyou.cn/v2/payment/recurring/cancel
Request body¶
해지할 정기 결제의 발급 주문번호와 등록한 앱 및 사용자 정보를 전달하세요. 2회차 이후 주문번호로는 해지할 수 없습니다.
| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
appid | String | 필수 | 등록한 앱의 App ID |
order_id | String | 필수 | 발급 주문번호. 1회차 지급 통보의 order_id |
player_id | String | 필수 | 등록한 사용자의 ID |
player_type | String | 필수 | 등록한 사용자의 유형 |
아래는 발급 주문번호로 정기 결제를 해지하는 요청 본문입니다.
Response body¶
성공 응답은 공통 응답 필드인 code와 message를 포함합니다. 아래는 해지 성공 응답입니다.
정기 결제를 찾을 수 없으면 10010003, 이미 해지했거나 활성 상태가 아니면 10010023을 반환합니다. PG 결제수단 삭제에 실패한 10010004 오류는 재시도하세요.
지급 통보와 결과 처리 API¶
Hive 서버는 정기 결제 결과를 일반 PG 결제와 같은 형식으로, 같은 지급 통보 URL에 전송합니다. 요청 형식과 전달 필드는 PG 결제 결과 알림 서비스를 참조하세요.
주문번호와 회차 연결¶
지급 통보에는 정기 결제 여부와 회차 번호가 포함되지 않습니다. 앱 서버는 저장한 발급 주문번호와 재결제 응답의 order_id를 사용해 지급 통보가 어느 정기 결제의 몇 회차에 해당하는지 확인해야 합니다.
| 전송 시점 | type | order_id | 앱 서버 처리 |
|---|---|---|---|
| 1회차 결제 완료 | paid | 발급 주문번호 | 발급 주문번호 저장 및 1회차 상품 지급 처리 |
| 2회차 이후 결제 완료 | paid | 해당 회차 주문번호. 재결제 응답의 order_id | 저장한 회차와 연결 후 상품 지급 처리 |
| Hive 콘솔 또는 PG에서 회차 환불 | cancelled | 환불한 회차 주문번호 | 해당 회차의 환불 결과 처리 |
server_id, iap_payload, market_pid는 등록할 때 보낸 값이 모든 회차의 지급 통보에 그대로 전달됩니다.
상품 지급과 환불¶
type이 paid인 지급 통보의 purchase_bypass_info를 사용해 영수증을 검증한 후 상품을 지급하세요. 전달 필드는 PG 결제 결과 알림 서비스를 참조하세요.
환불한 회차는 일반 결제와 같이 환불 유저 재결제 대상이 됩니다.
오류 코드¶
HTTP 상태 코드가 200이어도 JSON 본문의 code를 확인해야 합니다. 오류 코드와 요청 상황을 함께 확인해 아래와 같이 처리하세요.
| 코드 | 관련 API | 원인 | 처리 방법 |
|---|---|---|---|
0 | JSON 응답 공통 | 성공 | 각 API의 성공 응답 처리 |
10010001 | 공통 | 내부 오류 | 재시도. 재결제는 같은 sequence 사용 |
10010002 | 공통 | 필수값 누락, 형식 오류, JSON이 아닌 본문, POST가 아닌 메서드. 재결제의 sequence가 1 이하이거나 player_type이 잘못된 경우 포함 | 요청값과 형식 수정 |
10010003 | 결제수단 목록 조회, 등록 | 앱 또는 상품을 찾을 수 없음, 판매 중지 상품. 등록 시 페이먼트월의 email 누락 포함 | 앱과 상품 확인. 판매 중인 상품으로 요청하고, 페이먼트월은 이메일 입력 후 재요청 |
10010003 | 재결제, 해지 | 정기 결제를 찾을 수 없음. 발급 주문번호가 아니거나 다른 앱 또는 사용자의 정기 결제 | 1회차 발급 주문번호와 등록한 앱 및 사용자 정보 확인 |
10010004 | 공통 | PG 연동 오류. 해지 시 PG 결제수단 삭제 실패 포함 | 재시도. 재결제는 같은 sequence 사용 |
10010005 | 결제수단 목록 조회, 등록 | 국가와 상품 통화 조건에 맞는 정기 결제용 결제수단 없음 | market_pid를 포함해 목록 재조회 후 응답에 포함된 결제수단으로 등록 |
10010007 | 재결제 | 이미 결제한 회차 | 중복 요청이므로 무시 |
10010022 | 공통 | 내부 오류 | 재시도. 재결제는 같은 sequence 사용 |
10010023 | 재결제, 해지 | 해지, 등록 실패, 등록 미완료 등으로 정기 결제가 활성 상태가 아님 | 사용자에게 재등록 안내 |
10010024 | 재결제 | 한도 초과, 카드 정지 등 PG 승인 실패. message에 PG의 실패 사유 포함 | 사용자에게 결제수단 확인 안내 후 같은 sequence로 재시도 |
HTTP 401 | 공통 | 토큰 인증 실패 | X-Access-Token의 인증 정보 확인 |
연동 주의 사항¶
PG 정기 결제를 연동할 때는 주문번호와 회차 번호의 사용 방식, 상품 지급 시점, 가격 적용 기준, 해지 범위를 확인하세요.
발급 주문번호 사용¶
재결제와 해지는 반드시 1회차 지급 통보의 order_id인 발급 주문번호로 요청하세요. 2회차 이후의 주문번호로 요청하면 10010003 오류를 반환합니다. 주문번호 관리 방식은 연동 흐름을 참조하세요.
회차 번호와 재시도¶
sequence는 2부터 사용하세요. 같은 회차의 결제를 재시도할 때도 같은 sequence를 전달해야 이중 청구를 방지할 수 있습니다. 회차 상태별 응답과 재시도 방법은 재결제 API를 참조하세요.
지급 통보 기준의 상품 지급¶
상품은 type이 paid인 지급 통보를 기준으로 지급하세요. 재결제 성공 응답만으로 상품을 지급하면 안 됩니다. 영수증 검증과 회차 연결 방법은 지급 통보와 결과 처리 API를 참조하세요.
결제 시점의 상품 가격 적용¶
회차별 결제 금액은 결제를 요청한 시점의 상품 티어 가격입니다. 상품 가격을 변경하면 다음 회차부터 변경한 금액으로 결제합니다. 재결제 대상 상품과 판매 중지 시의 처리 방식은 재결제 API를 참조하세요.
페이먼트월 구매자 이메일¶
페이먼트월로 정기 결제를 등록할 때는 사용자에게 구매자 이메일을 입력받아 email에 전달하세요. 요청 필드와 입력 조건은 정기 결제 등록 API를 참조하세요.
해지와 환불 구분¶
정기 결제를 해지해도 이미 결제한 회차는 환불되지 않습니다. 해당 회차를 환불하려면 별도로 환불을 처리해야 합니다. 해지 요청과 응답은 해지 API를 참조하세요.