# Postback

{% hint style="info" %}
**Quick Info :** \
When a user successfully completes an offer, we immediately trigger a call to the Postback URL you have provided in your placement. This call contains all the relevant information required to credit your users, serving as a real-time notification to your server.
{% endhint %}

### Postback Parameters

<table><thead><tr><th width="183.33333333333331" align="center">PARAMETER</th><th width="404" align="center">DESCRIPTION</th><th align="center">EXAMPLE</th></tr></thead><tbody><tr><td align="center">[YOUR_USER_ID]</td><td align="center">This is the unique identifier code of the user who completed action on your platform.</td><td align="center">123GnL</td></tr><tr><td align="center">[REWARD_VALUE]</td><td align="center">The amount of your virtual currency to be credited to your user.</td><td align="center">9000</td></tr><tr><td align="center">[OFFER_NAME]</td><td align="center">The Name of the offer completed.</td><td align="center">Lords Mobile</td></tr><tr><td align="center">[MULTI_EVENT]</td><td align="center">Boolean: <code>true</code> for a multi-event offer, <code>false</code> otherwise.</td><td align="center">false</td></tr><tr><td align="center">[EVENT_NAME]</td><td align="center">Name of the event action that got conversion</td><td align="center">Lords Mobile Castle level 7</td></tr><tr><td align="center">[EVENT_ID]</td><td align="center">ID of the event action that got conversion</td><td align="center">476ede1881042f072794e3cfb5c</td></tr><tr><td align="center">[STATUS]</td><td align="center">For determining the reward amount, <code>completed</code> status adds currency while <code>rejected</code> status subtracts it..</td><td align="center">completed</td></tr><tr><td align="center">[OFFER_ID]</td><td align="center">ID of the offer as displayed on the AdBreak Media dashboard</td><td align="center">5620</td></tr><tr><td align="center">[USER_IP]</td><td align="center">IP address of the user that completed the offer</td><td align="center">139.144.178.218</td></tr><tr><td align="center">[PAYOUT]</td><td align="center">Amount in USD that you earned for this conversion</td><td align="center">90.00</td></tr><tr><td align="center">[TXID]</td><td align="center">Unique ID of the conversion generated by AdBreak Media</td><td align="center">1b6acc68414e699ebab37e0d5d2a17ab</td></tr><tr><td align="center">[COUNTRY]</td><td align="center">Country (ISO2 form) from the lead comes.</td><td align="center">US</td></tr><tr><td align="center">[HASH]</td><td align="center">SHA256 hash that can be used to verify that the call has been made from our servers.</td><td align="center">2cfbbd0297294396caf5c7db13bc36d5</td></tr><tr><td align="center">[SUB1]</td><td align="center">Extra Param that you passed though offerwall</td><td align="center">Sa123s</td></tr><tr><td align="center">[SUB2]</td><td align="center">Extra Param that you passed though offerwall</td><td align="center">Na70t</td></tr></tbody></table>

`REWARD_VALUE` and `PAYOUT` parameters are always absolute values, you will need to check status parameter to see if you need to add or subtract that amount from your users.

All values are URL encoded.

### Examples

This is how we call your postback url :

#### Without Values

```
https://example.com/api/adbreakmedia?user=[YOUR_USER_ID]&reward=[REWARD_VALUE]&offerName=[OFFER_NAME]&offerId=[OFFER_ID]&ip=[USER_IP]&status=[STATUS]&transaction_id=[TXID]&country=[COUNTRY]&is_multi=[MULTI_EVENT]&ename=[EVENT_NAME]&eid=[EVENT_ID]&hash=[HASH]&sub1=[SUB1]&sub2=[SUB2]
```

#### With Values

{% tabs %}
{% tab title="Completed" %}
{% hint style="success" %}
<https://example.com/api/adbreakmedia?user=abc123\\&coins=999\\&offerName=Lords%20Mobile\\&offerId=5620\\&ip=139.144.178.218\\&status=completed\\&transaction\\_id=1b6acc68414e699ebab37e0d5d2a17ab\\&country=US\\&is\\_multi=true\\&ename=Lords%20Mobile%20Castle%20level%207\\&eid=476ede1881042f072794e3cfb5c\\&hash=0c4c8e302e7a074a8a1c2600cd1af07505843adb2c026ea822f46d3b5a98dd1f>
{% endhint %}
{% endtab %}

{% tab title="Rejected" %}
{% hint style="danger" %}
<https://example.com/api/adbreakmedia?user=abc123\\&coins=999\\&offerName=Lords%20Mobile\\&offerId=5620\\&ip=139.144.178.218\\&status=rejected\\&transaction\\_id=1b6acc68414e699ebab37e0d5d2a17ab\\&country=US\\&is\\_multi=true\\&ename=Lords%20Mobile%20Castle%20level%207\\&eid=476ede1881042f072794e3cfb5c\\&hash=0c4c8e302e7a074a8a1c2600cd1af07505843adb2c026ea822f46d3b5a98dd1f>
{% endhint %}

> Please note that only the status will be changed to "rejected" in the callback, while all other values will remain the same. If you are using the transaction ID as a unique parameter, please ensure that you take appropriate action considering that the transaction ID will remain the same in the rejected callback.
> {% endtab %}
> {% endtabs %}

{% hint style="info" %}
&#x20;**Note :**&#x20;

Our servers expect an HTTP Status Code 200 from your Postback URL. If this response is not received from your URL, we will attempt to resend the Postback up to 5 times. There is a 1 hour delay between each attempt. After 5th attempt, you will receive a Postback failure email from us.\
\
Please be aware that the message returned by your postback endpoint should not include error messages such as `fail` or `error`. Otherwise, it will be considered a postback failure.
{% endhint %}

### Security

For enhanced security and to prevent tampering, please ensure that the postback URL used is exclusively designated for AdBreak Media. Additionally, consider whitelisting the server IP `139.144.178.218` for added protection.

You should also verify the hash received in the Postback to ensure that the call comes from our servers. Hash parameter should match SHA256 of :&#x20;

```
[YOUR_USER_ID]+[OFFER_ID]+[TXID]+[PUBLISHER_SECRET_KEY]
```

{% hint style="info" %}
To obtain your publisher secret key, please navigate to the dashboard settings/secret credentials section. Make sure to use this key for your postback verification purposes.
{% endhint %}

{% tabs %}
{% tab title="PHP" %}

```php
<?php
    function calculateSHA256Hash($data) {
        return hash('sha256', $data);
    }

    $serverIPs = ["139.144.178.218"];
    $serverIP = $_SERVER["HTTP_X_FORWARDED_FOR"] ?? $_SERVER["REMOTE_ADDR"] ?? "No Need";

    if (!in_array($serverIP, $serverIPs)) {
        http_response_code(400);
        exit("Access Denied");
    }

    $user = $_GET['user'];
    $offerId = $_GET['offerId'];
    $txid = $_GET['txid'];
    $received_hash = $_GET['hash'];

    $secret = '4bd91dc2fd97f2d2ecad9425019c179ffd26c5a866e991192ea8c43bf79e0a63';
    $calculated_hash = calculateSHA256Hash($user . $offerId . $txid . $secret);

    if ($received_hash === $calculated_hash) {
        // Your actions here
        http_response_code(200);
        echo "Approved";
    } else {
        http_response_code(400);
        echo "Unauthorized";
    }
?>

```

{% endtab %}

{% tab title="Node JS" %}

```typescript
const http = require('http');
const crypto = require('crypto');
const ipRangeCheck = require('ip-range-check');

function calculateSHA256Hash(data) {
  const hash = crypto.createHash('sha256');
  hash.update(data);
  return hash.digest('hex');
}

const server = http.createServer((req, res) => {
  const serverIPs = ["139.144.178.218"];
  let serverIP = req.headers["x-real-ip"] || req.headers["x-forwarded-for"] || "No Need";

  if (!ipRangeCheck(serverIP, serverIPs)) {
    res.writeHead(400);
    res.end("Access Denied");
    return;
  }

  const { hash, user, offerId, txid } = req.url.split('?')[1]
    .split('&')
    .reduce((acc, param) => {
      const [key, value] = param.split('=');
      acc[key] = value;
      return acc;
    }, {});

  const secret = '4bd91dc2fd97f2d2ecad9425019c179ffd26c5a866e991192ea8c43bf79e0a63';
  const generatedHash = calculateSHA256Hash(user + offerId + txid + secret);

  if (hash === generatedHash) {
    //your action here
    
    res.writeHead(200);
    res.end("Approved");
  } else {
    res.writeHead(400);
    res.end("Unauthorized");
  }
});

server.listen(3000, () => {
  console.log('Server is running on port 3000');
});

```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require 'digest'
require 'sinatra'
require 'ipaddr'

def calculate_sha256_hash(data)
  Digest::SHA256.hexdigest data
end

get '/endpoint' do
  server_ips = ["139.144.178.218"]
  server_ip = request.env["HTTP_X_FORWARDED_FOR"] || request.env["REMOTE_ADDR"] || "No Need"

  unless server_ips.include? server_ip
    status 400
    return "Access Denied"
  end
  
  user = params['user']
  offerId = params['offerId']
  txid = params['txid']
  received_hash = params['hash']
  
  secret = '4bd91dc2fd97f2d2ecad9425019c179ffd26c5a866e991192ea8c43bf79e0a63'
  calculated_hash = calculate_sha256_hash("#{user}#{offerId}#{txid}#{secret}")

  if received_hash == calculated_hash
    # your actions here
    status 200
    "Approved"
  else
    status 400
    "Unauthorized"
  end
end
```

{% endtab %}

{% tab title="Python" %}

```python
from flask import Flask, request, abort
import hashlib

app = Flask(__name__)

def calculate_sha256_hash(data):
    return hashlib.sha256(data.encode()).hexdigest()

@app.route('/endpoint', methods=['GET'])
def endpoint():
    server_ips = ["139.144.178.218"]
    server_ip = request.headers.get('X-Real-IP', request.remote_addr)
    
    if server_ip not in server_ips:
        abort(400, "Access Denied")

    user = request.args.get('user')
    offerId = request.args.get('offerId')
    txid = request.args.get('txid')
    received_hash = request.args.get('hash')

    secret = '4bd91dc2fd97f2d2ecad9425019c179ffd26c5a866e991192ea8c43bf79e0a63'
    calculated_hash = calculate_sha256_hash(user + offerId + txid + secret)

    if received_hash == calculated_hash:
        # Your actions here
        return "Approved", 200
    else:
        abort(400, "Unauthorized")

if __name__ == '__main__':
    app.run(debug=True)
```

{% endtab %}
{% endtabs %}

> If you encounter any difficulties while setting up the postback, please don't hesitate to reach out to us at <publishers@adbreakmedia.com>. Our team will be more than happy to assist you as soon as possible!
