Back to Dashboard
Offerwall & SDK
Web SDK & Iframe Offerwall REST API
API Reference
API Authentication Request Parameters JSON Responses
Webhooks & Postbacks
Reward Apps Postback Global Account Postback
Advertisers & Tracking
Direct CPA/CPI Campaigns S2S Postback & MMPs
Monetization Lockers
Content Locker Link Locker
Webhooks & S2S Callbacks

Reward Apps Server Postback Integration 🔄

Configure HTTP GET server-to-server (S2S) callbacks to automatically credit users with virtual currency upon completing offers with cryptographic signature verification.

How App Postbacks Work

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.

1. Quick Setup Steps

  1. Log in to your Publisher Workspace.
  2. Navigate to My Apps & Placements and select your app.
  3. Copy your unique Postback Secret Key.
  4. Click Edit Placement and enter your server callback URL with security tokens (e.g. https://your-site.com/api/postback?user={user_id}&reward={reward}&tx={transaction_id}&sig={signature}).
  5. Save changes and test using the Postback Simulator.

2. Postback URL Structure & Security Formats

Your server endpoint must accept standard HTTP GET requests with dynamic macro tokens enclosed in curly brackets {macro_name}.

Recommended: Cryptographic HMAC Signature Format
https://yourdomain.com/api/postback?user_id={user_id}&reward={reward}&amount={payout}&transaction_id={transaction_id}&status={status}&sig={signature}
Alternative: Secret Key Token Format
https://yourdomain.com/api/postback?user_id={user_id}&reward={reward}&transaction_id={transaction_id}&secret={secret}

3. Complete Macro Reference

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

4. Server Response Requirements

Success Response (HTTP 200 OK)

Your server MUST respond with an HTTP status code 200 OK within 10 seconds. The response body should be 1 or OK.

Idempotency & Duplicate Prevention

Crucial Rule: Always check if the incoming transaction_id has already been processed in your database before crediting points. If already processed, return 200 OK immediately.

5. Ready-to-Use Secure Server Verification (PHP & Node.js)

PHP with HMAC Signature Verification
<?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";
?>
Node.js Express with HMAC Verification
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");
});

6. Testing Your Postback Endpoint

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 →