Skip to main content

Server-to-Server Postbacks (v3)

[Recommended] Server-to-server postbacks deliver conversion events to your server using a POST request with a signed, structured JSON body. This is the production-grade reward path nearly every publisher uses.

AdGem can send postbacks for reward events and install events.

Reward Postbacks

These postbacks correspond to a player converting on a rewarded goal. Most offer goals are of this type. The conversion_type field will indicate this with a value of "reward".

Install Postbacks

Note

By default, AdGem only sends postbacks on Payable Conversion events. If you would like to enable Install postbacks to be sent to you, please reach out to your dedicated Publisher Support Advocate so we can enable this for you!

These postbacks correspond to a player completing an install goal. Install goals are used primarily for tracking purposes, and they do not reward the player with in-game currency. The conversion_type field will indicate this with a value of "install".

Setting Up Your Postback

Enabling Server Postback

From the AdGem Dashboard navigate to Properties & Apps and choose Edit from the Options drop down menu.

Edit button in dashboard

Once on the Properties & Apps menu, scroll down until you see Postback Options. Click on the radio input next to Server Postback.

Postback options in dashboard

Several new fields will appear that will allow you to configure your server postback.

Postback Key

The first field is your Postback Key. Copy this key to a secure place as you will need it to verify postback signatures. For security reasons, the Postback Key will only be visible once. See the Securing Your Postbacks section below to learn more about this important feature.

Postback keys in dashboard

Postback URL

Next, you will need to provide a Postback URL hosted on your server. A POST request will be made to the postback URL defined in your AdGem publisher dashboard every time a conversion occurs from your traffic sources.

Postback URL for POST method

Receiving AdGem Postbacks

Here is an example of the request body:

{
"request_id": "01786456-b959-404a-baa7-05ef8a2e0290",
"timestamp": 1720727170,
"data": {
"app_id": "2",
"campaign_id": "1",
"player_id": "bernhard.edison",
"amount": 150,
"payout": 1.5,
"all_goals_completed": 1,
"conversion_id": "c5eb2a9d-41a4-4088-80bb-ebc87bd1bb62",
"app_version": "1.0",
"ad_type": "offerwall",
"country": "US",
"c1": "custom value 1",
"c2": "custom value 2",
"c3": "custom value 3",
"c4": "custom value 4",
"c5": "custom value 5",
"gaid": "bk9384xs-p449-96ds-r132",
"idfa": "AB1234CD-E123-12FG-J123",
"ip": "24.24.24.25",
"os_version": "10.0.0",
"platform": "Other",
"state": "New York",
"click_datetime": "2024-07-15 10:39:55",
"conversion_datetime": "2024-07-15 10:39:55",
"goal_name": "Reach level 20",
"goal_id": "12345678911123456",
"offer_name": "Romaguera-Harber",
"tracking_type": "CPA",
"allow_multiple_conversions": false,
"store_id": "com.whatever.example",
"offer_id": "12345678900123456",
"conversion_type": "reward"
}
}

Request Body Fields

Only request_id and timestamp are sent at the top level. All other fields below are nested inside the top-level data object, as shown in the example above.

FieldDescription
request_idA unique ID for this postback request
timestampUnix timestamp (seconds since epoch) of when the postback was sent
app_idThe unique ID for your app on AdGem
campaign_idThe unique ID of the campaign/offer that was completed
player_idThe unique ID of the player/user on your system
amountThe amount of virtual currency to reward the user who completed the offer
payoutThe decimal amount of revenue earned from the user completing the offer
all_goals_completedIndicates if all goals have been completed for the campaign
conversion_idThe unique AdGem ID of the offer conversion
app_versionThe version of your app where the click originated
ad_typeThe type of ad unit where the click originated (for example offerwall)
countryThe location (i.e., the ISO country code) of the user when the offer was completed
c1A custom parameter value as set by the publisher
c2A custom parameter value as set by the publisher
c3A custom parameter value as set by the publisher
c4A custom parameter value as set by the publisher
c5A custom parameter value as set by the publisher
gaidGoogle advertising ID, available when the developer is using Google Play services
idfaApple advertising ID, available when the user has not limited ad tracking
ipThe IP address for the user who completed the offer
os_versionThe user's operating system version number
platformThe platform this user's device is using (for example, iOS)
stateThe user's state or region where they are located
click_datetimeThe exact date and time when the user clicked on the offer
conversion_datetimeThe exact date and time when the user completed the offer
goal_nameIndicates the name of the completed goal
goal_idIndicates the unique ID of each goal in a campaign/offer that was completed
offer_nameThe name of the campaign/offer that was completed as it shows in the Offerwall/API call
tracking_typeThe type of offer/campaign completed (for example, CPI, CPE, CPA, CPC, Market Research)
allow_multiple_conversionsBoolean indicating if an offer allows for multiple conversions
store_idThe unique ID of the app campaign, as assigned by the Google Play Store or Apple App Store
offer_idThe unique offer version with which the user engaged
conversion_typeThe type of the conversion (for example, "install" when the amount is 0, otherwise "reward")

Securing Your Postbacks

We provide two security measures for securing postback communication between AdGem and your server:

  1. IP Whitelisting - Verify the postback comes from AdGem's static IP
  2. Postback Hashing - Cryptographic verification of the postback integrity
Recommendation

We strongly recommend implementing both security measures to ensure postbacks are genuine. Without proper security, malicious actors could send fake postback requests to fraudulently earn virtual currency.

IP Whitelisting

Postbacks are sent from a static IP address. Whitelist this IP on your server. Contact support@adgem.com or your Publisher Support Advocate to get the production IP address.

Postback Hashing (v2 - GET Requests)

When you enable postback hashing by generating a Postback Key, you'll receive two new query parameters:

  • request_id - A unique UUID for each postback (no duplicates)
  • verifier - A cryptographic hash for validation

Verification Process:

  1. Remove the verifier parameter from the postback URL
  2. Hash the remaining URL using HMAC-SHA256 with your postback secret key
  3. Compare the calculated hash with the verifier parameter
hash_hmac('sha256', $postback_url, $postback_secret_key)

Full Example (PHP 7.1+):

// securely supply credentials using environment variables
define('ADGEM_WHITELIST_IP', $_ENV['ADGEM_WHITELIST_IP']);
define('ADGEM_POSTBACK_KEY', $_ENV['ADGEM_POSTBACK_KEY']);

// verify the static IP
if(ADGEM_WHITELIST_IP !== $_SERVER['REMOTE_ADDR']) {
http_response_code(403);
exit('Error: '.$_SERVER['REMOTE_ADDR'].' does not match the whitelisted IP address.');
}

// get the full request url
$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http");
$request_url = "$protocol://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

// parse the url and query string
$parsed_url = parse_url($request_url);
parse_str($parsed_url['query'], $query_string);

// get the verifier value
$verifier = $query_string['verifier'] ?? null;
if (is_null($verifier)) {
http_response_code(422);
exit("Error: missing verifier");
}

// rebuild url without the verifier
unset($query_string['verifier']);
$hashless_url = $protocol.'://'.$parsed_url['host'].$parsed_url['path'].'?'.http_build_query($query_string, "", "&", PHP_QUERY_RFC3986);

// calculate the hash and verify it matches
$calculated_hash = hash_hmac('sha256', $hashless_url, ADGEM_POSTBACK_KEY);
if ($calculated_hash !== $verifier) {
http_response_code(422);
exit('Error: invalid verifier');
}

// valid - safe to process the postback
http_response_code(200);
exit('OK');

Signature Verification (v3 - POST Requests)

For v3 POST postbacks, verify the request by hashing the request body with your secret key using HMAC-SHA256 and comparing it to the Signature header.

Route::post('/postbacks/adgem/v3', function () {
$receivedSignature = request()->headers->get('Signature', '');
$expectedSignature = hash_hmac('sha256', request()->getContent(), env('ADGEM_POSTBACK_KEY'));

if (hash_equals($expectedSignature, $receivedSignature)) {
return response()->noContent(200);
} else {
return response()->noContent(401);
}
});