본문으로 건너뛰기

Google Play 소모성 상품에 대해서, 가장 최근 예약된 구매건인데 소모처리 안되었다면 조회(모바일/PC 공용)

기본 정보

  1. Google Play에서 유저가 구매를 진행했고 금액 청구까지 되었지만, 클라이언트가 어떤 사유로 종료되어서 게임서버 및 빌링에 완료 요청이 전달되지 않은 데이터 단건을 조회하는 클라이언트(SDK)전용 API
  2. 해당 API를 이용해서 클라이언트 사이드에서 발생한 실패 건을 재 처리에 구현하는데 사용 가능
    1. 클라이언트가 예약 시점에 boid를 저장하지 않았을 경우에 사용할 수 있음
    2. boid가 있다면 기존 프로세스 그대로 사용 가능
항목내용비고
호출주체게임 클라이언트(또는 Game Platform SDK)
도메인각 환경별 도메인
인증 방식HTTP 헤더 인증 정보
HTTP 메소드POST
Content-Typeapplication/json

Request

HTTP Request end point

POST https://각 환경별 빌링시스템 도메인 /billing/him-platform-sdk/v1/google/play/common/getLatestReservedNotConsumed

HTTP Request Parameter

  • Content-Type: application/json 으로 요청되어야 합니다.
이름데이터 타입설명
pjidString(20)

프로젝트ID

  • 동일 게임이라면 서비스ID가 여러개일 수 있지만 프로젝트ID는 같음
1004
appStoreString

앱을 다운로드한 플랫폼 스토어

  • 구글 모바일과 PC를 구분해서 응답해줘야해서 파라미터로 전달 받음
  1. 모바일: GOOGLE_PLAY
  2. 구글PC: GOOGLE_PLAY_PC
playerIdString

대상 유저 ID

  • 해당 id로 게임서버는 빌링API에 예약을 진행했어야함
googleOrderIdStringGoogle의 'orderId'(주문ID)GPA.3340-4023-4149-75538
googlePurchaseTokenStringGoogle의 purchaseToken
googleProductIdStringGoogle의 'productId'(구매한 상품ID)
googleResponseOriginJsonString

SDK 등에서 얻은 구글에서 응답온 JSON 원본 전문

  • 추가 필드가 필요할 때 SDK 배포 없이 기능 구현을 위해서 전문을 받음
아래 참고

googleResponseOriginJson 예시

{
"kind": "androidpublisher#productPurchase",
"purchaseTimeMillis": 1704950296551,
"purchaseState": 0,
"consumptionState": 0,
"orderId": "GPA.3340-4023-4149-75538",
"purchaseType": 0,
"acknowledgementState": 0,
"purchaseToken": "ogkbpllihcbjbifglbceoihe.AO-J1OwtOCXpN6cE5ULFcLqwbjYIzbtcWWldhHTUPAe-poGQEPvMP9tfcKkWXFEZ68_b2E9j1cWBx-Gw6xOKS9nqkG_gX2Ljig",
"productId": "item.bag.blue",
"regionCode": "KR"
}

Response

응답은 JSON형태로 전달됩니다.

  • 대상 데이터가 존재하는 경우에만 resultData가 리턴되며 존재하지 않는 경우에는 null 입니다.
    • 예) 예약된 데이터가 없거나, 예약되었더라도 이미 소모처리된 경우에는 null

Response property

keydata typedescriptionexample
boidString(20)빌링 시스템의 주문ID4
reservedAtUnixTSLong빌링 시스템에 예약처리된 일시 유닉스 Time stamp1707900667

Sample

Success sample

  • 해당 유저의 가장 마지막 예약된 데이터 1건을 조회 후 → 구글 API를 통해서 상태정보 체크 결과 대상 데이터인 경우
    • 구글에 구매 요청되었지만 아직 소모처리 안되어서 소모처리 가능한 상태로 구글 API가 응답한 데이터
{
"resultCode": "SUCCESS",
"resultMessage": "There is data that was most recently reserved but has not been consumed.",
"resultData": {
"boid": "17",
"reservedAtUnixTS": 1707900667
}
}

Error sample

  • 해당 유저가 예약한 데이터가 존재하지 않음
{
"resultCode": "SUCCESS",
"resultMessage": "Request success. But not exist reserved data.",
"resultData": null
}
  • 잘못된 purchase token으로 요청되어 구글 API가 에러 발생
{
"resultCode": "EXTERNAL_API_ERROR",
"resultMessage": "Google Play Developer API(purchases.products.get) error: '400 Bad Request\nGET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.hybeim.intheseom/purchases/products/item.bag.blue/tokens/ogkbpllihcbjbifglbceoihe.AO-J1OwtOCXpN6cE5ULFcLqwbjYIzbtcWWldhHTUPAe-poGQEPvMP9tfcKkWXFEZ68_b2E9j1cWBx-Gw6xOKS9nqkG_gX2Ljig\r\n{\n \"code\": 400,\n \"errors\": [\n {\n \"domain\": \"androidpublisher\",\n \"location\": \"token\",\n \"locationType\": \"parameter\",\n \"message\": \"The purchase token does not match the package name.\",\n \"reason\": \"purchaseTokenDoesNotMatchPackageName\"\n }\n ],\n \"message\": \"The purchase token does not match the package name.\"\n}'",
"resultData": null
}
  • 가장 최근 구매 예약건이 소모처리 불가능한 경우
{
"resultCode": "SUCCESS",
"resultMessage": "Request success. But Current consumptionState is '1' not allow(from google). boid:'17' | see https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products.",
"resultData": null
}

에러 코드 정의

  • resultCode에 올 수 있는 에러 코드입니다.
  • SDK 스펙상 해당 코드일 경우에도 상태코드는 200으로 리턴 됩니다.
에러코드비고
INVALID_PARAMETER
EXTERNAL_API_ERROR

빌링 API가 호출하는 외부 API가 에러인 경우

  • 예) 구글 API 장애로 구매의 상태 정보를 받아오지 못하는 경우
  • 게임 서버는 지수 백오프 알고리즘으로 재 시도하거나 클라이언트의 미 처리 영수증 처리 기능으로 처리할 수 있음

요청 curl 샘플

  • 도메인은 각 환경에 맞게 변경 필요
curl --location 'https://api-dev.pub-dev.hybegames.io/billing/him-platform-sdk/v1/google/play/common/getLatestReservedNotConsumed' \
--header 'Content-Type: application/json' \
--data '{
"pjid": "1201",
"appStore": "GOOGLE_PLAY",
"playerId": "playerId",
"googleOrderId": "GPA.3340-4023-4149-75538",
"googlePurchaseToken": "bkdcnncmkeegcekfcmjaeppj.AO-J1OxMzEQ0nV5GJvj1ytipiX90uRpWtyyn4cgozqFYeRp1euFxm2lFbH3XR8mPBPWeXgIIsxhkpMvDeey1_lRJ7WLmFMJdbg",
"googleProductId": "seom_tany_100022",
"googleResponseOriginJson": "클라에서 획득한 구글의 Json 전체 내용"
}'