Setting Reward Values

Tapdaq enables you to set your rewarded video values directly on our dashboard, overriding any values set on each ad network. This gives you greater control of the rewards payouts within your application, across all of your rewarded video placements.

To access all rewarded video settings, including server to server reward callbacks, please log in to the Tapdaq dashboard and select Mediation > Ad Settings.

When configuring your reward values, you must provide a Reward Name for each reward you create, and a (positive) whole number for the Reward Value. You must also target at least one of your rewarded video placements.

You can add custom JSON to your reward, although this is optional. Custom JSON is limited to 1024 characters.


Using Server To Server Callbacks

Tapdaq provides a server-to-server callback function for rewarded video ads, allowing you to receive detailed user data on the rewarded video activity. The callback can optionally be digitally signed, ensuring that you can verify the origin and content of the request. Both GET and POST callbacks are supported.

The following diagram shows the high level reward flow used by Tapdaq:

Successes And Failures

A well-formed callback request will be sent to the Custom Success URL. Optionally, a Custom Failure URL can be set, to which a callback request that has either been insufficiently configured or has been marked by the SDK as failed will be sent. 

A callback is insufficiently configured if it is missing the success URL, or if the required dynamic parameters are not set (see below). Any missing or invalid config parameters will be indicated by an error message underneath ‘Status’ on the Server Side Rewarded Callbacks dashboard panel.

Dynamic Parameters

The values sent by Tapdaq in the request are in the form of key-value pairs. For a field to be included in the request, its key name must be set via the dashboard. This will also allow the key to match the representation used on the publisher’s side. Three of these parameters are required and must provided with a new key value. Optionally there are a range of others that can be added.

Optional Variables

To include an optional variable in the callback request, simply provide it with a custom key name on the dashboard.

Best Practises and Considerations

  • Ensure your reward API is highly-available as reward callbacks are only sent once. Tapdaq will not re-send reward requests that failed to process/respond correctly.
  • Consider using concurrency and asynchronous request handling to handle large traffic.
  • You may wish to treat each request per event ID as an idempotent action i.e. refuse to process an event ID more than once.
  • If using request signing, ensure that your private key is kept confidential. Tapdaq encrypts this value before storage on its backend.
  • You may choose to not process a reward for a user with an anonymised (zeroed-out) IDFA.


Verifying Rewards with a Digital Signature

Tapdaq can sign rewarded callbacks in order to authenticate the origin and content of the request. Various fields from the request are used to create a signature, which is then SHA256-hashed with a private key entered on the dashboard to create a HMAC and included in the request header.

Verifying the Signature

The signature should be re-created by the publisher at the other end of the request using the format defined below, with the same private key used to re-calculate an HMAC which should be compared with the original value to check that they are consistent. If the values do not match, the request may have been tampered with or sent from a non-Tapdaq origin.

Enabling Signed Callbacks

Simply enter a private key on the dashboard to enable signing.

HMAC Header

Added by Tapdaq as a header to the reward callback request. Formed of the username/public key (e.g. ‘tapdaq’) concatenated by a colon with the value of the HMAC.

Example Value of ‘hmac’ header field

tapdaq:5ae01fd769f7da3b6fe570b0c13cec0c09863514279b92a3ecac070095425272

Signature Fields

The following fields are used to generate the HMAC value:

Code Example For Validating A Signed Reward

package com.tapdaq.webhooks.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

public class ValidateRewardCallback {

  private static final String CHAR_ENCODING = "UTF-8";
  private static final String HMAC_ALGORITHM = "HmacSHA256";

  public static void main(String[] args) throws Exception {
    // Values set in Tapdaq dashboard:
    String httpMethod = "GET"; // or POST
    String url = "http://example.com/callback";
    String privateKey = "key123";

    // Values from the request parameters:
    String eventId = "abc123";
    String rewardValue = "5";
    String idfa = "00000000-0000-0000-0000-000000000000";
    String uid = "1234";

    // Values from the request header:
    Map<String, String> requestHeaders = new HashMap<>();
    requestHeaders.put("date", "2018-10-20T04:15:16.757");
    requestHeaders.put("hmac", "tapdaq:a7172648573e7081394e6b38d6a9e3f19f54a2d2a6cfe887cb7ba6e9315acd23");

    // remove public key 'tapdaq:' from start of hmac
    String receivedHmac = requestHeaders.get("hmac").split("tapdaq:")[1];

    // Now re-generate the HMAC...

    // Create base64-encoded Md5 hash of concatenated values [EVENT_ID]‌[REWARD_VALUE]‌[IDFA]‌[HASHED_USER_ID*]
    // * = optional, included if provided by app in custom_json and set as a dynamic variable in dashboard
    String concatenatedDashboardRequiredFields = eventId + rewardValue + idfa + uid;
    String base64EncodedMd5 = calculateBase64EncodedMd5(concatenatedDashboardRequiredFields);

    String capitalisedHttpMethod = httpMethod.toUpperCase();

    // Create SHA-256 encoded HMAC of concatenated values [MD5 HASH]‌[HTTP_METHOD]‌[DATE]‌[URL]
    String signature = base64EncodedMd5 + capitalisedHttpMethod + requestHeaders.get("date") + url;
    String hmac = calculateHmac(privateKey, signature);

    // Check if the re-generated HMAC matches the received one
    if(hmac.equals(receivedHmac)) {
      System.out.println("Reward valid");
    } else {
      System.out.println("Error! Reward invalid - calculated hmac: " + hmac);
    }
  }

  private static String calculateHmac(String key, String data) throws Exception {
    if (data == null || data.equals("")) {
      throw new IllegalArgumentException("Data should not be null or empty");
    }
    Mac sha256_HMAC = Mac.getInstance(HMAC_ALGORITHM);
    SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(CHAR_ENCODING), HMAC_ALGORITHM);
    sha256_HMAC.init(secret_key);

    return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes(CHAR_ENCODING)));
  }

  private static String calculateBase64EncodedMd5(String contentToEncode) throws NoSuchAlgorithmException, IOException {
    MessageDigest digest = MessageDigest.getInstance("MD5");
    digest.update(contentToEncode.getBytes(CHAR_ENCODING));

    return new String(Base64.encodeBase64(digest.digest()));
  }

}
Did this answer your question?