오퍼 검증 API

개요

플레이어가 오퍼 메시지를 열람하고 구매 버튼을 클릭하는 등 오퍼를 수락하면 다음 단계로 진행하기 전에 REST API를 이용해 오퍼를 검증해야 합니다. 이 검증 API를 사용하면 해당 오퍼가 텐투플레이 서버에서 온 것으로 신뢰성과 무결성, 그리고 보안 면에서 문제가 없다는 것을 확인할 수 있습니다. 오퍼 검증은 개인화 오퍼와 AI 인게임 상점 모두 적용 가능하며 응답 메시지만 차이가 납니다.

700
오퍼 검증하기

검증 API 사용 전에 텐투플레이에 아래의 키 정보를 요청하여 받으십시오.

  • API 키, 비밀키 (인증용)

  • 페이로드 키 (복호화용)

API키 보안

프론트엔드 앱에 API키가 노출되지 않도록 요청 결과를 가져올 때에 백엔드 서버를 통해 결과가 프론트엔드에 전달되도록 하십시오.

API 메소드

오퍼 검증

플레이어가 받은 오퍼 id에 대한 검증 요청

파라미터

헤더 파라미터
이름 설명 자료형 필수여부 기본값

TPApiKey

TentuPlay가 제공한 API 키

string

필수

없음

TPSecretKey

TentuPlay가 제공한 비밀키

string

필수

없음

요청 Body

  • Content type: application/json

이름 설명 자료형 필수여부 기본값

player_uuid

플레이어의 고유 id

string

필수

없음

offer_id

오퍼 id

integer

필수

없음

Body 예시
{
  "player_uuid": "string",
  "offer_id": 10
}

응답

인증 성공
HTTP/1.1 200 OK
Content-Type:application/json
{
    "success": true,	//boolean
    "result": "(string encoded in base64)"
}

응답 데이터는 AES-256-CTR 알고리즘으로 암호화되어있습니다. 결과 문자열은 임시값(nonce)과 암호화된 데이터가 결합되어 있으며 헥사로 인코딩되어 있습니다. 디코딩된 데이터의 앞 12바이트가 임시값입니다.

디코딩 후 데이터 파트는 payload 키를 이용하여 복호화해야 합니다. 가령 다음 예시 코드는 Python으로 쓰여진 복호화 코드입니다.

result = response.data['result']

byte_data = binascii.unhexlify(result.encode('utf-8'))
nonce = byte_data[:8]
encrypted_bytes = byte_data[8:]

cipher = AES.new(payload_key.encode('utf-8'), AES.MODE_CTR, nonce=nonce)
decrypted_bytes = cipher.decrypt(encrypted_bytes)
raw_data = decrypted_bytes.decode('utf-8')

복호화에 성공하면 응답 메시지의 JSON body를 다음 예시와 같이 볼 수 있습니다. 응답 메시지는 오퍼의 종류에 따라 다릅니다.

복호화된 데이터 예시
수동 오퍼 (개인화 오퍼)
{
	"player_uuid": "",
	"offer": {
		"price": 99.99,
		"message": {
			"en": {
				"url": "https://",
				"image": "https://",
				"title": ""
			}
		},
		"product_id": "",
		"product_name": "",
		"discount_rate": 10,
		"discount_price": 89.99,
		"message_layout": "h"
	},
	"is_opened": true,
	"expire_at": "YYYY-MM-DD hh:mm:ss"  // 값이 없으면 기간에 제한이 없음을 의미
}
AI 오퍼 (AI 인게임 상점)
{
	"player_uuid": "",
	"offer": {
		"offer_type": "ai",
		"recommendations": [
			{
				"store": "google",
				"product_list": [
					{
						"purchasable_slug": "diamond_500",
						"product_index": "",
						"purchase_link": "",
						"start_datetime": "YYYY-MM-DD hh:mm:ss",
						"end_datetime": "YYYY-MM-DD hh:mm:ss"
					}
				]
			}
		],
		"display_parameters": {
			"en": {
				"title": "",
				"message": "",
				"background_url": "https://",
				"toggle_message": "don't see me again today"
			}
		},
{
	"player_uuid": "",
	"offer": {
		"offer_type": "ai",
		"recommendations": [
			{
        "store": "google",
        "product_list": [
           {
             "purchasable_slug": "diamond_500",
             "product_index": "",
             "purchase_link": "",
             "start_datetime": "YYYY-MM-DD hh:mm:ss",
             "end_datetime": "YYYY-MM-DD hh:mm:ss"
           }
        ]
	    }
		],
		"display_parameters": {
			"en": {
				"title": "",
				"message": "",
			  "background_url": "https://",
			  "toggle_message": "don't see me again today"
			}
		},
		"message_parameters": {
			"<parameter_in_message>": {
				"entity": "<purchasable|characterarchetype|item|...>",
				"slug": ""
			}
		}
	},
	"is_opened": true,
	"expire_at": "YYYY-MM-DD hh:mm:ss"  // 값이 없으면 기간에 제한이 없음을 의미
}
인증 실패
HTTP/1.1 200 OK
Content-Type:application/json
{
	"success": false,	//boolean
	"code": 0,
	"message": "Cannot find requested offer."
}

검증이 실패하면 `code`에 `0`이 반환됩니다. 이는 `offer_id`에 해당하는 오퍼가 서버에 없다는 의미입니다.