ayeT-Studios Publisher Unity SDK Integration Guide (v1.8)
Publisher Documentation Overview
- API Placement - Documentation
- Android Placement - SDK Integration Guide
- iOS Placement - Swift SDK Integration Guide
- Unity SDK Integration Guide
- Web Placement - In-App Webview Offerwall Integration Guide
- Web Placement - Mobile & Desktop Browser Offerwall Integration Guide
- Rewarded Video HTML5 Web Integration Guide
Updates
2022-04-25: v1.8 - Updated to latest Android & iOS SDKs, fixed some warnings, based on Unity 2021
2020-06-11: v1.7.1 - Updated documentation to introduce new parametars to differentiate chargebacks from conversions
2020-07-29: v1.7 - Updated to latest Android & iOS SDKs, based on Unity 2019 LTS
2019-07-19: v1.6 - Updated wrapper & SDKs with adslot changes, recompiled iOS SDK with Swift 5
2019-02-01: v1.5 - Fixed conversion tracking issues under certain conditions (application lifecycle monitoring improved)
2018-12-04: v1.4 - Updated to Android SDK 3.0 - support for API 26+ build targets, bugfixes & improved handling under poor network conditions
2018-09-29: v1.3 - Updated iOS SDK to Xcode 10 and Swift 4.2, stripped debug symbols
2018-07-09: v1.2 - Removed Simulator Code from iOS SDK, fixed iTunes validation issues with Xcode 9+
2018-07-02: v1.1 - Updated Unity SDK (iOS) to Unity 2018 / Swift 4.1 / XCode 9.4, added post-install script for automatic XCode configuration
2018-01-20: v1.0 - Initial Release of our Publisher SDK (Unity)
Quick 1.3 To 1.8 Migration Guide
- Update your AyetSdk.showOfferwall() calls to pass the target offerwall adslot name as parameter
Introduction
The ayeT-Studios Publisher SDK allows you to easily monetize your app and reward your users with in-app currency. Your users get access to our offerwalls, allowing them to earn currency for completing tasks such as trying new apps, answering surveys, signing up for free trials or watching video ads. The integration is simple, allows both managed (our servers store user information and balances) and unmanaged (you receive callbacks and handle user wallets yourself) currencies and also works well alongside traditional in-app purchases.Topics
- Prerequisites
- Download The SDK
- Add The Package To Your Unity Project
- Android Specific: Update Or Create AndroidManifest.xml File
- Initialize The SDK & Managed User Balances
- Check User Balances (Managed Currency Handling)
- Show The Offerwall
- Unity Example Script
- Appendix I: Unmanaged Currency Handling / Conversion Callbacks
- Appendix II: Assets/Plugins/Android/AndroidManifest.xml Template
1. Prerequisites
Before integrating the SDK in your app, you should sign up for a publisher account.
Afterwards login as publisher and create a new Android App Placement and/or iOS App Placement using the correct android package name or iOS bundle identifier you intend to use for your final apps.
This is important since we'll generate APP_KEYs / Identifiers for you which have to be added to your Unity app.
So for each platform you intend to build on, you should create a separate placement and adslots (e.g. 2 placements for your Android / iOS cross-platform app).
The minimum required OS version is iOS 11.0 (and Swift 5.x ABI) and Android 5.1+.
Afterwards login as publisher and create a new Android App Placement and/or iOS App Placement using the correct android package name or iOS bundle identifier you intend to use for your final apps.
This is important since we'll generate APP_KEYs / Identifiers for you which have to be added to your Unity app.
So for each platform you intend to build on, you should create a separate placement and adslots (e.g. 2 placements for your Android / iOS cross-platform app).
The minimum required OS version is iOS 11.0 (and Swift 5.x ABI) and Android 5.1+.
2. Download The SDK
You can download the lastest version of our publisher package here:
AyetUnityPlugin_v1.8.unitypackage
AyetUnityPlugin_v1.8.unitypackage
3. Add The Package To Your Unity Project
Open your Unity project
- Assets -> Import Package -> Custom Package
- Select the AyetUnityPlugin_vVersion.unitypackage file
- Press the "Import" button to complete the process
4. Android Specific: Update Or Create AndroidManifest.xml File
If you're planning to build against Android, please make sure you have an AndroidManifest.xml file in Assets/Plugins/Android/.
If no AndroidManifest exists, you can check out the following template: Appendix II: AndroidManifest.xml Template.
Add these app permissions to the manifest:
Add our offerwall activity to your <application> scope:
Add these app permissions to the manifest:
<uses-permission android:name="android.permission.INTERNET" /> <!-- mandatory permission --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- optional --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- optional -->
Add our offerwall activity to your <application> scope:
<activity android:name="com.ayetstudios.publishersdk.OfferwallActivity" android:configChanges="orientation|screenSize"> <intent-filter android:label="offer"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="offer" android:host="com.example.myapplication" /> <!-- Replace with your lower case package name --> </intent-filter> </activity> <activity android:name="com.ayetstudios.publishersdk.VideoActivity" android:configChanges="orientation|screenSize" />
5. Initialize The SDK & Managed User Balances
In this step, we are going to initialize the SDK. We also use callbacks to track the user's account balance - this is optional and not required if you're planning to manage user balances on your own servers.
Attention: The username or external identifier passed in the init call (e.g. username, hashed email address, etc.) will be accessible in the conversion callbacks through the {external_identifier} parameter.
First, the SDK needs to be initialized like this (APP_KEY is the placement identifier you can find in your dashboard in the android or ios placement details):
Implement the SdkUserBalance interface in order to get notified when user balance changes occur:
If you want to spend user currency, for example if the user clicks a "purchaseInAppItem" button, you can utilize the deductUserBalance function:
First, the SDK needs to be initialized like this (APP_KEY is the placement identifier you can find in your dashboard in the android or ios placement details):
#if UNITY_IOS AyetSdk.init ("<YOUR_IOS_PLACEMENT_APP_KEY>", "<username (external identifier)>", this); #endif #if UNITY_ANDROID AyetSdk.init ("<YOUR_ANDROID_PLACEMENT_APP_KEY>", "<username (external identifier)>", this); #endif
Implement the SdkUserBalance interface in order to get notified when user balance changes occur:
public void userBalanceInitialized (int available_currency, int pending_currency, int spent_currency){ Debug.Log("Your::Script::userBalanceInitialized => available_currency: " + available_currency.ToString() + " pending_currency: "+pending_currency.ToString() + " spent_currency: " + spent_currency.ToString() ); }userBalanceInitialized is triggered after calling AyetSdk.init().
public void userBalanceChanged (int available_currency, int pending_currency, int spent_currency){ Debug.Log("YourScript::userBalanceChanged => available_currency: " + available_currency.ToString() + " pending_currency: "+pending_currency.ToString() + " spent_currency: " + spent_currency.ToString() ); }userBalanceChanged is triggered if the user balance changes while running the app.
If you want to spend user currency, for example if the user clicks a "purchaseInAppItem" button, you can utilize the deductUserBalance function:
AyetSdk.deductUserBalance (<DEDUCT_AMOUNT>, this);Implement the SdkDeductCallback interface in order to get notified if a deduction succeeded:
public void deductSuccess (){ Debug.Log ("YourScript::deductSuccess"); } public void deductFailed (){ Debug.Log ("YourScript::deductFailed"); }
6. Check User Balances (Managed Currency Handling)
After initializing the SDK, you can check the current user balances anywhere in your code:
AyetSdk.getAvailableCurrency(); AyetSdk.getPendingCurrency (); AyetSdk.getSpentCurrency ();
7. Show The Offerwall
Showing the offerwall is straight-forward, you can simply call AyetSdk.showOfferwall:
AyetSdk.showOfferwall("your offerwall adslot name");showOfferwall starts our offerwall activity and displays available tasks for the user to complete.
8. Unity Example Script
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ExampleScript : MonoBehaviour , SdkUserBalance , SdkDeductCallback { public void userBalanceInitialized (int available_currency, int pending_currency, int spent_currency){ Debug.Log("ExampleScript::userBalanceInitialized => available_currency: " + available_currency.ToString() + " pending_currency: "+pending_currency.ToString() + " spent_currency: " + spent_currency.ToString() ); } public void userBalanceChanged (int available_currency, int pending_currency, int spent_currency){ Debug.Log("ExampleScript::userBalanceChanged => available_currency: " + available_currency.ToString() + " pending_currency: "+pending_currency.ToString() + " spent_currency: " + spent_currency.ToString() ); } public void deductSuccess (){ Debug.Log ("ExampleScript::deductSuccess"); } public void deductFailed (){ Debug.Log ("ExampleScript::deductFailed"); } void Start () { } void Update () { if (Input.touchCount == 1) { Touch touch = Input.touches [0]; if (touch.phase == TouchPhase.Ended) { if (Input.GetTouch (0).position.y > (Screen.height/2)) { //sdk initialization AyetSdk.init ("abcde123abcde123abcde123", "user_id_123", this); } else { if (Input.GetTouch (0).position.x < (Screen.width/3)) { //show offerwall AyetSdk.showOfferwall("offerwall adslot name"); } else if(Input.GetTouch (0).position.x > ((Screen.width/3)*2)){ //show user current balance Debug.Log ("ExampleScript Available currency: " + AyetSdk.getAvailableCurrency()); Debug.Log ("ExampleScript Pending currency: " + AyetSdk.getPendingCurrency ()); Debug.Log ("ExampleScript Spent currency: " + AyetSdk.getSpentCurrency ()); } else { int amount = 1; //deduct balance AyetSdk.deductUserBalance (amount, this); } } } } } }
9. Appendix I: Unmanaged Currency Handling / Conversion Callbacks
If you want to manually manage your users currencies on your own servers, you can configure a conversion callback url in our publisher dashboard.
To do so, navigate to Placements / Apps, edit your app placement and set the Callback Url to your server's postback url:
If this is the callback url your set for your app placement:
A typical conversion callback sent by our server will look like this:
Important: Your server must always reply with an HTTP 200 status code to our postbacks. Otherwise we will resend the postback 12 times over a span of one hour before giving up.
Available Macros for Postback URLs:
Postback Verification with HMAC Security Hash (optional):
Our server will always add a custom header, X-Ayetstudios-Security-Hash, containing a SHA256 HMAC hash of the request parameters and your publisher api key.
Your API key can be found in your dashboard at ayetstudios.com under settings.
To verify the hash, perform the following steps:
(1) Get all request parameters
(2) Order the request parameters alphabetically
(3) Build and compare the HMAC hash using the ordered request parameter string and your API key
PHP Example:
If your want to restrict postbacks to our callback server IPs, please whitelist the following IPs and check back regularly for possible changes:
To do so, navigate to Placements / Apps, edit your app placement and set the Callback Url to your server's postback url:

If this is the callback url your set for your app placement:
https://your-server.com/callback?network=ayetstudios&amount={currency_amount}&uid={uid}&device={advertising_id}&payout_usd={payout_usd}
A typical conversion callback sent by our server will look like this:
https://your-server.com/callback?network=ayetstudios&amount=360&uid=username&device=[GAID/IDFA]&payout_usd=0.36* Note: This assumes you set the user identifier to username in your AyetSdk.init(..) call, the currency conversion rate in your placement was 1000 per $1 and the user completed an offer with a $0.36 payout.
Important: Your server must always reply with an HTTP 200 status code to our postbacks. Otherwise we will resend the postback 12 times over a span of one hour before giving up.
Available Macros for Postback URLs:
{transaction_id} | string | Unique transaction id - use for duplicate checks. If chargeback it's prepend with r- |
{payout_usd} | float | The actual conversion payout in USD. If chargeback value is negative. |
{currency_amount} | float | The amount of currency the user earned (taken from your offerwall currency configuration). If chargeback value is negative. |
{external_identifier} | {uid} | string | The user identifier set in your app for this user when initializing the sdk |
{user_id} | integer | Our internal id for this offerwall user |
{placement_identifier} | string | The placement_identifier for which the conversion occured |
{adslot_id} | int | The id of the adslot for which the conversion occured |
{ip} | string | Converting device's IP address if known, 0.0.0.0 otherwise |
{offer_id} | int | Offer ID of the converting offer |
{offer_name} | string | Name / title of the converting offer |
{device_uuid} | string | ayeT-Studios internal device identificator |
{device_make} | string | Device manufacturer |
{device_model} | string | Device model |
{advertising_id} | string | Device advertising id (GAID/IDFA) if known, otherwise empty |
{sha1_android_id} | string | Device sha1 hashed android id if known, otherwise empty |
{sha1_imei} | string | Device sha1 hashed imei if known, otherwise empty |
{is_chargeback} | int | Values 0 or 1. Indicator if the callback is conversion or chargeback. If set to 0 then it's conversion else it's chargeback. |
{chargeback_reason} | string | Reason why chargeback created. Only available if is_chargeback set to 1. |
{chargeback_date} | string | Date of chargeback creation. Only available if is_chargeback set to 1. |
{task_name} | string | Only available for cpe campaigns, shows individual task name for that conversion |
{currency_identifier} | string | Shows virtual currency name as set in adslot. |
{currency_conversion_rate} | decimal | Shows currency conversion rate used to calculate user currency for the given conversion. |
Postback Verification with HMAC Security Hash (optional):
Our server will always add a custom header, X-Ayetstudios-Security-Hash, containing a SHA256 HMAC hash of the request parameters and your publisher api key.
Your API key can be found in your dashboard at ayetstudios.com under settings.
To verify the hash, perform the following steps:
(1) Get all request parameters
(2) Order the request parameters alphabetically
(3) Build and compare the HMAC hash using the ordered request parameter string and your API key
PHP Example:
ksort($_REQUEST, SORT_STRING); $sortedQueryString = http_build_query($_REQUEST, '', '&'); // "adslot_id=123¤cy_amount=100&payout_usd=1.5...." $securityHash = hash_hmac('sha256', $sortedQueryString, 'YOUR PUBLISHER API KEY'); if($_SERVER['HTTP_X_AYETSTUDIOS_SECURITY_HASH']===$securityHash) { // actually sent as X-Ayetstudios-Security-Hash but converted by apache2 in this example // success } else { // invalid signature }
If your want to restrict postbacks to our callback server IPs, please whitelist the following IPs and check back regularly for possible changes:
35.165.166.40 35.166.159.131 52.40.3.140Last IP List Update: 2017-04-07
10. Appendix II: Assets/Plugins/Android/AndroidManifest.xml Template
This is a sample AndroidManifest template in case you're not using a custom AndroidManifest file yet. Please make sure to update package, versionCode and versionName.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication" <!-- Replace with your lower case package name --> android:versionCode="1" android:versionName="1.0" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal"> <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" /> <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name"> <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> </activity> <activity android:name="com.ayetstudios.publishersdk.OfferwallActivity" android:configChanges="orientation|screenSize"> <intent-filter android:label="offer"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="offer" android:host="com.example.myapplication" /> <!-- Replace with your lower case package name --> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> <!-- mandatory permission --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- optional --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- optional --> </manifest>