Verify Offer

Overview

When an offer is given and the player accept the offer by clicking an associated button such as Purchase, it is necessary to verify the offer by using a REST API before proceeding. With the verfication API, you can make sure that the offer is sent from TentuPlay server when it comes to both validity and integrity without any possible security threats. Verifying offer goes for both personalized offer and AI in-game shop offer with different response body.

TentuPlay Verifying Offer
Offer Verification Sequence

Before consuming the API, please request and obtain the following keys from TentuPlay.

  • API key and secret key: for authentication

  • Payload key: for payload decryption

Security of API keys

To prevent you API keys from exposing in your public front-end apps, make sure that you use a back-end server as a relay to retrieve the API results and then pass them on to your front-end.

API Endpoints

Offer Verifcation

Request verification of an offer ID given to a player

Parameters

Header Parameters
Name Description Type Required Default

TPApiKey

API key from TentuPlay

string

required

null

TPSecretKey

Secret key from TentuPlay

string

required

null

Request Body

  • Content type: application/json

Name Description Type Required Default

player_uuid

Player’s uuid

string

required

null

offer_id

Offer ID

integer

required

null

Body example
{
  "player_uuid": "string",
  "offer_id": 10
}

Responses

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

Tentuplay encrypts response data with AES-256-CTR algorithm. The result string is a combination of nonce and encrypted data with hex encoded. Nonce is the first 12 bytes of decoded data.

After hex decoding, the data part is to be decrypted with the payload key. For instance, the following is an example decryption code written in 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')

On successful decryption, the response JSON body will be shown as one of the following examples depending on offer type:

Decrypted data example
Manual Offer (Personalized Offer)
{
	"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"  // if null, it means no limit on period
}
AI Offer (AI in-game shop)
{
	"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"  // if null, it means no limit on period
}
Failed Verification
HTTP/1.1 200 OK
Content-Type:application/json
{
	"success": false,	//boolean
	"code": 0,
	"message": "Cannot find requested offer."
}

If the verification is failed, 0 is returned in code, which means there is no offer in server matchd to offer_id.