Postback Security
You should verify the signature received in the postback to ensure that the call comes from our servers.
Signature parameter should match MD5 of subId
transactionId
reward
secret key
. You can find your Secret Key
of your website in My Apps. Here is a detailed page for getting your API and Secret Key.
Postback Examples:
<?php
$secret = "YOUR_SECRET_KEY"; // Get it from app placement
// Receive all data
$subId = $_REQUEST['subId'] ?? null;
$payout = $_REQUEST['payout'] ?? null;
$reward = $_REQUEST['reward'] ?? null;
$reward_name = $_REQUEST['reward_name'] ?? null;
$reward_value = $_REQUEST['reward_value'] ?? null;
$offer_name = $_REQUEST['offer_name'] ?? null;
$offer_type = $_REQUEST['offer_type'] ?? null;
$transId = $_REQUEST['transId'] ?? null;
$userIp = $_REQUEST['userIp'] ?? null;
$country = $_REQUEST['country'] ?? null;
$status = $_REQUEST['status'] ?? null;
$debug = $_REQUEST['debug'] ?? null;
$signature = $_REQUEST['signature'] ?? null;
// Validation Example
if (!$subId || !$transId || !$payout || !$reward) {
$response = [
'success' => false,
'message' => 'Missing required parameters'
];
echo json_encode($response);
exit;
}
// Debug validation (only use in production)
if($debug == "true") {
$response = [
'success' => false,
'message' => 'Test postbacks are not allowed'
];
echo json_encode($response);
exit;
}
// Validate Signature
if(md5($subId . $transId . $reward . $secret) != $signature)
{
$response = [
'success' => false,
'message' => 'Signature validation failed'
];
echo json_encode($response);
exit;;
}
// Process the data
// Your business logic goes here
import json
from flask import request, abort
secret = "YOUR_SECRET_KEY" # Get it from app placement
# Receive all data
sub_id = request.args.get('subId')
payout = request.args.get('payout')
reward = request.args.get('reward')
reward_name = request.args.get('reward_name')
reward_value = request.args.get('reward_value')
offer_name = request.args.get('offer_name')
offer_type = request.args.get('offer_type')
trans_id = request.args.get('transId')
user_ip = request.args.get('userIp')
country = request.args.get('country')
status = request.args.get('status')
debug = request.args.get('debug')
signature = request.args.get('signature')
# Validation Example
if not sub_id or not trans_id or not payout or not reward:
response = {
'success': False,
'message': 'Missing required parameters'
}
return json.dumps(response), 400
# Debug validation (only use in production)
if debug == "true":
response = {
'success': False,
'message': 'Test postbacks are not allowed'
}
return json.dumps(response), 400
# Validate Signature
if md5((sub_id + trans_id + reward + secret).encode()).hexdigest() != signature:
response = {
'success': False,
'message': 'Signature validation failed'
}
return json.dumps(response), 400
# Process the data
# Your business logic goes here
const express = require('express');
const crypto = require('crypto');
const app = express();
const port = 3000;
const secret = "YOUR_SECRET_KEY"; // Get it from app placement
// Middleware to parse URL-encoded bodies and JSON
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
// Receive all data
app.all('/your-endpoint', (req, res) => {
const subId = req.body.subId || req.query.subId || null;
const payout = req.body.payout || req.query.payout || null;
const reward = req.body.reward || req.query.reward || null;
const rewardName = req.body.reward_name || req.query.reward_name || null;
const rewardValue = req.body.reward_value || req.query.reward_value || null;
const offerName = req.body.offer_name || req.query.offer_name || null;
const offerType = req.body.offer_type || req.query.offer_type || null;
const transId = req.body.transId || req.query.transId || null;
const userIp = req.body.userIp || req.query.userIp || null;
const country = req.body.country || req.query.country || null;
const status = req.body.status || req.query.status || null;
const debug = req.body.debug || req.query.debug || null;
const signature = req.body.signature || req.query.signature || null;
// Validation Example
if (!subId || !transId || !payout || !reward) {
const response = {
success: false,
message: 'Missing required parameters'
};
res.json(response);
return;
}
// Debug validation (only use in production)
if (debug === "true") {
const response = {
success: false,
message: 'Test postbacks are not allowed'
};
res.json(response);
return;
}
// Validate Signature
const hash = crypto.createHash('md5').update(subId + transId + reward + secret).digest('hex');
if (hash !== signature) {
const response = {
success: false,
message: 'Signature validation failed'
};
res.json(response);
return;
}
// Process the data
// Your business logic goes here
// Example success response
const successResponse = {
success: true,
message: 'Data processed successfully'
};
res.json(successResponse);
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
require 'sinatra'
require 'json'
require 'digest'
SECRET = "YOUR_SECRET_KEY" # Get it from app placement
post '/' do
# Receive all data
sub_id = params['subId']
payout = params['payout']
reward = params['reward']
reward_name = params['reward_name']
reward_value = params['reward_value']
offer_name = params['offer_name']
offer_type = params['offer_type']
trans_id = params['transId']
user_ip = params['userIp']
country = params['country']
status = params['status']
debug = params['debug']
signature = params['signature']
# Validation Example
if sub_id.nil? || trans_id.nil? || payout.nil? || reward.nil?
response = {
success: false,
message: 'Missing required parameters'
}
halt 400, response.to_json
end
# Debug validation (only use in production)
if debug == "true"
response = {
success: false,
message: 'Test postbacks are not allowed'
}
halt 400, response.to_json
end
# Validate Signature
calculated_signature = Digest::MD5.hexdigest("#{sub_id}#{trans_id}#{reward}#{SECRET}")
if calculated_signature != signature
response = {
success: false,
message: 'Signature validation failed'
}
halt 400, response.to_json
end
# Process the data
# Your business logic goes here
response = {
success: true,
message: 'Data processed successfully'
}
content_type :json
response.to_json
end
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import com.fasterxml.jackson.databind.ObjectMapper;
@WebServlet("/processData")
public class DataProcessorServlet extends HttpServlet {
private static final String SECRET = "YOUR_SECRET_KEY"; // Get it from app placement
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
// Receive all data
String subId = request.getParameter("subId");
String payout = request.getParameter("payout");
String reward = request.getParameter("reward");
String rewardName = request.getParameter("reward_name");
String rewardValue = request.getParameter("reward_value");
String offerName = request.getParameter("offer_name");
String offerType = request.getParameter("offer_type");
String transId = request.getParameter("transId");
String userIp = request.getParameter("userIp");
String country = request.getParameter("country");
String status = request.getParameter("status");
String debug = request.getParameter("debug");
String signature = request.getParameter("signature");
response.setContentType("application/json");
PrintWriter out = response.getWriter();
ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> responseMap = new HashMap<>();
// Validation Example
if (isNullOrEmpty(subId) || isNullOrEmpty(transId) || isNullOrEmpty(payout) || isNullOrEmpty(reward)) {
responseMap.put("success", false);
responseMap.put("message", "Missing required parameters");
out.print(mapper.writeValueAsString(responseMap));
out.flush();
return;
}
// Debug validation (only use in production)
if ("true".equalsIgnoreCase(debug)) {
responseMap.put("success", false);
responseMap.put("message", "Test postbacks are not allowed");
out.print(mapper.writeValueAsString(responseMap));
out.flush();
return;
}
// Validate Signature
String concatenatedString = subId + transId + reward + SECRET;
String calculatedSignature = md5Hash(concatenatedString);
if (!calculatedSignature.equals(signature)) {
responseMap.put("success", false);
responseMap.put("message", "Signature validation failed");
out.print(mapper.writeValueAsString(responseMap));
out.flush();
return;
}
// Process the data
// Your business logic goes here
}
private boolean isNullOrEmpty(String param) {
return param == null || param.trim().isEmpty();
}
private String md5Hash(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes());
// Convert byte array into signum representation
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
// Handle the exception as per your application's requirement
return "";
}
}
}
using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Mvc;
public class PostbackController : Controller
{
private const string Secret = "YOUR_SECRET_KEY"; // Get it from app placement
[HttpPost]
public IActionResult ReceivePostback()
{
// Receive all data
string subId = Request.Form["subId"];
string payout = Request.Form["payout"];
string reward = Request.Form["reward"];
string rewardName = Request.Form["reward_name"];
string rewardValue = Request.Form["reward_value"];
string offerName = Request.Form["offer_name"];
string offerType = Request.Form["offer_type"];
string transId = Request.Form["transId"];
string userIp = Request.Form["userIp"];
string country = Request.Form["country"];
string status = Request.Form["status"];
string debug = Request.Form["debug"];
string signature = Request.Form["signature"];
// Validation Example
if (string.IsNullOrEmpty(subId) || string.IsNullOrEmpty(transId) || string.IsNullOrEmpty(payout) || string.IsNullOrEmpty(reward))
{
var response = new
{
success = false,
message = "Missing required parameters"
};
return Json(response);
}
// Debug validation (only use in production)
if (debug == "true")
{
var response = new
{
success = false,
message = "Test postbacks are not allowed"
};
return Json(response);
}
// Validate Signature
using (var md5 = MD5.Create())
{
string input = subId + transId + reward + Secret;
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
string computedSignature = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
if (computedSignature != signature)
{
var response = new
{
success = false,
message = "Signature validation failed"
};
return Json(response);
}
}
// Process the data
// Your business logic goes here
return Json(new { success = true });
}
}
We have not included IP address validation in the examples above for certain reasons. We advise verifying the whitelisted IP addresses; however, it is entirely up to you to use this feature as it is optional and not mandatory.
Don’t forget to check the transId against your database to ensure it doesn’t already exist.
Our servers wait for a response for a maximum time of 60 seconds before the timeout. In this case, postback will be marked as failed. Please, check if the transaction ID sent to you was already entered in your database, this will prevent to give twice the same amount of virtual currency to the user.
IPs to whitelist
We will be sending the postbacks from any of the following IP address(es). Please make sure they are whitelisted if needed to be in your server.
195.35.39.220
Respond to Postback
Our servers will expect your website to respond with "ok". If your postback doesn't return "ok" as response, postback will be marked as failed (even if postback was successfully called) and you will be able to resend it manually from Revtoo.
Last updated