Callbacks
TapResearch reports every reward to your backend through a server-to-server postback. Because the Survey Feed API has no in-app SDK surface, only the server-to-server postback applies here.
Server-to-Server Postback
The server-to-server postback is a GET request that TapResearch sends to your callback URL immediately after a user earns a reward. The reward details are passed as query parameters, and an HMAC-MD5 signature (sig) lets you verify the request originated from TapResearch.
Important: With server-to-server callbacks your app is responsible for notifying users of the rewards they receive — TapResearch does not notify users with this method.
Update Callback URL
Set or update your callback URL in the "Edit App" section of the Publisher Dashboard.

URL requirements:
- No spaces or special characters
- Must return a 2xx response code to be considered valid
Sample Request
https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| uid | String | Persistent unique identifier for this user. |
| tid | String | Transaction ID or click ID. This value will not be unique if the user completed multiple surveys in a single session. Use cpid for deduping purposes. |
| cpid | String | Unique survey complete identifier. We recommend that you store and check against this value to ensure you reward the user only once per survey complete. |
| payout_amount | Integer | Amount of currency earned by this user. |
| payout_currency | String | The type of currency the user earned. |
| revenue | Decimal | Amount you will be paid for this survey complete, in USD. |
| payout_type | Integer | The action that the user was rewarded for. 0 - Profile Complete, 3 - Survey Rewarded, 9 - Quick Question Completed. |
| sig | String | The URL signature: an HMAC-MD5 generated from the query string minus the sig parameter. See Signature Validation below. |
Callback Testing
Use the Test Callback button in the dashboard to generate a test completion that fires a callback to your specified URL.
Best practice: Test callbacks before deploying to production.
Test callbacks use fixed currency values. Commercial survey values will vary.
Signature Validation
For security, every callback request includes an HMAC-MD5 signature (sig) generated from the query string. Validate it on every request before you reward a user.
Grab your API secret from your main dashboard. Example: 26dcc0fc7b6208fdfeffaf19f627cb4a
- Start with the incoming callback request, for example:
https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4 - Isolate the query string, leaving out the question mark.
- Strip out the
sigparameter, including the leading ampersand (&). - URL-decode the remaining query string.
- Run your API secret and the decoded query string through an HMAC-MD5 generator.
- Compare your generated HMAC against the
sigparameter value. If they match, record the complete and reward the user.
- Ruby
- PHP
- Java
# Sample request URL
url = "https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4"
# Isolate query string
query_string = url.gsub(/^(.*?)\?/, "")
# Strip out the sig parameter
stripped_query_string = query_string.gsub(/&sig.*/, "")
# Decode URL
decoded = URI.decode_www_form_component(stripped_query_string)
# Generate HMAC-MD5
api_secret = "26dcc0fc7b6208fdfeffaf19f627cb4a"
digest = OpenSSL::Digest.new("md5")
md5 = OpenSSL::HMAC.hexdigest(digest, api_secret, decoded)
puts md5 # 42cbd66af5b670bed293d9b01c06d3c4
<?php
# Sample request URL
$url = 'https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4';
# Isolate query string
$query_string = parse_url($url, PHP_URL_QUERY);
# Strip out the sig parameter
$stripped_query_string = substr($query_string, 0, strpos($query_string, 'sig') - 1);
# Decode URL
$decoded = urldecode($stripped_query_string);
# Generate HMAC-MD5
$api_secret = '26dcc0fc7b6208fdfeffaf19f627cb4a';
$md5 = hash_hmac('md5', $decoded, $api_secret);
echo $md5; # 42cbd66af5b670bed293d9b01c06d3c4
?>
private static final String API_SECRET = "26dcc0fc7b6208fdfeffaf19f627cb4a";
private static final String ALGO = "HmacMD5";
try {
// URL
String urlString = "https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4";
// Generate HMAC-MD5
Mac mac = Mac.getInstance(ALGO);
SecretKeySpec key = new SecretKeySpec(API_SECRET.getBytes(StandardCharsets.UTF_8), ALGO);
mac.init(key);
// Isolate query string and remove sig parameter
String queryString = urlString.substring(urlString.indexOf("?") + 1);
queryString = queryString.substring(0, queryString.indexOf("&sig=")) + queryString.substring(queryString.indexOf("&sig=") + 37);
// Decode URL
String decode = URLDecoder.decode(queryString, StandardCharsets.UTF_8);
byte[] bytes = mac.doFinal(decode.getBytes(StandardCharsets.UTF_8));
String md5 = DatatypeConverter.printHexBinary(bytes).toLowerCase();
System.out.println(md5); // 42cbd66af5b670bed293d9b01c06d3c4
} catch (Exception e) {
e.printStackTrace();
}
Whitelisted IP Addresses
To further harden your endpoint, restrict incoming callback requests to the following TapResearch source IP addresses:
| IP Address |
|---|
| 34.198.225.203 |
| 3.88.121.21 |
| 3.89.214.250 |
| 3.92.129.242 |
Retries
If a callback fails, our system continues retrying to send the reward for 48 hours OR until a 2xx response code is returned.
Survey outcome parameter
For every callback generated via the Survey Feed API, the survey_outcome
parameter is included — an integer representing the participant's final status:
| Value | Status | Description |
|---|---|---|
| 1 | Complete | The participant successfully completed the survey. |
| 2 | Disqualified | The participant was screened out based on targeting requirements. |
| 3 | Over Quota | The survey reached its quota while the participant was in progress. |
Callbacks only fire for revenue-generating matches. If a participant is disqualified or the survey reaches its quota, a callback is sent only when that outcome results in a partial reward (as configured in your App Settings). If no revenue is generated for the event, no postback is triggered.