Configure HTTP GET server-to-server (S2S) callbacks to automatically credit users with virtual currency upon completing offers with cryptographic signature verification.
Whenever an end-user completes a task, survey, or tiered game offer, the advertiser network notifies AdVanta. Our engine validates the conversion, checks for fraud, computes your virtual currency payout, and instantly sends an automated HTTP GET request to your configured postback endpoint.
https://your-site.com/api/postback?user={user_id}&reward={reward}&tx={transaction_id}&sig={signature}).Your server endpoint must accept standard HTTP GET requests with dynamic macro tokens enclosed in curly brackets {macro_name}.
https://yourdomain.com/api/postback?user_id={user_id}&reward={reward}&amount={payout}&transaction_id={transaction_id}&status={status}&sig={signature}
https://yourdomain.com/api/postback?user_id={user_id}&reward={reward}&transaction_id={transaction_id}&secret={secret}
You can include any combination of the following supported macro tokens in your postback URL query parameters:
| Macro Token | Description | Example Value |
|---|---|---|
{signature} or {sig} |
Cryptographic HMAC-SHA256 signature computed as hash_hmac('sha256', "{transaction_id}:{user_id}:{reward}", secret). Guarantees tamper-proof payloads. |
a7f8c4e9102b3... |
{secret} |
Your app's private Postback Secret Key. Allows your server to verify that the request originated from AdVanta. | nSDKvzpgnIy0T3xE... |
{user_id} |
The unique user ID you passed when loading the offerwall or tracking link. | usr_9847291 |
{transaction_id} |
Unique transaction identifier generated for each completed lead. | txn_66d2f3a8b41 |
{reward} |
The calculated reward amount in your virtual currency based on your configured exchange rate. | 250 |
{payout} |
The publisher commission amount in USD ($). | 2.50 |
{offer_id} |
The unique identifier of the campaign/offer completed. | 48102 |
{offer_name} |
The title/name of the offer (URL-encoded). | State%20of%20Survival |
{status} |
Conversion status: approved, rejected, or reversed (chargeback). |
approved |
{ip} |
The IP address of the end user when they converted. | 198.51.100.42 |
{country} |
The 2-letter ISO country code of the conversion. | US, DE, GB |
{device} |
The user's device operating system. | android, ios, desktop |
{aff_sub} - {aff_sub4} |
Custom tracking parameters passed in the original click link. | campaign_101 |
Your server MUST respond with an HTTP status code 200 OK within 10 seconds.
The response body should be 1 or OK.
transaction_id has already been processed in your database before crediting points. If already processed, return 200 OK immediately.
<?php
// postback.php
$appSecret = 'YOUR_APP_POSTBACK_SECRET'; // Find in App Details page
$userId = $_GET['user_id'] ?? null;
$transactionId = $_GET['transaction_id'] ?? null;
$rewardAmount = floatval($_GET['reward'] ?? 0);
$status = $_GET['status'] ?? 'approved';
$signature = $_GET['sig'] ?? $_GET['signature'] ?? null;
if (!$userId || !$transactionId) {
http_response_code(400);
exit("Missing parameters");
}
// 1. Verify Cryptographic HMAC Signature
$expectedSig = hash_hmac('sha256', "{$transactionId}:{$userId}:{$rewardAmount}", $appSecret);
if ($signature && !hash_equals($expectedSig, $signature)) {
http_response_code(403);
exit("Invalid Security Signature");
}
// 2. Prevent duplicate crediting (Idempotency)
if (isTransactionAlreadyProcessed($transactionId)) {
http_response_code(200);
exit("DUPLICATE_IGNORED");
}
// 3. Handle conversion status & user wallet crediting
if ($status === 'approved') {
creditUserCoins($userId, $rewardAmount);
logTransaction($userId, $transactionId, $rewardAmount, 'approved');
} elseif ($status === 'reversed' || $status === 'rejected') {
// Chargeback / Fraud Reversal -> Deduct coins
deductUserCoins($userId, $rewardAmount);
logTransaction($userId, $transactionId, $rewardAmount, 'reversed');
}
// 4. Confirm receipt to AdVanta
http_response_code(200);
echo "1";
?>
const crypto = require('crypto');
const express = require('express');
const app = express();
const APP_SECRET = 'YOUR_APP_POSTBACK_SECRET';
app.get('/api/postback', async (req, res) => {
const { user_id, transaction_id, reward, status, sig } = req.query;
if (!user_id || !transaction_id) {
return res.status(400).send("Missing parameters");
}
// 1. Verify HMAC Signature
if (sig) {
const expectedSig = crypto
.createHmac('sha256', APP_SECRET)
.update(`${transaction_id}:${user_id}:${reward}`)
.digest('hex');
if (sig !== expectedSig) {
return res.status(403).send("Invalid Signature");
}
}
// 2. Check Idempotency
const existing = await db.transactions.findOne({ transaction_id });
if (existing) {
return res.status(200).send("DUPLICATE_IGNORED");
}
// 3. Process user reward or chargeback deduction
if (status === 'approved') {
await db.users.updateOne({ id: user_id }, { $inc: { balance: Number(reward) } });
await db.transactions.create({ transaction_id, user_id, amount: reward, status });
} else if (status === 'reversed' || status === 'rejected') {
await db.users.updateOne({ id: user_id }, { $inc: { balance: -Number(reward) } });
}
return res.status(200).send("1");
});
You can simulate live server-to-server postbacks (including signature checks and chargebacks) at any time using our built-in simulator:
Open Live Postback Simulator →