Explore

Callbacks

Purpose of Callbacks

When a user completes a survey or encounters a screenout, we send a callback. This notifies your server that one of your users has successfully completed a survey or experienced a screenout. You can utilize this information to reward your users. Customize the callback link to include all necessary parameters for rewarding your users.

To do so, customize your callback URL with the desired parameters.

Types of Callbacks

Flukelabs will send a callback for every transaction involving payments or rewards. Currently, Flukelabs sends these callback types:

  • Credit: A callback sent when a user earns credits or rewards.
  • Chargeback: A callback sent when a previously credited amount is reversed.
  • Test: A callback sent for testing purposes to simulate transactions without actual rewards.

Params Info

Params Explanation Data Type
{userId} Unique identifier for the user Varchar
{userAmount} The amount in your Virtual Currency that you need to credit to your user. Float
{pubAmount} The amount in USD we paid to your publisher's Account. Float
{ip} User's IP address String
{txId} Transaction ID Varchar
{offerType} Type of offer completed by User . ("offer" , "ptc" , "shortlink" , "game" , "faucet", "coupon", "contest") String
{type} Type of transaction (credit, chargeback, test) String
{hash} SHA256 hash of {userId} + appSecret + {txId} Varchar

CallBack Demo Codes

Below codes are for demo purposes and for developing the understanding of logic .


function flukelabs() {
    $secret = "secretkey";
    $userId = $this->request->getGet('userId');
    $transactionId = $this->request->getGet('txId');
    $reward = $this->request->getGet('userAmount');
    $userIp = $this->request->getGet('ip') ?? "0.0.0.0";
    $signature = $this->request->getGet('hash');

    if (hash('sha256', $userId . $secret . $transactionId) !== $signature) {
        return "signature error";
        die();
    }

    // check for double callback by checking txId
    if (!$isTxIdExists) {
        // pay your user logic ,if credit
        // chargeback if type is chargeback
        echo "OK";
    }
}
      

const express = require('express');
const axios = require('axios');
const crypto = require('crypto');
const router = express.Router();

router.get('/flukelabs', async (req, res) => {
    const secret = "secretkey";
    const { userId, txId, userAmount, ip, hash } = req.query;

    if (crypto.createHash('sha256').update(userId + secret + txId).digest('hex') !== hash) {
        return res.send("signature error");
    }

    // Check for double callback by checking txId
    if (!isTxIdExists) {
        // Pay your user logic if credit
        // Chargeback if type is chargeback
        app.get('/route', function(req, res) {
        res.send('OK');
});

        
    }
});
    

use sha2::{Digest, Sha256};

fn flukelabs(userId: &str, txId: &str, userAmount: &str, ip: &str, hash: &str) -> String {
    let secret = "secretkey";

    let signature = format!("{}{}{}", userId, secret, txId);
    let calculated_hash = format!("{:x}", Sha256::digest(signature.as_bytes()));

    if calculated_hash != hash {
        return String::from("signature error");
    }

    // Check for double callback by checking txId
    if !is_tx_id_exists() {
        // Pay your user logic if credit
        // Chargeback if type is chargeback
    }

    String::from("OK")
}
    

import hashlib

def flukelabs(userId, txId, userAmount, ip, hash):
    secret = "secretkey"
    calculated_hash = hashlib.sha256((userId + secret + txId).encode()).hexdigest()

    if calculated_hash != hash:
        return "signature error"

    # Check for double callback by checking txId
    if not is_tx_id_exists:
        # Pay your user logic if credit
        # Chargeback if type is chargeback

    return "OK"
    

#include 
#include 
#include 

std::string flukelabs(std::string user_id, std::string tx_id, std::string amount, std::string ip, std::string hash) {
    std::string secret = "secretkey";
    std::string signature = user_id + secret + tx_id;

    unsigned char shaResult[SHA256_DIGEST_LENGTH];
    SHA256(reinterpret_cast(signature.c_str()), signature.length(), shaResult);

    std::stringstream ss;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        ss << std::hex << static_cast(shaResult[i]);
    }
    std::string calculated_hash = ss.str();

    if (calculated_hash != hash) {
        return "signature error";
    }

    // Check for double callback by checking txId
    if (!is_tx_id_exists()) {
        // Pay your user logic if credit
        // Chargeback if type is chargeback
    }

    return "OK";
}
    

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Flukelabs {

    public String flukelabs(String userId, String txId, String amount, String ip, String hash) {
        String secret = "secretkey";
        String signature = userId + secret + txId;

        String calculatedHash = "";
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] encodedHash = digest.digest(signature.getBytes());
            calculatedHash = bytesToHex(encodedHash);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        if (!calculatedHash.equals(hash)) {
            return "signature error";
        }

        // Check for double callback by checking txId
        if (!isTxIdExists()) {
            // Pay your user logic if credit
            // Chargeback if type is chargeback
        }

        return "OK";
    }

    private static String bytesToHex(byte[] hash) {
        StringBuilder hexString = new StringBuilder(2 * hash.length);
        for (byte b : hash) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    private boolean isTxIdExists() {
        // Implementation for checking txId existence
        return false;
    }
}
    

Expected Response

Whitelist IP : 37.60.253.153

const virtualCurrencyAmount = 100;
const virtualCurrencyName = 'Coins';

const response = {
    status: 'OK',
    remark: `Rewarded ${virtualCurrencyAmount} in ${virtualCurrencyName}`
};

console.log(response);
    

virtual_currency_amount = 100
virtual_currency_name = 'Coins'

response = {
    'status': 'OK',
    'remark': f'Rewarded {virtual_currency_amount} in {virtual_currency_name}'
}

print(response)
    

use serde_json::json;

fn main() {
    let virtual_currency_amount = 100;
    let virtual_currency_name = "Coins";

    let response = json!({
        "status": "OK",
        "remark": format!("Rewarded {} in {}", virtual_currency_amount, virtual_currency_name)
    });

    println!("{}", serde_json::to_string_pretty(&response).unwrap());
}
    

#include 
#include 

using json = nlohmann::json;

int main() {
    int virtual_currency_amount = 100;
    std::string virtual_currency_name = "Coins";

    json response = {
        {"status", "OK"},
        {"remark", "Rewarded " + std::to_string(virtual_currency_amount) + " in " + virtual_currency_name}
    };

    std::cout << response.dump(4) << std::endl;

    return 0;
}
    

import com.google.gson.Gson;

public class Main {
    public static void main(String[] args) {
        int virtualCurrencyAmount = 100;
        String virtualCurrencyName = "Coins";

        Gson gson = new Gson();
        String response = gson.toJson(new Response("OK", "Rewarded " + virtualCurrencyAmount + " in " + virtualCurrencyName));

        System.out.println(response);
    }

    static class Response {
        String status;
        String remark;

        Response(String status, String remark) {
            this.status = status;
            this.remark = remark;
        }
    }
}
    

$virtualCurrencyAmount = 100;
$virtualCurrencyName = 'Coins';

$response = [
    'status' => 'OK',
    'remark' => "Rewarded $virtualCurrencyAmount in $virtualCurrencyName"
];

echo json_encode($response, JSON_PRETTY_PRINT);