Developing a Mobile App for Cashback Service
A cashback service is a middleman between user, store, and partner network. Technically: app tracks user transitions to stores (via deeplink or tracking links), partner network confirms purchase, service credits rewards. Main technical challenge—attribution: prove user made purchase via app, not directly.
Tracking Partner Transitions
Use partner network tracking links (Admitad, CJ, Impact, proprietary). How it works:
- App opens tracking link:
https://trk.admitad.com/g/xxxxx?uid={userId} - Tracker redirects to store, sets cookie
- User makes purchase
- Store sends conversion to network with
uid - Network sends postback to service server
- Server credits cashback to user with that
uid
Store transition via SFSafariViewController (iOS) or Custom Tabs (Android). Can't use built-in WKWebView—its cookies isolated and not passed to Safari. This common cause of "lost" attribution.
import SafariServices
func openShopWithTracking(shop: Shop) {
guard let trackingUrl = buildTrackingUrl(shop: shop, userId: currentUser.id) else { return }
let safariVC = SFSafariViewController(url: trackingUrl)
safariVC.preferredControlTintColor = .systemBlue
present(safariVC, animated: true)
// Record transition locally for stats
analyticsService.track(.shopOpened(shopId: shop.id))
}
// Android: Chrome Custom Tabs for tracking
val customTabsIntent = CustomTabsIntent.Builder()
.setShowTitle(true)
.setColorScheme(CustomTabsIntent.COLOR_SCHEME_LIGHT)
.build()
customTabsIntent.launchUrl(this, trackingUri)
Cashback Accrual and Withdrawal
Cashback stored as internal user balance. Accrual statuses:
| Status | Description |
|---|---|
PENDING |
Transition recorded, purchase not confirmed |
CONFIRMED |
Store confirmed purchase (usually 30–90 days) |
AVAILABLE |
Available for withdrawal |
WITHDRAWN |
Withdrawn |
CANCELLED |
Purchase returned, cashback cancelled |
Withdrawal via SBP, card transfer, or promo code conversion. Integrate with payout providers: YooKassa Payouts, Tinkoff Payouts API, MTS Pay.
Store Search and Filtering
Store list—main app screen. Filters: category, cashback size, type (fixed % or fixed amount), new / popular.
Backend—full-text search via PostgreSQL tsvector or Elasticsearch. Client debounces search:
// iOS: search with debounce via Combine
@Published var searchQuery = ""
init() {
$searchQuery
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.filter { $0.count >= 2 }
.sink { [weak self] query in
self?.loadShops(query: query)
}
.store(in: &cancellables)
}
Campaign Notifications
Elevated cashback for limited period—key retention tool. App shows promotions in feed with countdown timer. Push about promotion starts—via FCM/APNs with user interest segmentation.
Timeline Estimates
Basic version (store catalog, tracking, accrual history): 4–6 weeks. Withdrawal via SBP/card—another 1–2 weeks. Pricing is calculated individually.







