Flutter offerwall plugin. One Dart API, Android and iOS.

Add the Moonetix offerwall to your Flutter app with one plugin. It brings the native Android and iOS SDKs with it, so there is nothing else to set up in Gradle or Xcode.

  • 3.27+Flutter
  • 2.0.0Current version
  • 2Platforms, one plugin
Flutter SDKVersion 2.0.0
main.dart
import 'package:moonetix_offerwall/moonetix_offerwall.dart';
 
Moonetix.init('YOUR_APP_ID');
 
// When the user taps Earn
await Moonetix.open(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 plugin

    Add the plugin from the Moonetix package repository and run flutter pub get. On Android it brings the Maven repository, SDK, and R8 rules. On iOS it brings the iOS SDK for CocoaPods and Swift Package Manager.

    pubspec.yaml
    dependencies:
      moonetix_offerwall:
        hosted: https://moonetix.com/pub
        version: ^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 with a fresh token. Listen to Moonetix.events before you call open, and refresh the balance when the user closes the offerwall.

    main.dart
    void main() {
      WidgetsFlutterBinding.ensureInitialized();
      Moonetix.init('YOUR_APP_ID');
      runApp(const MyApp());
    }
     
    Moonetix.events.listen((MoonetixEvent event) {
      switch (event) {
        case MoonetixOpened():
          break;
        case MoonetixClosed():
          refreshBalance();
        case MoonetixErrorEvent(:final MoonetixError error):
          debugPrint('${error.code.name}: ${error.message}');
      }
    });
     
    await Moonetix.open(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 plugin handles for you

  • Native SDKs included

    The plugin brings the Android and iOS SDKs with it. No Gradle repositories or Xcode steps to add by hand.

  • Offers open in the right place

    Store offers open in Google Play or the App Store, and other sites in the browser, so installs are tracked correctly.

  • No key inside your app

    Your app holds only the App ID. Sessions come from your server and work once.

  • Typed events

    A broadcast stream of MoonetixOpened, MoonetixClosed, and MoonetixErrorEvent, or a listener if you prefer callbacks.

  • Your design

    The screen uses the title and colors from the Design tab of your dashboard.

  • No advertising ID

    The plugin 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 Flutter SDK, what causes it, and the fix.

  • invalidAppId

    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.

  • invalidToken

    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.

  • tokenExpiredOrUsed

    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.

  • notInitialized

    open was called before init.

    FixCall Moonetix.init in main().

  • unsupported

    The app runs on web or desktop, or the native part of the plugin is not in the build yet.

    FixRun on Android or iOS, and stop and rebuild the app. Hot reload does not add native code.

  • No events arrive

    The app started listening after it called open.

    FixListen to Moonetix.events before you call open, from an object that stays alive.

  • 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

Flutter version
Flutter 3.27 or newer
Platforms
Android 5.0+, and iOS 13+ built with Xcode 16 or newer
Package
moonetix_offerwall ^2.0.0, hosted at moonetix.com/pub
Language
Dart
Native setup
None, the plugin brings both SDKs
Price
Free for approved publishers

Other integrations

Flutter questions

What developers ask before they add the Flutter SDK.

Stuck on something? Contact us

Which Flutter versions does the plugin support?

Flutter 3.27 or newer. On iOS, build with Xcode 16 or newer.

Is the plugin on pub.dev?

It is hosted in the Moonetix package repository. Add it to pubspec.yaml with hosted: https://moonetix.com/pub and run flutter pub get, the same way you add any package.

Do I need to change Gradle or Xcode settings?

Usually not. The plugin brings the Android and iOS SDKs with it. Only if your android/settings.gradle blocks project repositories, add the Moonetix Maven repository there.

How do I know when the user closes the offerwall?

Listen to Moonetix.events, a broadcast stream, before you call open. MoonetixClosed is a good moment to load the user’s balance from your server.

How are rewards credited?

From the signed postback on your server, once per transaction ID. Events in the app are for your user interface only.

What do I declare in the store privacy forms?

User ID, Device ID, Coarse Location, and Product Interaction, linked to the user, not used for tracking. The docs list the Google Play names for the same data types.

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