Create an Offer Presentation Experience
Ensure that your application backend configures a qualification webhook with Zendrive's IQL service. This webhook will be called every time a user gets qualified for an offer. This section comprises the following topics:
Create an Offer Presentation Experience
Create an Offer Presentation Experience
Create an Offer Presentation Experience
Create an Offer Presentation Experience
Create an Offer Presentation Experience
1.0. Integrate Qualification Webhook
This section describes how to integrate the IQL Qualification Webhook with your application in the backend and send a push notification in response to the webhook.
1.1. Integrate the IQL Qualification Webhook
@api_view(['POST'])
def qualification_webhook(request):
try:
original_data = request.data
payload_data = format_webhook_payload(original_data)
driver_id = payload_data['user']
driver = User.objects.get(driver_id=driver_id)
push_service = PushService()
push_service.send_qualification_push(driver)
return Response(status=status.HTTP_200_OK)
except User.DoesNotExist:
logger.error("Qualification web-hook was sent for a non-existent user"
+ driver_id)
return Response(status=status.HTTP_400_BAD_REQUEST)
except PushService.Error as e:
logger.exception(e)
return Response(status=status.HTTP_200_OK)
KO
1.2. Send a Push Notification In Response To The Webhook
class PushService:
def send_qualification_push(self, driver):
self.__send_push(
driver,
message=None,
extra={
"qualification_status": "qualified",
"msg": "Yay! You qualified for a great offer."
})
def send_heartbeat_push(self, driver):
self.__send_push(driver, message=None, extra={"type": "heartbeat"})
def __send_push(self, driver, message, extra, content_available=1):
gcm_devices = GCMDevice.objects.filter(user=driver)
apns_devices = APNSDevice.objects.filter(user=driver)
if gcm_devices.exists() or apns_devices.exists():
try:
gcm_devices.send_message(message=message, extra=extra)
except Exception:
raise PushService.GCMError(
"Unable to send push notification to Android devices of user, {}."
.format(driver.driver_id))
try:
apns_devices.send_message(
message=message,
content_available=content_available,
extra=extra)
except Exception:
raise PushService.APNSError(
"Unable to send push notification to iOS devices of user, {}."
.format(driver.driver_id))
else:
raise PushService.NoRegisteredDevicesError(
"{} does not have any registered device token.".format(
driver.driver_id))
class Error(Exception):
"""
Base exception for PushService.
"""
class NoRegisteredDevicesError(Error):
"""
Raised if the user doesn't have any registered device tokens.
"""
class GCMError(Error):
"""
Raised upon failure to send push to Android devices.
"""
class APNSError(Error):
"""
Raised upon failure to send push to iOS devices.
"""
1.3. Refresh Driver Status In Response To Qualification Push Notification
abstract class IqlFirebaseServices : FirebaseMessagingService() {
...
...
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
val iqlQualificationStatus = message.data[QUALIFICATION_STATUS_NOTIFICATION_STRING] ?: ""
Timber.d("IQL Qualification Status saved. qualification_status:$iqlQualificationStatus")
if (iqlQualificationStatus.isNotEmpty()) {
ZWLWorkManager.enqueueFetchIQLDriverStatus(applicationContext)
}
}
}
object ZWLWorkManager {
...
...
fun enqueueFetchIQLDriverStatus(context: Context) {
Timber.d("Enqueue work to fetch IQL Driver Status")
val work1 = OneTimeWorkRequestBuilder<FetchIQLDriverStatusWorker>()
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
)
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork(
FETCH_IQL_DRIVER_STATUS,
ExistingWorkPolicy.REPLACE,
work1
class FetchIQLDriverStatusWorker(context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) {
private val loginRepository = ZWLCore.loginRepository()
private val iqlApisRepository = ZWLCore.iqlApisRepository()
override suspend fun doWork(): Result = withContext(AppDispatchers.IO) {
Timber.d("Start fetch IQL Driver Status Work ")
try {
loginRepository.getDriverIdFromPreferences()?.let { driverId ->
iqlApisRepository.refreshDriverStatusFromNetwork(driverId)
}
} catch (e: Exception) {
Timber.e(e, "Fetch IQL Driver Status Work failed")
}
Timber.d("End Fetch IQL Driver Status Work")
return@withContext Result.success()
}
}
1.4. Check if the User is Qualified
class HomeFragment : Fragment(R.layout.fragment_home) {
...
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentHomeBinding.bind(view)
subscribeObserver()
init()
checkNetworkConnectivity()
observeTripDeletionStatus()
with(binding) {
...
…
// Check if user is qualified
viewModel.qualifyStatus.observe(viewLifecycleOwner) { qualificationStatus ->
when (qualificationStatus) {
QUALIFICATION.QUALIFIED.ordinal -> {
showHomeScreen()
// set progress to 100% when user is qualified
setProgressWithoutAnimation(binding.progressIndicatorCard, MAX_PROGRESS)
// update driver status when user is qualified
viewModel.getDriverStatus()
}
QUALIFICATION.NOT_QUALIFIED.ordinal -> {
showHomeScreen()
}
QUALIFICATION.CLEARED.ordinal -> {
Timber.d("clear qualification status")
}
}
}
}
}
...
...
}
1.5. Refresh Driver Status at Application Launch
// Define function to refresh driver status in the home activity
class HomeViewModel(application: Application) : AndroidViewModel(application) {
...
...
fun checkAndExecuteDriverStatusAPI() {
executeApiUsingTimeStamps(previousApiTimeStamp = driverStatusApiTimeStamp) {
executeApi(
calendar = it,
onTimeChanged = {
driverStatusApiTimeStamp = it
Timber.d("Driver Status Api New Time Stamp $driverStatusApiTimeStamp")
},
onExecute = {
getDriverStatus()
},
log = "Driver Status Api called at"
)
}
}
// Refresh driver status on app launch
class HomeActivity : AppBaseActivity(), PopupMenu.OnMenuItemClickListener {
private lateinit var binding: ActivityHomeBinding
private val viewModel: HomeViewModel by viewModels()
...
...
override fun onResume() {
super.onResume()
val recentTrips = viewModel.trips.value
...
...
viewModel.checkAndExecuteDriverStatusAPI()
}
...
}
2.0. Present Offer Using IQL Ad Unit API
This section describes how to integrate the adUnit
API, fetch the Ad Unit details and save them in the local database. Refer to the adUnit
IQL API documentation here:
Use the following code to present an offer through the adUnit
API.

3.0. Capture Additional User Data


4.0. IQL Reference Application UX Design
Here is the overall design implementation for the IQL Reference Application:
5.0. Publisher Integration Testing Checklist
Use the following testing checklist to test your application's offer presentation experience:
Push Notification: Test that the push notification for the offer is displayed correctly and that clicking on it takes the user to the offer page.
Input User Information: Verify that the user is able to input their personal information accurately and that pre-filled fields contain accurate information.