Reward app with 5-network ad mediation
Earning Point is an Android reward application backed by a full Laravel admin panel, built for an external freelance client as a white-label "GPT/reward" product — a monetisation model common in India where users complete micro-tasks for points redeemable as cash or vouchers. Users earn points by watching YouTube videos, visiting sponsored websites, completing offerwall surveys via CPX integration, spinning a lucky wheel, claiming daily check-in bonuses, and referring friends. The point balance is redeemable through admin-configured payout options, with withdrawal requests routed through a manual approval queue in the admin panel.
This was the first significant external freelance engagement — client deadline, real money, and a non-technical buyer who needed a complete turnkey product. The deliverable was not just source code but a fully packaged ZIP at version 5.9, including a pre-seeded MariaDB SQL dump, signing keystore, a How to Update.txt, and a GitBook documentation site. That packaging discipline is what separated it from a GitHub handoff.
The client needed something that worked as both a functional product and a maintainable white-label kit — configurable enough that branding, API endpoints, and reward logic could be changed without touching source code. The reward API also had an obvious vulnerability: any script that could call the point-credit endpoints would drain the payout pool. The solution had to block automated farming at the device level, not just with rate limits.
Choosing the ad strategy required care. AdMob alone has poor fill rates in India (a Tier 3 advertising market), which directly impacts the platform's ability to fund user point payouts. A single-network integration would have left significant eCPM on the table, but manually managing fallback logic across five SDKs would have added brittle complexity to the AdManager layer.
The Android app is 318 Java source files built on Android SDK 34 (minSdk 21), using a classic Activity-based architecture with Retrofit 2 and OkHttp 3 for networking and Gson for serialisation. An ApiClient.java singleton and ApiInterface.java define all endpoints; the API_URL and API_KEY are injected at build time from gradle.properties via buildConfigField, so white-labelling requires changing two properties, not hunting through source. Auth tokens issued by Laravel Sanctum are persisted in SharedPreferences via Session.java. Push notifications go through Firebase Cloud Messaging. The lucky wheel spin animation runs as a local Gradle subproject (luckyWheel module) bundled alongside the main app, giving full control over animation timing and prize sector configuration to match the backend's wheel_points table.
The Laravel admin panel runs on PHP 8.1 with Eloquent ORM against a 27-table MariaDB schema. Yajra Datatables handles server-side paginated table rendering; Spatie Laravel Permission manages sub-admin RBAC; Intervention Image handles avatar processing; Hammerstone Fast Paginate applies keyset-based pagination for large transaction logs. The offerwall CPX postback endpoint (/offer_cr/{id}) receives completion callbacks from the survey network, verifies the shared secret, and credits the offerwall_earing and transaction tables in one atomic operation.
AppLovin mediation over manual network switching. Integrating five ad SDKs and writing fallback logic manually would have produced fragile waterfall code in AdManager. AppLovin's mediation layer handles waterfall ordering, timeout, and fill-rate optimisation automatically — the app calls one SDK and the mediation routes to whichever network bids highest. Standard practice for India-market consumer apps, and the right call for a client who can't afford poor eCPM on a reward platform.
Firebase App Check with Play Integrity attestation. The obvious exploit in any reward app is scripted API calls to farm points without engaging with content. App Check requires a valid attestation token generated on a real Android device with a verified Play Store signature — emulators and sideloaded builds fail at the attestation layer before reaching rate limiting. The setup friction (Play Console SHA registration, Firebase project linking, enforcement toggling) is real, but essential for the business model's integrity.
BuildConfig API key injection. Hardcoding the backend URL or API key in source would force a full recompile to white-label. Injecting from gradle.properties via buildConfigField means the client changes two lines to point the app at a different backend — no source editing required.
luckyWheel as a local Gradle module. The spin wheel animation needed to match the backend's configurable prize sector structure exactly. A third-party library would have imposed its own data model; a local module gives full control over sector count, weights, and animation timing to stay in sync with what the wheel_points admin table defines.
The project was delivered at version 5.9 as a complete client package — 318 Java source files, a full Laravel admin panel, a 27-table MariaDB schema, and five ad networks mediated through a single AppLovin integration. The reward API is protected against bot farming by Firebase App Check Play Integrity attestation. The delivery package included SQL dump, keystore, update instructions, and GitBook documentation, requiring zero technical hand-holding from the client. It established the template for subsequent freelance deliveries.
Java source files
MariaDB tables
ad networks mediated
delivered version
Expo SDK 55 React Native app with Reanimated 4, self-hosted Supabase, and a custom OdometerText animation
Offline-first Flutter app with GetX state management, Appwrite backend, and Lottie animations
Did this resonate?