Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

To reward users, it is necessary to integrate the Reward Request Postback API. Postback requests are conducted in a Server-to-Server communication format for security purposes.

Summary of Procedures

1. Establish a server endpoint capable of receiving reward requests from Buzzvil (we refer to this endpoint's URL as the postback URL).

2. Perform Server-to-Server integration as instructed in this guide.

3. Provide the postback URL to Buzzvil's Technical Support Manager.

Index

Introduction

This API is designed to inform publishers when users receive points through Buzzvil, allowing them to send accrual requests.

항목

내용

1

Request Direction

Buzzvil → Publisher

2

HTTP Request method

POST - application/x-www-form-urlencoded

3

HTTP Request URL

Endpoint on the publisher’s server

4

HTTP Request Parameters

Refer to the below “HTTP Request Parameters” table

5

HTTP Response Code

The Buzzvil server determines whether the result of the reward request was successful based on the response code received from the publisher’s server.

  • 200 (OK), 204 (No Content), 409 (Duplicate Request): SUCCESSFUL

    • Response codes when the publisher server successfully processes the request (points accrued to the user)

    • Resond with 409 when the server’s already accrued points to the user but duplicate requests were received

  • Response codes other than 200, 204, 409: FAILED

    • Retry postback request up to 5 times

    • Retry intervals are roughly 1 minute, 10 minutes, 1 hour, 3 hours, and 24 hours from initial failure

Response codes other than 200: Refer to standard HTTP response codes

Even if the body contains error content, no retry postback will be attempted if the response code is 200

HTTP Request Parameters

If the String type value of the parameter field is in Korean, the value will be encoded in Unicode.

Field

Type

Description

user_id

REQUIRED

String 
(max 255)

User identifier defined by the publisher

transaction_id

REQUIRED

String 
(max 32)

ID issued for the reward. Used to identify each reward and prevent duplicate point issuance.

The same transaction_id is used for postback retries.

Please ensure that rewards are not granted to users for duplicate requests.

point

REQUIRED

Integer

Amount of reward that should given to the user

unit_id

REQUIRED

Long

Identifier for the specific area where ads are placed.

For instance, if ads are placed on the lower banner area on an app’s “Home” tab, an ID will be issued for the ad placement area (view).

This ID will be issued by Buzzvil.

title

REQUIRED

String
(max 255 in Korean)

Ad title

  • i.e 출시 임박! 해당 CPS 상품을 먼저 만나보세요! 😁 #Buzzvil #환상적

  • Reward requests could occur for non-ad products. In this case, the value is empty.

action_type

REQUIRED

String
(max 32)

Refers to the action type of the reward request

  • opened: opened Feed

  • u: unlocked

  • l: landed

  • a: action (when the user performed the required missions for an ad)

  • won: won Potto

  • manual: manual postback requested

  • spinned : spinned roulette

  • daily : Feed daily reward event

More action types can be added as products are released

event_at

REQUIRED

Long (timestamp)

Timestamp of point issuance (UNIX Timestamp in seconds)

The timestamp will mostly be the same as the API call time, but could differ in cases of API call retries

extra

REQUIRED

String
(max 1024)

If additional parameters need to be added, use this parameter (JSON serialized string value)

  • 매체사가 지정한 캠페인 데이터 (대시보드에서 캠페인을 생성할 때 지정할 수 있습니다)

    • e.g {"sub_type": "A", "source":"external"}

data

OPTIONAL

String

Parameter used if encrypting HTTP request parameters

For details about encrypting request paremeters, refer to the below “HTTP Request Parameter Encryption/Decryption” section.

c

OPTIONAL

String

Parameter used when sending a Checksum to the HTTP request parameters

For details, refer to the below “Add Checksum Parameter” section.

custom2

OPTIONAL

String
(max 255)

Custom Parameter specified by the publisher when integrating S2S APIs

  • Value will be included in the reward request postabck

  • value up to custom 4 can be transmitted

custom3

OPTIONAL

String
(max 255)

Custom Parameter specified by the publisher when integrating S2S APIs

  • Value will be included in the reward request postabck

  • value up to custom 4 can be transmitted

custom4

OPTIONAL

String
(max 255)

Custom Parameter specified by the publisher when integrating S2S APIs

  • Value will be included in the reward request postabck

  • value up to custom 4 can be transmitted

HTTP Request Parameter Postback Example

{
  "user_id": "12345",
  "point": 1,
  "transaction_id": "126905422_10000001",
  "event_at": 1641452397,
  "unit_id": 5539189976900000,
  "action_type": "l",
  "title": "\uad11\uace0\u0020\ud2b9\uac00",
  "extra": "{}"
}

IP Whitelist

To receive reward request postbacks from Buzzvil servers, please whitelist the following IPs on your firewall.

  • 54.64.39.245

  • 52.68.114.43

  • 13.113.136.11

  • 52.194.132.196

  • 13.114.88.146

Request Parameter Verification OPTIONAL

It is possible to encrypt or add verifications for reward request postbacks sent from the Buzzvil server. This process is not mandatory but provides two methods if needed.

1. HTTP Request Parameter Encryption/Decryption

If you want to encrypt the HTTP request parameters sent from the Buzzvil server to the media, use this method. The encryption method provided is the Advanced Encryption Standard (AES), with AES-256 as the block encryption and using Cipher Block Chaining (CBC) mode and PKCS7 padding.

 Procedure

Prerequisites

  • Obtain the following values for AES-256 encryption through Buzzvil Manager:

    • AES Key (length: 32)

    • AES IV (length: 16)

  • Before providing the AES Key and IV to the publisher, the publisher must generate private and public keys using RSA-1024, and provide the public key to the Buzzvil Manager.

  • The Buzzvil Manager will encrypt the AES Key and IV, and provide the values to the publisher. The publisher should use the private key to decrypt the values.

Steps for Encryption/Decryption

  1. Buzzvil server encrypts HTTP request parameters.

    1. Apply UTF-8 encoding to the JSON-serialized parameters (string).

    2. Apply PKCS7 padding and proceed with AES encryption on the string.

    3. Perform base64 encoding on the encrypted value

  2. Add the encrypted value to the HTTP POST request as data.

    1. e.g

      {
        "data": "cg087LiIp30jCWpc3MVLfxPL4F05OFGGCkQwwpS6pRVMZhkumzfTFxc8iBoZ8unI15uk0cmY+CbSeOaLHsd7PaxsbyKISiJ31WJJ1OwfaYttoMwFysKNfL7pSz2HB9ULWZicG8MSPxCPKr9RDqgOXpuEoVm9YR3I4yNE5M0LNltpCTdXRBjTrOcjp+RtEZ1VENtHqTICK18nDqO+91BUt3AJsf4VmzogJ8UpA0izEbY="
      }
  3. The publisher performs the following decryption steps:

    • Base64 decoding

    • Decrypt the string after PKCS7 padding removal

    • Decode the string in UTF-8

 

Example

  • AES decryption Key and IV: buzzvil123456789

{
  "unit_id":"12345",
  "transaction_id":"10000000_1",
  "user_id":"buzzvil",
  "point": 1,
  "action_type":"won",
  "event_at": 1599622182,
  "title":"title",
  "extra": "{}"
}

  • Encrypted data from JSON (UTF-8encoding) → AES encryption → base64 encoding

    cg087LiIp30jCWpc3MVLfxPL4F05OFGGCkQwwpS6pRVMZhkumzfTFxc8iBoZ8unI15uk0cmY+CbSeOaLHsd7PaxsbyKISiJ31WJJ1OwfaYttoMwFysKNfL7pSz2HB9ULWZicG8MSPxCPKr9RDqgOXpuEoVm9YR3I4yNE5M0LNltpCTdXRBjTrOcjp+RtEZ1VENtHqTICK18nDqO+91BUt3AJsf4VmzogJ8UpA0izEbY=

 

  • When decrypted:

    • base64 decoding

      r\r<\xec\xb8\x88\xa7}#\tj\\\xdc\xc5K\x7f\x13\xcb\xe0]98Q\x86\nD0\xc2\x94\xba\xa5\x15Lf\x19.\x9b7\xd3\x17\x17<\x88\x1a\x19\xf2\xe9\xc8\xd7\x9b\xa4\xd1\xc9\x98\xf8&\xd2x\xe6\x8b\x1e\xc7{=\xaclo"\x88J"w\xd5bI\xd4\xec\x1fi\x8bm\xa0\xcc\x05\xca\xc2\x8d|\xbe\xe9K=\x87\x07\xd5\x0bY\x98\x9c\x1b\xc3\x12?\x10\x8f*\xbfQ\x0e\xa8\x0e^\x9b\x84\xa1Y\xbda\x1d\xc8\xe3#D\xe4\xcd\x0b6[i\t7WD\x18\xd3\xac\xe7#\xa7\xe4m\x11\x9dU\x10\xdbG\xa92\x02+_\'\x0e\xa3\xbe\xf7PT\xb7p\t\xb1\xfe\x15\x9b: \'\xc5)\x03H\xb3\x11\xb6

       

    • AES decryption) Key, IV: buzzvil123456789

      {"unit_id": "12345", "transaction_id": "10000000_1", "user_id": "buzzvil", "point": 1, "action_type": "won", "event_at": 1599622182, "title": "title", "extra": "{}"}

       

    • UTF-8 decoding

      {"unit_id": "12345", "transaction_id": "10000000_1", "user_id": "buzzvil", "point": 1, "action_type": "won", "event_at": 1599622182, "title": "title", "extra": "{}"}

      (memo) Since there is no Korean in the above example, there is no need for UTF-8 decoding

Sample Code

 Java 1.8+
import java.lang.RuntimeException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.*;
import javax.crypto.spec.SecretKeySpec;

public class Main {
    public static void main(String[] args) {
        String aesKey = "BuzzvilAESKeyTest123456789101112";
        String aesIV = "0000000000000000";

        // Check to make sure encryption is compatible with Buzzvil
        String toBuzzvilMessage = "{\"success\": 1, \"reason\": \"중복 적립 요청\"}";
        String encrypted = encrypt(toBuzzvilMessage, aesKey, aesIV);
        System.out.println("----encrypted----\n"+encrypted);
        System.out.println("buzzvil encryption compatible? YES");

        // Check to make sure values coming from Buzzvil is decryptable
        String fromBuzzvilEncrypted = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw==";
        String fromBuzzvilDecrypted = "{\"point\": 1, \"user_id\": \"buzzvil_test\", \"transaction_id\": \"100004_100000000\", \"event_at\": 1588936508, \"campaign_name\": \"버즈빌 테스트 campaign_name\", \"extra\": \"{}\", \"action_type\": \"l\", \"base_point\": 1, \"campaign_id\": 202010160022, \"is_media\": 1, \"unit_id\": 452613281179508, \"revenue_type\": \"cpm\"}";

        String decrypted = decrypt(fromBuzzvilEncrypted, aesKey, aesIV);
        System.out.println("----decrypted-----\n"+decrypted);
        System.out.println("buzzvil decryption compatible? "+fromBuzzvilDecrypted.equals(decrypted));
    }

    static String encrypt(String message, String key, String iv) {
        try {
            // 1. encode in utf-8
            byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);

            // 2. encrypt message through AES CBC with PKCS7
            byte[] encrypted = aes(messageBytes, key, iv, Cipher.ENCRYPT_MODE);

            // 3. encode in base64
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    static String decrypt(String message, String key, String iv) {
        try {
            // 1. decode base64 message
            byte[] base64DecodedBytes = Base64.getDecoder().decode(message);

            // 2. decrypt message through AES CBC with PKCS7
            byte[] decrypted = aes(base64DecodedBytes, key, iv, Cipher.DECRYPT_MODE);

            // 3. decode in utf-8
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    static byte[] aes(byte[] messageBytes, String key, String iv, int cipherMode) {
        try {
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
            byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);

            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(cipherMode, keySpec, ivSpec);

            return cipher.doFinal(messageBytes);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }
    }
}
 PHP 7.0+
<?php
function encrypt($str, $mode, $key, $iv) {
    $encrypted = openssl_encrypt($str, $mode, $key, OPENSSL_RAW_DATA, $iv);
    return base64_encode($encrypted);
}
 
function decrypt($str, $mode, $key, $iv) {
    $text = base64_decode($str);
    return openssl_decrypt($text, $mode, $key, OPENSSL_RAW_DATA, $iv);
}
 
$mode = "AES-256-CBC";
 
$key = "BuzzvilAESKeyTest123456789101112";
$iv = "0000000000000000";

$plaintext = '{"success": 1, "reason": "중복 적립 요청"}';
$encrypted = encrypt($plaintext, $mode, $key, $iv);
print ("ENCRYPTED: ".$encrypted."\n");
// +VEmHrt+jwI6Dg2zImdGtI+iIQEqV8v5btpS1a3cdEQBzIc72V9aKju5m6+ELTBixbITMBoHIYjj8jJbsKbIgg==

$fromBuzzvil = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw==";
$decrypted = decrypt($fromBuzzvil, $mode, $key, $iv);
print("DECRYPTED: ".$decrypted);
/*
{"point": 1, "user_id": "buzzvil_test", "transaction_id": "100004_100000000", "event_at": 1588936508, "campaign_name": "버즈빌 테스트 campaign_name", "extra": "{}", "action_type": "l", "base_point": 1, "campaign_id": 202010160022, "is_media": 1, "unit_id": 452613281179508, "revenue_type": "cpm"}
*/
?>
 Python 2.7+ & Python 3.6+

Python 2.7+

# -*- coding:utf-8 -*-
import base64
# https://pypi.python.org/pypi/pycryptodome/3.9.9
from Crypto.Cipher import AES
# https://pypi.python.org/pypi/pkcs7/0.1.2
from pkcs7 import PKCS7Encoder

def encrypt(message, key, iv):
	message_plaintext_padded = PKCS7Encoder().encode(message)
	cipher = AES.new(key, AES.MODE_CBC, iv)
	message_encrypted_raw = cipher.encrypt(message_plaintext_padded)
	return base64.b64encode(message_encrypted_raw)

def decrypt(message, key, iv):
	message_decoded = base64.b64decode(message)
	cipher = AES.new(key, AES.MODE_CBC, iv)
	messaged_decrypted_padded = cipher.decrypt(message_decoded)
	message_plaintext_decoded = PKCS7Encoder().decode(messaged_decrypted_padded)	
	return message_plaintext_decoded

iv = '0000000000000000'
key = 'BuzzvilAESKeyTest123456789101112'

plaintext = '{"success": 1, "reason": "중복 적립 요청"}'
encrypted = encrypt(plaintext, key, iv)
print "ENCRYPTED: {}".format(encrypted)
# +VEmHrt+jwI6Dg2zImdGtI+iIQEqV8v5btpS1a3cdEQBzIc72V9aKju5m6+ELTBixbITMBoHIYjj8jJbsKbIgg==

from_buzzvil = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw=="
decrypted = decrypt(from_buzzvil, key, iv)
print "DECRYPTED: {}".format(decrypted)
#{"point": 1, "user_id": "buzzvil_test", "transaction_id": "100004_100000000", "event_at": 1588936508, "campaign_name": "버즈빌 테스트 campaign_name", "extra": "{}", "action_type": "l", "base_point": 1, "campaign_id": 202010160022, "is_media": 1, "unit_id": 452613281179508, "revenue_type": "cpm"}

Python 3.6+

# -*- coding:utf-8 -*-
import base64
# https://pypi.python.org/pypi/pycryptodome/3.9.9
from Crypto.Cipher import AES
from binascii import unhexlify

BLOCK_SIZE = 16

def encrypt(message, key, iv):
	message_plaintext_padded = pad(message).encode('utf-8')
	cipher = AES.new(key, AES.MODE_CBC, iv)
	message_encrypted_raw = cipher.encrypt(message_plaintext_padded)
	return base64.b64encode(message_encrypted_raw)

def decrypt(message, key, iv):
	message_decoded = base64.b64decode(message)
	cipher = AES.new(key, AES.MODE_CBC, iv)
	messaged_decrypted_padded = unpad(cipher.decrypt(message_decoded))
	return messaged_decrypted_padded.decode('utf-8')

def pad(s):
	return s + (BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE)

def unpad(s):
	return s[:-ord(s[len(s)-1:])]

iv = '0000000000000000'.encode('utf-8')
key = 'BuzzvilAESKeyTest123456789101112'.encode('utf-8')

plaintext = '{"success": 1, "reason": "중복 적립 요청"}'
encrypted = encrypt(plaintext, key, iv)
print ("ENCRYPTED: {}".format(encrypted))
# +VEmHrt+jwI6Dg2zImdGtI+iIQEqV8v5btpS1a3cdEQBzIc72V9aKju5m6+ELTBixbITMBoHIYjj8jJbsKbIgg==

from_buzzvil = "IGCdundUBkXf3s7VXl0pqIKDSC/KGc2j8n1DBLKLZAHqkYlG+aWW+G5hGLvoNeUjlI42FtJLpwGUYbFlhy0QXLQv1Z+P7iUOyJrhujmFWX1FdJ5ZBefA5aceGiOlN119NPAX3JOuUAf45HkWG52NcdaHOzWu8rTnghSeLPo9QK0t6l/2gSFvGtOfZolnAHNZAeGEmcqAkhPmUoFtRAW+Zh6TNQY68FrSUI/XYc87Ky0ndaug1Kf7Ogbf8zLK+tJ4LdTCn9A+wcWxEpdkX45f1r/8jTIUK/s1PqBirXFuruq5/XhkhFmdq/I0qBAJ0uxBnk+29GaEQVMtYTzB+eJWTgrQzKhN6Nww2XEPEOl27yH+K0F+sj8QpZ0jkPETadP0gpwKMKv3zlA6xyndIYWrpw=="
decrypted = decrypt(from_buzzvil, key, iv)
print ("DECRYPTED: {}".format(decrypted))
#{"point": 1, "user_id": "buzzvil_test", "transaction_id": "100004_100000000", "event_at": 1588936508, "campaign_name": "버즈빌 테스트 campaign_name", "extra": "{}", "action_type": "l", "base_point": 1, "campaign_id": 202010160022, "is_media": 1, "unit_id": 452613281179508, "revenue_type": "cpm"}

2. Add Checksum Parameter

Use this method if you want to add a checksum parameter to Request Parameters for postback data verification. The provided verification method is HMAC authentication using the SHA-256 algorithm.

 Procedure

Prerequisites

Obtain the following values for HMAC authentication through Buzzvil Manager:

  • HMAC Key (maximum length: 64)

Steps

  1. Generate a string in the following format using the transaction_id, user_id, point, and event_at values from the received postback parameters (referred to as msg).

    1. Caution: The msg value should be encoded, and there should be no spaces between each parameter string and colon.

      msg=u'{0}:{1}:{2}:{3}'.format(
      							params['transaction_id'],
                          		params['user_id'],
                                  params['point'],
                          		params['event_at'],
                      		).encode('utf-8')

       

  2. Encrypt the msg value using the HMAC SHA-256 algorithm.

    • key: hmac_key

    • data: msg

  3. Compare the resulting value with the c field value received in the postback parameters to confirm the match.

    • Result Length: 64 characters

Example

  • hmac_key = 12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh

    {
        "transaction_id": 429482977,
        "user_id": "testuserid76301",
        "point": 2,
        "event_at": 1849274,
        "c": "43ad5b2639e3363d81879e0ac441a14a369993a0cc6a1f21921f8344cb2612eb"
    }
  • msg = 429482977:testuserid76301:2:1849274

  • No labels