You can set a Server-to-Server webhook URL through Pollfish developer dashboard, in your app's page. On every survey completion through your app an HTTP GET request will be made using that URL.
Note: You should use this call to verify a survey completion if you reward your users. This is the only 100% accurate and secure way to monitor survey completion through your app.
Server-to-server callbacks can be used to retrieve several different params on publisher's server side.
In general, we advice to monitor all these parameters on your server side.
You can test server-to-server callbacks in developer mode. On every survey completion a callback will be fired. In that call a debug=true parameter will be appended to indicate that the callback is for a survey completed in developer mode. If your app is turned in release mode, no debug parameter will exist in the call.
For example the following URL template:
http://www.example.com/pollfish/[[request_uuid]]?cpa=[[cpa]]
could produce a URL in developer mode like the following:
http://www.example.com/pollfish/CPMdQdgAzHoL6360iXY5qLp?cpa=30&debug=true
Every user can complete only once a specific survey. You can avoid dublicates in survey completion callbacks by appending and listening to tx_id param. This id is calculated by user id and survey id and uniquely identifies a survey completion by a user. A user should not complete the same survey twice. Having that said you should never receive callbacks with the same tx_id param. Use this param to avoid crediting a user more than once for the same survey.
| Note: You should always check debug param when verifying a callback. Please ignore debug=true callbacks when rewarding your users in a live app since this can be an indication of a tampered app.
You can pass a unique id for a user (as you may use it in your own system) through the SDK, during intiialization. You can retrieve this id through the server-to-server callback if you append request_uuid parameter to the call.
You can easily retrieve through every callback how much money were earned in USD cents, by appending and reading param with name cpa.
In every callback received, aside from money earned you can retrieve the Reward Name and Reward Value, by appending and reading params with name reward_name and/or reward_value.
| Note: You can set those values per app, through the Publisher Dashboard under section Reward Settings
You can register and receive callbacks when a user was not eligible for a survey. User not eligible in that case means that either the user was screened out from a particular survey or he/she was marked as fraud by our anti-fraud system.
If you want to register and receive not eligible/eligible info in your callbacks please select the checkbox as below
Once you select to register for not eligible callbacks, you will need to add "status" in your url. This param will return two values
[eligible | noteligible]
For example:
https://mybaseurl.com?device_id=[[device_id]]&cpa=[[cpa]]&request_uuid=[[request_uuid]]×tamp=[[timestamp]]&tx_id=[[tx_id]]&signature=[[signature]]&status=[[status]]
Important: If you have selected checkbox "Notify me when the user is not eligible" you should add "status" param in your url. If you uncheck this option you should remove "status" param from your url.
As before, you will need to select the Notify me when the user is not eligible checkbox and provide a new parameter for the termination reason called [[term_reason]]
For example:
https://mybaseurl.com?device_id=[[device_id]]&cpa=[[cpa]]&request_uuid=[[request_uuid]]×tamp=[[timestamp]]&tx_id=[[tx_id]]&signature=[[signature]]&status=[[status]]&reason=[[term_reason]]
The [[term_reason]] value will contain one of these strings as the reason
Term reason | Description |
---|---|
quota_full | The quota that the respondent belongs was closed while the user was answering the survey |
survey_closed | The survey collected all the desired responses while the user was answering the survey |
profiling | The respondent did not match the target audience of the survey |
screenout | The respondent choose a non-desired answer in a survey screening question |
duplicate | The respondent attempted to answer the same survey twice |
security | Generic reason for security and fraud checks |
geomissmatch | We identified irregularities in the location data of the respondent |
quality | The respondent failed in one of our trap questions or other quality checks |
hasty_answers | The respondent completed the survey too fast or used straightlining |
gibberish | The respondent answered with gibberish text in at least one open-ended question |
captcha | The respondent failed one of our CAPTCHA tests |
third_party_termination | Generic reason for terminations that happen in mediation survey providers |
third_party_termination_fraud | The respondent was marked as fraud in the mediation survey provider |
third_party_termination_quality | The respondent was marked as low quality in the mediation survey provider |
user_rejection | The respondent rejected the survey |
vpn | The respondent answered the survey using VPN or an IP address that characterized as suspicious |
survey_expired | The respondent was prevented from entering a survey that would have resulted in "survey closed" or "quota full" |
underage_profiling | The respondent is below the allowed age of participation |
Important: These responses might change in the future
As with all callback URL parameters, in order to receive values for a parameter you have to include the corresponding parameter placeholder in the URL that you submit to Pollfish. For the signature parameter you have to include the [[signature]] parameter placeholder. If you do not included it then your callback URLs will not be signed. Because of this the following URL templates will result in not having your callback URLs signed.
http://www.example.com/pollfish-callback
http://www.example.com/pollfish-callback?cpa=[[cpa]]&uuid=[[request_uuid]]
In addition to the signature parameter in order to enable URL signatures you also need to include one more parameter. This is because the signature signs the parameter values and not the URL. So if you specify the below URL template your URLs will not include a signature.
http://www.example.com/pollfish-callback?sig=[[signature]]
To make sure that your callback URLs are signed include the signature parameter plus one other parameter.
Valid examples:
http://www.example.com/pollfish-callback?tx_id=[[tx_id]]&sig=[[signature]]
http://www.example.com/pollfish-callback?tx_id=[[tx_id]]&time=[[timestamp]]&sig=[[signature]]
http://www.example.com/pollfish-callback?tx_id=[[tx_id]]&time=[[timestamp]]&cpa=[[cpa]]&device=[[device_id]]&request_uuid=[[request_uuid]]&sig=[[signature]]
If you want to be protected by fake requests forged by malicious third parties then including the signature in your URL is not enough. You must make sure that you include at least one other parameter that varies a lot between requests or is unique between requests. We recommend using at least the tx_id parameter in combination with the signature parameter to protect against fake callback requests.
Bad URL template:
http://www.example.com/pollfish-callback?cpa=[[cpa]]&sig=[[signature]]
This is bad because signature only uses cpa as input and cpa does not vary a lot between requests.
Good URL template:
http://www.example.com/pollfish-callback?id=[[tx_id]]&sig=[[signature]]
This is a good URL template because tx_id is unique for all the callback requests that you are going to receive.
Very good URL template:
http://www.example.com/pollfish-callback?id=[[tx_id]]time=[[timestamp]]&sig=[[signature]]
Includes both tx_id and timestamp.
The signature of the callback URLs is the result of appling the HMAC-SHA1 hash function to the [[parameters]] that are included in the URL using your account's secret_key.
We only sign the values that are substituted using the parameters placeholders ([[click_id]], [[cpa]], [[device_id]], [[request_uuid]], [[reward_name]], [[reward_value]], [[status]], [[timestamp]], [[tx_id]] and [[term_reason]]). We do not sign any other part of the URL including any other URL parameters that the publisher might specify. For example in the below URL only the values that are going to be substituded in [[request_uuid]] and [[tx_id]] are used as input and not the values of the bundle_id
and source
URL parameters.
https://www.example.com?request_uuid=[[request_uuid]]&tx_id=[[tx_id]]&signature=[[signature]]&bundle_id=com.domain.app&source=pollfish
Your secret_key is an auto-generated key by Pollfish that serves as a shared secret between the publisher and Pollfish. You can find out more about your secret_key at the Account Information page.
To sign the parameters they are assembled in alphabetical order using the parameter placeholder names in a string by concatenating them using the colon ':' character. For example if you have the follwing URL template:
https://www.example.com?device_id=[[device_id]]&cpa=[[cpa]]×tamp=[[timespamp]]&tx_id=[[tx_id]]&signature=[[signature]]
Then the produced string, that will be the input to HMAC-SHA1, will have the pattern: cpa:device_id:timestamp:tx_id
Furthermore if we have the following values: device_id=my-device-id
, cpa=30
, timestamp=1463152452308
and tx_id=08f31d41d800cc7a0beb7eb4897639a8ba7fd7db
the string that will be the input to HMAC-SHA1 will be:
30:my-device-id:1463152452308:08f31d41d800cc7a0beb7eb4897639a8ba7fd7db
and the produced callback URL will be:
https://www.example.com?device_id=my-device-id&cpa=30×tamp=1463152452308&tx_id=08f31d41d800cc7a0beb7eb4897639a8ba7fd7db&signature=BbgBlH5HODk%2FSKw3MQuvqM%2BgTxQ%3D
Please note that the string is created using the parameter values before they are URL encoded.
To verify the signature in server-to-server postback calls follow the below proceedure:
- Extract the value of the signature parameter from the URL.
- URL decode the value you extracted in (1) using Percent encoding
- Extract the values of the rest of the parameters URL.
- URL decode the values you extracted in (3) using Percent encoding.
- Sort the values from (4) alphabeticaly using the names of the template parameters. The names of the template parameters in sorted order are:
cpa
,device_id
,request_uuid
,reward_name
,reward_value
,status
,term_reason
,timestamp
,tx_id
and not the names of any URL parameters your URL may contain. - Produce a string by concatenating all non-empty parameter values as sorted in the previous step using the
:
character. The only parameter that when specified in the URL template can be empty isrequest_uuid
. There is a special handling forterm_reason
: If the user is non-eligible then it has one of the values described in section 6 and with that value is included in the callback url and the signature calculation. If however the user is eligible the term is included but with an empty value and must participate in the signature calculation. An example of a callback url for an eligible user ishttps://mybaseurl.com?device_id=my-device-id&term_reason=&cpa=30
which gives the string30:my-device-id:
for signature calculation. The trailing:
is because of the emptyterm_reason
- Sign the string produced in (6) using the HMAC-SHA1 algorithm and your account's secret_key that can be retrieved from the Account Information page.
- Encode the value produced in (7) using Base64. Please note that the input to the Base64 function must be the raw byte array output of HMAC-SHA1 and not a string representation of it.
- Compare the values produced in (2) and (8). If they are equal then the signature is valid.
Please note that during developer mode the debug=true
parameter is not included in the input of the signature.
<!DOCTYPE html>
<html>
<head>
<title>Pollfish s2s signature validator example</title>
</head>
<body>
<h1>Validate signature</h1>
<p>Url pattern is: <code>https://example.com?device_id=[[device_id]]]&cpa=[[cpa]]&timestamp=[[timstamp]]&tx_id=[[tx_id]]&request_uuid=[[request_uuid]]&status=[[status]]&signature=[[signature]]</code></p>
<?php $secret_key = "my-secret"; ?>
<p>Will check signature using HMAC-SHA1 and secret_key = <br><?php echo($secret_key) ?></b></p>
<?php
$cpa = rawurldecode($_GET["cpa"]);
$device_id = rawurldecode($_GET["device_id"]);
$request_uuid = rawurldecode($_GET["request_uuid"]);
$reward_name = rawurldecode($_GET["reward_name"]);
$reward_value = rawurldecode($_GET["reward_value"]);
$status = rawurldecode($_GET["status"]);
$timestamp = rawurldecode($_GET["timestamp"]);
$tx_id = rawurldecode($_GET["tx_id"]);
$url_signature = rawurldecode($_GET["signature"]);
$data = $cpa . ":" . $device_id;
if (!empty($request_uuid)) { // only added when non-empty
$data = $data . ":" . $request_uuid;
}
$data = $data . ":" . $reward_name . ":" . $reward_value . ":" . $status . ":" . $timestamp . ":" . $tx_id;
$computed_signature = base64_encode(hash_hmac("sha1" , $data, $secret_key, true));
$is_valid = $url_signature == $computed_signature;
?>
<p>cpa = <?php echo($cpa); ?></p>
<p>device_id = <?php echo($device_id); ?></p>
<p>request_uuid = <?php echo($request_uuid); ?></p>
<p>reward_name = <?php echo($reward_name); ?></p>
<p>$reward_value = <?php echo($reward_value); ?></p>
<p>status = <?php echo($status); ?></p>
<p>timestamp = <?php echo($timestamp); ?></p>
<p>tx_id = <?php echo($tx_id); ?></p>
<p>The signature is generated using the input string:<code><?php echo($data); ?></code></p>
<p>The generated signature is: <?php echo($computed_signature); ?></p>
<p>The URL signature is: <?php echo($url_signature); ?></p>
<p>The signature is valid: <?php echo($is_valid ? "true" : "false"); ?></p>
</body>
</html>
You can check logs from your s2s callbacks history simply by selecting the relevant button on your Dashboard.
In that popup you will find all callbacks generated from Pollfish servers for your app, sorted by date. You can easily track the status of each call and response from you server side. Each call in the logs is clickable and you can also search for a specific callback based on specific params of your url structure.