Self-managed currency is used when you are handling the currency of your users with your own servers. This method can give you more control with your user’s currency but it also means that you are completely responsible for the back-end work for storing and handling the currency amounts for all your users. getCurrencyBalance, awardCurrency, or spendCurrency are only available for Managed Currency. Tapjoy does not provide any client-side/app-side notifications for self-managed currency: you are responsible for notifying the app and your user when we call your callback server. You MUST set up a callback server to work with self-Managed currency.
Note: It’s important to note that while Tapjoy does its best to reward users as quickly as possibly we can’t guarantee that the user will be rewarded instantaneously. There are a lot of factors that determine how long it may take to reward a user. As a best practice, you should check for an updated balance at regular intervals and after certain app events like app launch, app resume, in between levels, video ad close, before your store loads, etc. We also recommend that you let your users know that it may take some time before an offer gets completed.
Note: Each platform must have its own currency, even if it is self managed.
When a user has earned currency by completing an offer, we will make an HTTP GET request to this URL. The format of the parameters will be:
<callback_url>?snuid=<user_id>¤cy=<currency>&mac_address=<mac_address>
//Example
http://www.sampledoman.com/payments/offers/tapjoy?&snuid=42&currency=50&mac\_address=00-16-41-34-2C-A6
The default request parameters include snuid and currency (how much currency should be added to the user’s account), and the user’s wifi mac_address (if available).
Tapjoy servers will expect either a 200 or 403 response from your server.
Your server should respond with 200 only if:
Your server should respond with 403 if:
Tapjoy will continue to retry if Tapjoy servers receive any response other then 200 or 403. (Note that it is very important NOT to actually reward the user if you are giving a non-200 response, as Tapjoy will continue to re-attempt the callback, possibly resulting in large numbers of duplicate rewards.) We’ll retry approximately every 5 minutes for 4 days. We will treat the request as having failed if your server takes more than 5 seconds to respond.
NOTE: The response body of the callback URL responses needs to be in UTF-8. If they are not in UTF-8 we will retry even if you return a 200.
You can access your Virtual Currency Secret Key in Dashboard > Monetize > Virtual Currency > Create/Edit. This key is different from the Application SDK Key. Use this Virtual Currency Secret Key to sign the callback.
If a secret key in the Currency is present (secret_key=
) then we will add the following parameters to the callback request:
The verifier is computed by taking the MD5 hash of the id, snuid, currency and secret key, separated by colons. In Ruby code, this would be:
Digest::MD5.hexdigest("#{id}:#{snuid}:#{currency}:#{secret_key}")
Your server should recompute the verifier and reject any requests that do not match. The server should respond with a 403 Forbidden if the verifier doesn’t match.
Note that each application should have a separate secret key. Please do not use the same secret key for all of your applications, as this might lead to a situation where rewarding a user in one application will also reward the user in the other application. Also the id above represents the request_id not currency_id.
We have improved on the callbacks listed above with more information and security. If you would like to use this improved version, please reach out to your account manager or our support team to help you enable this version of the callback.
When a user has earned currency by completing an offer, we will make a POST request to the URL you provided. The format of the parameters will be:
{
"id": "reward.id",
“rev”: 100,
“cp”: ”your_custom_string”
"currency": {
"id": "currency_id",
"reward": "xxx",
"currency_sale": "",
},
"offer": {
"name": "Some offer",
“type”: “”,
“icon_url”: “offer_icon_url,
},
“placement”: {
“content_type”: “offerwall”,
“name”: “placement_name”
},
"user": {
"id": "pub_user_id"
},
“timestamp”: “123491324”
}
Parameter | Type | Description |
---|---|---|
id | string | The unique reward id for this request |
rev | double | Revenue in USD cents earned |
cp | string | The custom parameter passed through the SDK via the setCustomParameter method |
currency.id | string | The unique identifier for this currency |
currency.reward | integer | Currency amount rewarded to user |
currency.currency_sale | float | Currency sale multiplier (when applicable) |
offer.name | string | Name of hte advertiser offer |
offer.type | This is not currently supported | |
offer.icon_url | string | Icon URL of the offer |
placement.name | string | The placement associated with this conversion |
placement.content_type | string | The type of the placement used |
user.id | string | The user ID passed through the SDK via the setUserID method |
timestamp | timestamp | The timestamp of this transaction |
The JSON body will be hasehd using a SHA256 hashing algorithm. The verifier will be generated from POST currency callback request body and our shared secret key (found on the Tapjoy dashboard with your callback URL) This verifier will be sent in the POST currency callback request headers.
HMAC_SHA-256(<Request-Body>,<Secret-Key>)
Example of the Tapjoy header with signature:
X-Tapjoy-Signature => 7205ccfdfa1fe28cd05a1b56a9508d898cc938aa555a6c18848097fe4ee0975b
It is critically important that you set a user id if you are using a self-managed currency. This value is what the snuid
is set to in the callback URL. We recommended using the connect flags to set the user id on connect, before any content is requested.
If set incorrectly, your users will not be rewarded and you will not get paid. The user id should be set to a unique user ID (typically a number).
For data security and GDPR compliance purposes, the setUserID parameter should not include any recognizable or identifiable information, such as a username, real name, or email address. For security and fraud detection purposes, the user ID should be constant for the lifetime of the user. (Do not, for example, use the user ID parameter to communicate information like the user’s level or score.)
The User ID can be up to 190 characters long.
The code samples below demonstrate how to use the connect flag, and also how to call the setUserID
API directly (after connect) if necessary. When calling the API directly use the callbacks to ensure your id has been set successfully. We strongly recommend using the connect flag where possible:
// Recommended approach using connect flag
NSDictionary *connectFlags = @{TJC_OPTION_USER_ID : @"<USER_ID_HERE>"};
[Tapjoy connect:@"SDK_KEY_GOES_HERE" options:connectFlags];
// Setting the user id directly
[Tapjoy setUserIDWithCompletion:@"<USER_ID_HERE>" completion:^(BOOL success, NSError *error) {
}];
// Recommended approach using connect flag
Hashtable<String, Object> connectFlags = new Hashtable<String, Object>();
connectFlags.put(TapjoyConnectFlag.USER_ID, "<USER_ID_HERE>"); // Important for self-managed currency
Tapjoy.connect(getApplicationContext(), "SDK_KEY_GOES_HERE", connectFlags, new TJConnectListener() {...});
// Setting the user id directly
Tapjoy.setUserID("<USER_ID_HERE>", new TJSetUserIDListener() {
@Override
public void onSetUserIDSuccess() {
}
@Override
public void onSetUserIDFailure(String error) {
}
});
// Recommended approach using connect flag
Dictionary<string,string> connectFlags = new Dictionary<string,string>();
connectFlags.Add("TJC_OPTION_USER_ID", "<USER_ID_HERE>");
#if UNITY_ANDROID
Tapjoy.Connect("your_android_sdk_key", connectFlags);
#elif UNITY_IOS
Tapjoy.Connect("your_ios_sdk_key", connectFlags);
#endif
// Callbacks for SetUserID
TJPlacement.OnSetUserIDSuccess += HandleOnSetUserIDSuccess;
TJPlacement.OnSetUserIDFailure += HandleOnSetUserIDFailure;
// Setting the user id directly
Tapjoy.SetUserID("<USER_ID_HERE>")
// Recommended approach using connect flag
try {
let flags: object = { TJC_OPTION_USER_ID: '<userId>' };
await Tapjoy.connect('<sdk_key>', flags);
} catch (error) {
console.log(error);
}
// Setting the user id directly
try {
await Tapjoy.setUserId('<userId>');
} catch (error) {
console.log(error);
}
You can find further examples on the Quickstart page for iOS, Android, Unity, and React Native.
TROUBLESHOOTING: If you are calling setUserID and the snuid in the callback URL isn’t a value you expect, then you need to call setUserID before the user goes to the in-app offerwall or tapjoy.com to complete offers. Tapjoy will send device id as snuid in the callback URL if there is no userID associated with a device. For example, a user could launch the app but then go to tapjoy.com before your app sends us the userID. To prevent this you need to make sure setUserID is called on every launch after the connect call.
If you have not set the user ID the system will attempt to use the best-available device ID. In most cases this will be the Advertising ID for the device. However, depending on SDK version, device model/version, device OS version, and Google Play Services the exact ID may vary. Other possible values include the Android ID, udid, and mac_address.
Each time you request a placement you can tell Tapjoy the users current balance. You must set this before requesting the placement content.
TJPlacement *placement = [TJPlacement placementWithName:@"placementName" delegate:nil];
[placement setBalance:100 forCurrencyId:@"1234" withCompletion:^(NSError * _Nullable error) {
if (error != nil) {
//Failure
NSString *message = error.localizedDescription;
} else {
//Success
}
}];
TJPlacement placement = Tapjoy.getPlacement("placement", this);
placement.setCurrencyBalance("1234", 100, new TJSetCurrencyBalanceListener() {
@Override
public void onSetCurrencyBalanceSuccess() {
}
@Override
public void onSetCurrencyBalanceFailure(int code, String error) {
}
});
TJPlacement placement = TJPlacement.CreatePlacement("placementName");
placement.SetCurrencyBalance("[CURRENCY_ID]", 100);
// Optional callbacks
void OnEnable()
{
TJPlacement.OnSetCurrencyBalanceSuccess += HandleSetCurrencyBalanceSuccess;
TJPlacement.OnSetCurrencyBalanceFailure += HandleSetCurrencyBalanceFailure;
}
void OnDisable()
{
TJPlacement.OnSetCurrencyBalanceSuccess -= HandleSetCurrencyBalanceSuccess;
TJPlacement.OnSetCurrencyBalanceFailure -= HandleSetCurrencyBalanceFailure;
}
public void HandleSetCurrencyBalanceSuccess(TJPlacement placement)
{
}
public void HandleSetCurrencyBalanceFailure(TJPlacement placement, int code, string error)
{
}
let placement = new TJPlacement('placementName');
try {
await placement?.setCurrencyBalance('1234', 100);
} catch (e: any) {
let code = e.code;
let message = e.message;
}
If you set the balance you can also set the required amount value on a placemnet.
TJPlacement* placement = [TJPlacement placementWithName:@"placementName" delegate:nil];
placement setRequiredAmount:100 forCurrencyId:@"1234" withCompletion:^(NSError * _Nullable error) {
if (error != nil) {
//Failure
NSString *message = error.localizedDescription;
} else {
//Success
}
}
TJPlacement placement = Tapjoy.getPlacement("placement", this);
placement.setCurrencyAmountRequired("1234", 100, new TJSetCurrencyAmountRequiredListener() {
@Override
public void onSetCurrencyAmountRequiredSuccess() {
}
@Override
public void onSetCurrencyAmountRequiredFailure(int code, String error) {
}
});
TJPlacement placement = TJPlacement.CreatePlacement("placementName");
placement.SetRequiredAmount("[CURRENCY_ID]", 200);
// Optional callbacks
void OnEnable()
{
TJPlacement.OnSetCurrencyAmountRequiredSuccess += HandleSetRequiredAmountSuccess;
TJPlacement.OnSetCurrencyAmountRequiredFailure += HandleSetRequiredAmountFailure;}
void OnDisable()
{
TJPlacement.OnSetCurrencyAmountRequiredSuccess -= HandleSetRequiredAmountSuccess;
TJPlacement.OnSetCurrencyAmountRequiredFailure -= HandleSetRequiredAmountFailure;
}
public void HandleSetCurrencyBalanceSuccess(TJPlacement placement)
{
}
public void HandleSetCurrencyBalanceFailure(TJPlacement placement, int code, string error)
{
}
public void HandleSetRequiredAmountSuccess(TJPlacement placement)
{
}
public void HandleSetRequiredAmountFailure(TJPlacement placement, int code, string error)
{
}
let placement = new TJPlacement('placementName');
try {
await offerwallPlacement?.setRequiredAmount(100, '100');
} catch (e: any) {
let code = e.code;
let message = e.message;
}
If your reward callback server require add permission (whitelist) to access, this is the Tapjoy's IP list. (Last modified: 12 May 2024)
18.215.207.89
18.235.142.165
23.20.255.113
23.23.134.165
3.210.188.32
3.215.42.140
3.217.209.177
3.218.95.35
3.219.236.53
3.231.137.161
If you haven’t launched your app yet, you can switch a Tapjoy Managed currency to a Self-Managed currency from the Edit Virtual Currency screen on the Tapjoy dashboard. Be sure to enter a properly formatted URL into the callback URL field - otherwise the change will not actually take place.
If you have a live application that has currency managed by Tapjoy, the process of switching is more complex. Here are a few things to consider:
To migrate user’s balance, we recommend follow these steps:
If you’re considering switching to self-managed, but aren’t sure how to implement your own virtual currency server we recommend checking out solutions by Parse or UrbanAirship.