Android offerwall SDK. Native, in a few lines of Kotlin.

Open the Moonetix offerwall as a native screen in your Android app. Install one Gradle dependency, create a session on your server, and call open. Works from Kotlin, Java, and Jetpack Compose.

  • 5.0+Android, API 21
  • 2.0.0Current version
  • 0Extra permissions
Android SDKVersion 2.0.0
EarnActivity.kt
// Once, in your Application class
Moonetix.init(applicationContext, "YOUR_APP_ID")
 
// When the user taps Earn
Moonetix.open(activity, token)

Go live in four steps.

Copy the code, replace the placeholders with the values from your dashboard under Apps, your app, Integration, and test before you launch.

  1. Install the SDK

    Add the Moonetix Maven repository and one dependency. The SDK adds the internet permission and its screen to your manifest by itself, and brings its own R8 and ProGuard rules.

    settings.gradle.kts
    dependencyResolutionManagement {
        repositories {
            google()
            mavenCentral()
            maven { url = uri("https://moonetix.com/maven") }
        }
    }
     
    // app/build.gradle.kts
    dependencies {
        implementation("com.moonetix:offerwall:2.0.0")
    }
  2. Add a token endpoint to your server

    Your app never holds the API key. When a user taps Earn, your app asks your server for a session, and your server asks Moonetix for a single-use token for that signed-in user. A token works once, for 10 minutes.

    session.php
    <?php
    // POST /api/moonetix/session: a fresh token for the signed-in user
    $user = current_user();
    if (!$user) {
        http_response_code(401);
        exit;
    }
     
    $key = getenv('MOONETIX_API_KEY');
    $ch  = curl_init('https://api.moonetix.com/v1/session');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query(['user_id' => (string)$user->id]),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 10,
        CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $key],
    ]);
    $data = json_decode((string)curl_exec($ch), true);
    $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
     
    header('Content-Type: application/json');
    if ($code === 201 && !empty($data['token'])) {
        echo json_encode(['token' => $data['token']]);
        exit;
    }
    http_response_code($code === 403 ? 403 : 503);
    echo json_encode(['error' => 'offerwall_unavailable']);
  3. Open the offerwall

    Call init once with the App ID from your dashboard, then open the offerwall with the token from your server. Errors never throw: they arrive as events, and onClosed is a good moment to refresh the user’s balance.

    EarnActivity.kt
    Moonetix.init(applicationContext, "YOUR_APP_ID")
     
    Moonetix.setListener(object : MoonetixListener {
        override fun onClosed() {
            refreshBalance()
        }
        override fun onError(error: MoonetixError) {
            Log.w("Earn", "${error.code}: ${error.message}")
        }
    })
     
    lifecycleScope.launch {
        val token = fetchMoonetixToken(authToken)
        Moonetix.open(this@EarnActivity, token)
    }
  4. Credit rewards with the postback

    Every reward reaches your server as a signed postback. Check the hash, add the reward once per transaction ID, and take it back if a later postback reverses it. Failed postbacks are retried up to 5 times.

    Postback macros and retries

    Dashboard, Postback tab
    https://yoursite.com/postback?user={user_id}&tx={transaction_id}&status={status}&reward={reward}&hash={hash}
9:41
Earn coins12,450 Coins
EarnMy offers
  • Castle MergeReach level 10+1,500
  • FitTrackStart a free trial+2,000
  • Word RushPlay 3 days in a row+450
  • Budget PalSet up your first budget+800
Reward creditedCastle Merge · +1,500 Coins
Native screen
Postback 200 OK

What your users see

A native screen over your app, with your title and colors, your currency, and every reward confirmed by a postback.

What the SDK handles for you

  • Offers open in the right place

    Offers that lead to Google Play open in the store app, and other sites open in the browser, so installs are tracked correctly.

  • No key inside your app

    Your app holds only the App ID. Sessions are created on your server and work once, so nobody can open the offerwall as another user.

  • A locked-down screen

    Only offerwall pages load inside it, with no JavaScript bridge into your app.

  • Native navigation

    The back button goes back inside the offerwall, and screen rotation or a low-memory restart keeps the user where they were.

  • Your design, no extra code

    The screen uses the title and colors from the Design tab of your dashboard, and picks up changes within a few minutes.

  • No advertising ID

    The SDK does not use the advertising identifier and does not track users across apps.

Test it, then launch.

Everything you need to check before real users see your offerwall, with the tools built into your dashboard.

  1. Open as a test user

    In Integration status on the Integration tab, open your offerwall as the user owner-test. Test visits are not counted as users.

  2. Run it on a real device

    Build for Android or iOS and open the offerwall from your Earn button with a fresh token each time.

  3. Send a test postback

    Choose the user, status, and payout, and see exactly what your server answered, with the response code and time. Test transaction IDs start with test_.

  4. Test from a normal connection

    VPNs, proxies, Tor, and cloud networks are blocked, so test on home Wi-Fi or mobile data, in a country where offers run.

Launch checklist

0 of 11 ready

Common errors, fixed fast.

What you might see while you integrate the Android SDK, what causes it, and the fix.

  • INVALID_APP_ID

    The value passed to init is not the App ID. Passing the API key here is the most common mistake.

    FixCopy the 24-character App ID again from the Integration tab.

  • INVALID_TOKEN

    The app passed something other than the token, or a token created with the API key of another app.

    FixPass only the token field, which starts with sst_, and use the App ID and API key of the same app.

  • TOKEN_EXPIRED_OR_USED

    The token is older than 10 minutes or was already used, for example kept from an earlier tap.

    FixCreate a new token for every open, right when the user taps Earn.

  • NOT_INITIALIZED

    open was called before init.

    FixCall Moonetix.init in Application.onCreate.

  • UNKNOWN

    Android System WebView is missing or turned off, or the Activity you passed was already closing.

    FixAsk the user to update Android System WebView, and pass an Activity that is on screen.

  • onClosed never arrives

    The listener was cleared in onStop, or it belonged to a screen that is gone.

    FixSet it in onCreate and clear it in onDestroy, or set it once in your Application.

  • 403 from /v1/session

    app_not_live means the app is paused or your account is not active. user_blocked means we blocked this user.

    FixDo not show the offerwall. For app_not_live, check your notifications.

  • VPN or Proxy detected

    The device is on a VPN, a proxy, or a cloud network, where offers cannot be tracked.

    FixTest on a normal home or mobile connection, in a country where offers run.

  • Postback log shows 403 or 404

    Your script rejected the postback, or the URL is wrong.

    FixOpen the URL from the log in a browser and check your hash code.

  • Postback log shows a timeout

    Your script takes longer than 6 seconds to answer.

    FixAnswer with 200 first, and run slow work in the background.

  • Postback log shows 301 or 302

    Your URL redirects, for example from http to https.

    FixUse the final URL. Postbacks do not follow redirects.

At a glance

Minimum version
Android 5.0 (API 21), with Android System WebView or Chrome
Languages
Kotlin, Java, and Jetpack Compose
Package
com.moonetix:offerwall:2.0.0 from moonetix.com/maven
Dependencies
Only the Kotlin standard library
Permissions
Internet only, added by the SDK
Price
Free for approved publishers

Other integrations

Android questions

What developers ask before they add the Android SDK.

Stuck on something? Contact us

Which Android versions does the Moonetix SDK support?

Android 5.0 (API 21) or newer, with Android System WebView or Chrome on the device. The only dependency is the Kotlin standard library, so it works in Kotlin and Java apps.

Do I need to add ProGuard or R8 rules?

No. The SDK brings its own R8 and ProGuard rules, and it adds the internet permission and its offerwall screen to your manifest by itself.

Does my API key go into the app?

No. Your app only holds the App ID. Your server creates a session with the API key and passes a token to the app. A token works once and for 10 minutes, so nothing in your app can open another user’s offerwall.

Does the SDK use the advertising ID?

No. It does not use the advertising ID, asks for no permission other than internet access, and does not track users across apps. The docs list what to declare in the Google Play Data safety form.

How do I reward users in my app?

Credit rewards from the signed postback on your server, never from events in the app, because events can be faked on a device. When the user closes the offerwall, load their new balance from your server.

Can the offerwall screen match my app?

Yes. It uses the title and colors from the Design tab of your dashboard. You can also pass your own title, toolbar color, or hide the mark with MoonetixOptions.

Turn your traffic into earnings.

Create a free publisher account and earn from every offer your users complete on your website, app, game, or community.

Worldwide targeting
More
Log in