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:

adUnit Endpoint V2.0

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.