Hive 아이템 연동
Hive 아이템은 게임 내의 재화나 아이템의 지급/회수 기능을 통합하여 관리할 목적으로 제공하는 시스템입니다. Hive 아이템 연동은 쿠폰 시스템, 이벤트, 오퍼월, CPI 등과 연동하여 아이템을 지급 또는 회수하는 기능을 제공합니다. 관리자용 백오피스에서는 수동으로 지급/회수하거나 이력을 검색할 수도 있습니다.
Note
- 아이템 지급/회수 요청 API 는 비동기(asynchronous) 방식으로 동작되며, API 요청 시 요청 정보 등록의 성공 및 실패 여부만 판단하여 응답합니다.
- 게임 서버 API 호출과 같은 실제 처리 동작에 대한 응답 은 Hive 콘솔 메뉴의 빌링 > Hive 아이템 > 지급/회수 요청 또는 지급/회수 성공 로그 에서 관련 내용을 검색한 후 검색 결과 목록의 상태 항목 클릭 시 나타나는 팝업 창에서 확인할 수 있습니다.
- Hive 아이템은 대규모 트래픽 처리가 필요하므로 개발사 앱 서버 평균 응답 시간이 0.5초를 초과하면, 메인 Queue가 아닌 별도 Queue로 분리해 동작할 수 있습니다. 이 경우 아이템 지급 처리에 많은 지연이 발생할 수 있습니다. 원활한 아이템 지급 처리를 위해 개발사 앱 서버 평균 응답 시간 0.5초 미만을 유지하는 것을 권장합니다.
연동 준비 사항¶
Hive 아이템과 연동하려면 먼저 Hive 아이템 관리 메뉴에서 게임 서버 URL과 아이템을 등록해야 합니다.
지급/회수 요청 API¶
지급/회수 요청 API의 기본 사항 확인하기¶
API 통신 방식¶
- 지급/회수 요청 API는 HTTP 통신과 socket을 이용한 JSON String 통신 2가지 타입을 제공합니다.
- Hive 아이템에서 게임 서버로 JSON String 형태의 지급 또는 회수를 요청합니다.
- 게임 서버에서 Hive 아이템으로 JSON String 형태의 결과를 반환합니다.
- 응답 결과는 처리 코드와 메시지를 포함합니다.
- JSON String은 모두 UTF8로 인코딩해야 합니다.
게임 적용 방법¶
- 서비스 오픈 전에는 테스트 서버로, 서비스 오픈 후에는 상용 서버로 연동 테스트 결과를 전송합니다.
- 게임이 이미 서비스 중이어도 테스트 서버와 반드시 연동해야 합니다.
- 모든 아이템은 우편함으로 지급됩니다.
- 우편함에서 유저에게 보여줄 지급 문구가 필요한 경우 요청 명세 > 요청 사유를 참고하세요. 게임 서버에서는 표기하는 문구를 각 언어에 맞게 분기 처리해야 합니다.
- 아이템 요청은 유저당 하나씩 전송됩니다. 여러 아이템의 지급/회수 요청이 동시에 전송될 수 있으나 하나의 요청은 한 트랜잭션 내에서 처리되어야 합니다. 아이템 지급/회수 하나가 실패할 경우에는 전체 롤백 후 실패를 응답하도록 구현하세요.
게임 서버 방화벽 해제¶
서버로 통신하려면 게임 서버에서 아래 IP의 방화벽 인바운드 규칙을 해제해야 합니다.
- 52.79.76.25
- 3.37.22.75
- 43.133.238.219 (샌드박스 서버)
게임 서버 헬스 체크¶
Hive 아이템은 게임 서버의 이상 여부를 확인하기 위해 지급/회수 요청 API에 아래 내역을 전송합니다. Hive 아이템 서버에서 게임 서버로, Request Body에 5분 간격으로 2번 전송합니다.
{"transactionId":"","idCategory":"","id":"","detail":[{"action":"","assetCode":"","amount":0}],"reason":""}
위 내용을 전달받은 게임 서버는 Validation 에러가 발생할 수 있으며, 이 때는 Response 값 내 code와 message 필드에 에러 정보를 실어 응답하면 됩니다. Hive 아이템은 code 값만 단독으로 판단하지 않습니다. code, message 필드가 있으면 게임 서버가 정상이라고 판단하고 없으면 게임 서버가 비정상 상태라고 판단합니다.
Apihash 값 검증¶
게임 서버는 Header의 Apihash 값을 통해 Hive 아이템 서버로부터 전달받은 데이터의 유효성을 검증할 수 있습니다. 해시 값 검증에 앞서, 반드시 Hive 아이템 서버로부터 전달받은 Request Body 데이터를 JSON encode 또는 unicode로 변환해야 합니다. (예제 코드 참조) 
 요청 명세의 접두어와 변환된 JSON String 값을 혼합(접두어+JSON String)하여 SHA1 형식의 해시 값을 생성하고, 이 값과 Apihash 값을 비교하여 검증합니다.
- 예제 코드
// 변환된 JSON String 예시 (가독성을 위해 임의로 개행 및 공백 추가)
 {
    "transactionId": "123456789",
    "idCategory": "vid",
    "id": "1004",
    "detail": [
        {
            "action": "p",
            "assetCode": "gem",
            "amount": 1,
            "method": ""
        }
    ],
    "reason": "td",
    "subReason": "",
    "userMessage": "",
    "templateMessage": {
        "ko": {
            "title": "HIVE Item uc9c0uae09 uba54uc138uc9c0 QA ud55cuad6d",
            "body": "HIVE Item uc9c0uae09 uba54uc138uc9c0 QA ud55cuad6duc5b4 ub178ucd9c"
        }
    },
    "serverId": "kr",
    "additionalinfo": "",
    "gameIndex": 539
}
HTTP 통신 방식의 지급/회수 요청 API¶
지급/회수 요청 API는 Hive 콘솔 > 빌링 > 아이템 > 아이템 등록 메뉴에서 설정한 게임 서버(URL)와 HTTP 프로토콜 통신을 하며, 요청 데이터 전송 방식은 POST 방식입니다.
요청 명세 (Hive 아이템 -> 게임 서버)¶
HTTP Header : Apihash
- 데이터 유효성 검증 위해 Apihash라는 키 값으로 해시 값을 전송합니다.
- 해시 값은 SHA1를 사용하세요. (본문 JSON String에 접두어 !@#COM2US!@# 추가)
Request Body (Hive 아이템 -> 게임 서버)
| 필드명 | 설명 | 타입 | 필수 여부 (필수: M, 옵션: O) | 
|---|---|---|---|
| transactionId | 각 요청을 구별하기 위한 식별자 (중복 요청 확인용) 자세히 | String | M | 
| idCategory | ID 
 | String | M | 
| id | idCategory에 해당하는 ID 값 | String | M | 
| detail | 아래 세 항목 객체의 배열 | Array | M | 
| ㄴaction | 지급/회수 여부 
 | String | M | 
| ㄴassetCode | 지급할 항목 코드 | String | M | 
| ㄴamount | 지급 수량 | Integer | M | 
| reason | 요청 사유 자세히 | String | M | 
| subReason | 요청 사유 자세히 | String | O | 
| serverId | 대상 유저가 접속한 서버 (서버 구분값) | String | M | 
| additionalinfo | 게임 서버로 보내기 위해 클라이언트에서부터 넘어온 추가적인 정보 (모두 소문자) (JSON String 형식) | String | O | 
| duration | 우편함 보관 기간 (선택 사항) 자세히 
 | Integer | O | 
| userMessage | 아이템 지급 메시지 (고정 메시지) templateMessage를 사용하지 않는 구게임 호환용 | String | O | 
| templateMessage | 아이템 지급 메시지에 설정된 메시지 데이터key는 언어 코드, value는 메시지(title)와 본문(body)으로 구성 (단, 데이터가 존재하는 경우 기본 형식은 Object이며, 빈 값이면 공백 String으로 전달) | Object | O | 
| gameIndex | Hive 앱센터 게임별 일련번호 | Integer | M | 
transactionId¶
- 이미 처리된 요청인지 transactionId로 식별하여 판단합니다. (중복 지급/회수 방지)
- 중복 요청의 경우 응답 값에 해당 사항을 명시합니다. (응답 명세 참고)
reason¶
Note
reason 필드 내역은 추후 추가/변경될 수 있으므로 해당 요청에 대한 발생 사유는 단순 참조용으로만 사용해야 합니다.
| 필드명 | 설명 | 
|---|---|
| pe | 과금오류 (Payment Error) | 
| rge | 보상(게임오류) (Reward Game Error) | 
| rcd | 보상(고객불만) (Reward Consumer Dissatisfaction) | 
| rce | 보상(쿠폰오류) (Reward Coupon Error) | 
| ro | 보상(해외) (Reward Overseas) | 
| ae | 재화변경지급 (Asset Exchange) | 
| e | 이벤트 (Event) | 
| ea | 이벤트(자동) (Event Automatic) | 
| mc | 대량쿠폰 (Massive Coupon) | 
| uc | 고유쿠폰 (Unique Coupon) | 
| b | 인게임 빌링 (Billing - HIVE IAP v2) | 
| lb | 러비웹샵 빌링 (Lebi Billing) | 
| co | 오퍼월 (Cpi Offerwall) | 
| p | 프로모션 (Promotion) - 크로스배너, 오퍼월, UA 모두 동일하게 사용 | 
| sr | 스트리밍 보상 (Streaming Reward) | 
| tcs | 테스트(CS) (Test CS) | 
| tgm | 테스트(GM) (Test GM) | 
| tpm | 테스트(PM) (Test PM) | 
| tqa | 테스트(QA) (Test QA) | 
| td | 테스트(개발) (Test Developer) | 
| tg | 테스트(홍보/사업) (Test Market , Business) | 
| tmb | 테스트(해외) (Test Overseas) (Test Developer) | 
| re | 회수(기타) (Retrieve Etc) | 
| rr | 회수(환불) (Retrieve Refund) | 
| mr | 대량요청 (Massive Request) | 
| etc | 기타 (Etc) | 
subReason¶
| Reason | subReason | 설명 | 
|---|---|---|
| p | 프로모션 하위 요청 상세 | |
| 1 | 크로스 일반 배너 CPI | |
| 2 | 크로스 일반 배너 CPA | |
| 3 | 크로스 전면 배너 CPI | |
| 4 | 크로스 전면 배너 CPA | |
| 5 | 오퍼월 일반 CPI | |
| 6 | 오퍼월 일반 CPA | |
| 7 | 오퍼월 스페셜 CPI | |
| 8 | 오퍼월 스페셜 CPA | |
| 9 | UA CPI | |
| 10 | UA CPA | |
| 11 | UC CPI | 
프로모션 기능 분류
- 크로스 프로모션: 유저가 플레이하는 현재 게임에서 배너와 오퍼월(무료충전소) 형태로 다른 게임을 광고할 수 있습니다. 일반 배너와 전면 배너로 나뉩니다.
- 오퍼월: 오퍼월에는 유저 기기에 설치 이력이 없는 게임 목록이 배너 형태로 표시됩니다. 유저가 배너를 터치한 후 연결되는 마켓에서 게임을 설치하면 보상을 지급합니다. 오퍼월 일반과 오퍼월 스페셜로 나뉩니다.
- UA/UC: 소셜 미디어와 QR 코드를 활용하는 게임 초대 기능입니다. UA에는 초대하는 유저와 받는 유저가 있는 반면 UC는 초대 받는 유저만 존재합니다. UC는 사전 예약에서 활용할 수 있습니다.
보상 방법
- CPI: 게임 설치 후 실행하면 보상을 지급합니다.
- CPA: 게임 실행 도중 정해진 목표를 달성하면 보상을 지급합니다. 자세한 내용은 프로모션 운영 가이드에서 확인하세요.
duration¶
- 요청 항목을 지급한 후 우편함에 보관하는 기간으로, 백오피스에서 항목마다 개별 설정할 수 있습니다.
- 게임 서버에서는 3가지 경우로 나눠 상황에 맞게 처리합니다.- 해당 키가 존재하지 않을 경우: 게임 서버에서 설정한 기본값을 사용합니다. (예. 기본 7일 보관)
- 1~9999: 명시된 숫자를 일 단위로 사용합니다. (예. 값이 14이면 14일 보관)
- -1: 게임 서버에서 설정할 수 있는 최대값을 사용합니다. (예. 영구 보관)
 
응답 명세 (게임 서버 -> Hive 아이템)¶
Response (게임 서버 -> Hive 아이템)
| 필드명 | 설명 | Type | 필수 여부 (필수: M, 옵션: O) | 
|---|---|---|---|
| code | 처리 결과 코드 자세히 | Integer | M | 
| message | 처리 결과 메시지 | String | M | 
- 에러코드
| 코드값 | 설명 | 
|---|---|
| 2xxxx | 요청 이상 없음. 처리 성공 | 
| ㄴ 20000 | 요청 이상 없음. 처리 성공 | 
| ㄴ 20001 | 요청 이상 없음. 이미 성공 처리된 경우 (중복 요청) 이미 정상 처리된 transactionId가 존재할 경우 | 
| 4xxxx | 요청 파라미터 오류 | 
| ㄴ 40001 | 요청 json 에러 | 
| ㄴ 40002 | 해쉬 오류 | 
| ㄴ 40003 | 필수 파라미터 키 누락 | 
| ㄴ 40004 | 필수 파라미터 키 타입 오류 | 
| ㄴ 40005 | 필수 파라미터 값 비어있음 | 
| ㄴ 40006 | 잘못된 필수 파라미터 값 (예. 음수) | 
| 5xxxx | 서버 처리 오류 | 
| ㄴ 50001 | 존재하지 않는 유저 | 
| ㄴ 50004 | DB 등록 오류 | 
| ㄴ 50005 | 파라미터 오류 (예. 존재하지 않는 항목 코드) | 
- Call Sample
curl -L -v 
-d '{"transactionId":"27905","idCategory":"vid","id":"828292","detail":[{"action":"p","assetCode":"gold","amount":500,"method":""},{"action":"p","assetCode":"gem","amount":200,"method":""}],"reason":"td","subReason":"","userMessage":"","templateMessage":{"ko":{"title":"ud55cuae00 uba54uc138uc9c0","body":"ud55cuae00 ub0b4uc6a9"},"en":{"title":"English Message","body":"English Contents"}},"serverId":"kr","additionalinfo":"","gameIndex":539}' 
-H "Content-Type: text/html" 
-H "Apihash: e9d7307948ff0134fb59c5f96e68f5ae21e3e47f" 
https://sandbox-misample.com2us.net/hive/item
- Request Sample
> POST /hive/item HTTP/2
> Host: sandbox-misample.com2us.net
> user-agent: curl/7.68.0
> accept: */*
> content-type: text/html
> apihash: e9d7307948ff0134fb59c5f96e68f5ae21e3e47f
> content-length: 447
- Response Sample
< HTTP/2 200
< server: nginx
< date: Tue, 12 Jul 2022 11:29:21 GMT
< content-type: application/json; charset=utf-8
<
* Connection #0 to host sandbox-misample.com2us.net left intact
{"status":"200","code":"20001","message":"this request has already been processed"}
Request Sample(PHP)
// 요청 데이터 
$data = array(
    'transactionId'     => '12321',
    'idCategory'        => 'vid',
    'id'                => '828292',
    'detail'            => array(
        array(
            'action'    => 's',
            'assetCode' => 'gold',
            'amount'    => 500,
        ),
        array(
            'action'    => 's',
            'assetCode' => 'gem',
            'amount'    => 200,
        ),
    ),
    'reason'            => 'p',
    'subReason'         => '3',
    'userMessage'       => '',
    'templateMessage'   => array(
        'ko' => array(
            'title' => '한글 메세지',
            'body'  => '한글 내용'
        ),
        'en' => array(
            'title' => 'English Message',
            'body'  => 'English Contents'
        ),
    ),
    'serverId'          => 'GLOBAL',
    'additionalinfo'    => '{"character":1}',
    'gameIndex'         => 539
);
$jsonData = json_encode($data); // JSON 으로 변환
/******************************************************************** 
변환 결과(가독성을 위해 임의로 개행 및 공백 추가) :
{
    "transactionId": "12321",
    "idCategory": "vid",
    "id": "828292",
    "detail": [
        {
            "action": "s",
            "assetCode": "gold",
            "amount": 500
        },
        {
            "action": "s",
            "assetCode": "gem",
            "amount": 200
        }
    ],
    "reason": "p",
    "subReason": "3",
    "userMessage": "",
    "templateMessage": {
        "ko": {
            "title": "한글 메세지",
            "body": "한글 내용"
        },
        "en": {
            "title": "English Message",
            "body": "English Contents"
        }
    },
    "serverId": "GLOBAL",
    "additionalinfo": "{"character":1}",
    "gameIndex": 539
}
********************************************************************/
// header 를 application/json 으로 설정 & hash 설정 
$hash = sha1('!@#COM2US!@#' . $jsonData); 
$header = array(
    'Content-type: application/json',
    'Apihash: ' . $hash
);
$url = 'http://game.com2us.com/gms.php'; // 게임 서버 url
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, $header); 
curl_setopt($curl, CURLOPT_URL, $url); 
curl_setopt($curl, CURLOPT_POST, true); 
curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
$result = curl_exec( $curl );
curl_close( $curl );
// 결과 데이터 처리
$response = json_decode($result);
Response Sample(PHP)
// php header 선언
header('Content-type: application/json');
// json Data
$rawData = file_get_contents('php://input');
//Hash값 확인
$hash = sha1('!@#COM2US!@#' . $rawData);
$requestHash = $_SERVER['Apihash'];
if ($requestHash != $hash) {
/*****************************************************************
해쉬 값이 다를 경우의 처리 (해쉬 사용 여부는 선택사항)
*****************************************************************/
}
// 요청받은 JSON 데이터를 디코딩
$requestData = json_decode($rawData, TRUE);
foreach ($requestData['detail'] as $item) {
/*****************************************************************
요청에 따른 재화 처리
*****************************************************************/
}
$returnData = array(
'code' => 50001,
'message' => 'user not exists',
);
//UTF8BOM이 붙는 것을 방지하기 위해
ob_clean()
//JSON으로 변환하여 응답 전송
echo json_encode($returnData);
/*****************************************************************
변환 결과(임의로 개행 삽입) :
{
"code" : 50001,
"message" : "user not exists"
}
*****************************************************************/
Socket 통신 방식의 지급/회수 요청 API¶
Socket을 이용한 지급/회수 요청 API TCP/IP는 프로토콜을 이용한 패킷 데이터 통신으로, 기본 포트는 20080입니다. 데이터는 HTTP 통신 때와 동일한 JSON 형식이고 바이트 순서는 Network Byte order (Big-endian)입니다.
요청 패킷 명세 (Hive 아이템 -> 게임 서버)¶
| 패킷 크기 | 4 바이트 | 4 바이트 | 가변 | 4 바이트 | 가변 | 
|---|---|---|---|---|---|
| 설명 | 전체 패킷 길이 | Header 길이 | Header 내용 | Body 길이 | Body 내용 | 
- 첫 4 바이트는 해당 4 바이트를 포함한 패킷 전체의 길이를 명시합니다. 
 예. header가 46 바이트, body가 100 바이트라면 4+4+46+4+100 = 158 바이트
- 다음 4 바이트는 바로 뒤에 이어질 Header 길이를 의미합니다.
- Header는 HTTP 통신에서의 해쉬 값과 동일한 JSON 문자열 형태입니다. 
 예.{"Apihash":"912ec803b2ce49e4a541068d495ab570"}
- 마지막 4 바이트는 바로 뒤에 이어질 Body 길이를 의미합니다.
- Body는 HTTP 통신에서의 요청 값과 동일한 JSON 문자열 형태입니다.
응답 패킷 명세 (게임 서버 -> Hive 아이템)¶
| 패킷 크기 | 4 바이트 | 가변 | 
|---|---|---|
| 내용 | 전체 패킷 길이 | Body | 
- 첫 4 바이트는 해당 4 바이트를 포함한 패킷 전체의 길이를 명시합니다.
- Body는 HTTP 통신에서의 응답 값과 동일한 JSON 문자열 형태입니다.