Android callbacks and notifications
The Android SDK talks back to your app through callback interfaces. Some you pass as an anonymous object into a method call; others you implement on the Activity or Fragment that hosts the SDK, so the SDK can find them while it is on screen.
This page lists every interface, what it delivers, and when it fires — then covers push notifications, which sit outside the callback system entirely.
The interfaces at a glance
| Interface | Implemented on | Fires when | Payload |
|---|---|---|---|
CHEGTopBannerCallBack | Anonymous object at the call site | The banner request completes | Banner JSON |
CHEGTopOfferCallBack | Anonymous object at the call site | The store request completes | Store JSON |
CHEGCashBackCallBack | Anonymous object at the call site | The points request completes | Points JSON |
CHEGScratchCardCallBack | Anonymous object at the call site | The scratch card request completes | Card JSON with a deep link |
CHEGHeartBeatListener | The calling Activity or Fragment | The user is active inside the SDK | Nothing |
CHEGPaymentListener | Set on CHEGPaymentManager | The SDK needs your app to collect a payment | Base64 payment data |
CHEGscratchRevealCallBack | The calling Activity | A reward is revealed inside the SDK | Reveal data |
onResponse receives a String, not a typed model. The SDK does no error mapping for you — a
failed request may arrive as null, as an empty string, or as a body whose status is false.
Guard all three before parsing.
Data callbacks
These four are structurally identical: one method, one nullable string, delivered when the network call this callback was passed to completes.
CHEGTopBannerCallBack
Delivered by getTopBannerDetails. Carries the banner
creatives for a placement, keyed by placement id.
object : CHEGTopBannerCallBack {
override fun onResponse(responseString: String) {
if (responseString.isBlank()) return renderNoBanners()
val response = Gson().fromJson(responseString, BannerResponse::class.java)
renderCarousel(response.banners["01"].orEmpty())
}
}
Once you render a creative, fire its impression with CheggoutUtils.Companion.trackLink(href, virtualId). The callback firing is not an impression — display is.
CHEGTopOfferCallBack
Delivered by getTopStoreDetails. Carries an array of stores
with storeId, title, href, logo, discountPercentage and category.
object : CHEGTopOfferCallBack {
override fun onResponse(responseString: String?) {
val stores = parseStores(responseString ?: return)
renderStoreRail(stores) // show name AND discount
}
}
CHEGCashBackCallBack
Delivered by getChegCashBackPoints. Carries
{ "cashbackPoints": "100", "deepLink": "deeplinkString" }. cashbackPoints is a string.
object : CHEGCashBackCallBack {
override fun onResponse(responseString: String?) {
val points = parsePoints(responseString) ?: return hideCoinBadge()
coinBadge.text = points.cashbackPoints
coinBadge.setOnClickListener { openDeepLink(points.deepLink) }
}
}
CHEGScratchCardCallBack
Delivered by getScratchCardDetails. Carries the card's
status, banner, deepLink and the optional interstitial fields.
object : CHEGScratchCardCallBack {
override fun onResponse(responseString: String?) {
val card = parseCard(responseString) ?: return
if (!card.status) return // "not eligible" — a normal outcome
showCardBanner(card.banner) { launchWithDeepLink(card.deepLink) }
}
}
status: false means no card was issued. Treat it as a non-event and show nothing — not as an error
worth surfacing to the user.
CHEGHeartBeatListener
Implemented on the Activity or Fragment that launches the SDK. The SDK calls
onCheggoutHeartBeat() while the user is interacting inside Cheggout, so your app's inactivity
timer does not expire a session that is in fact active.
class ShopActivity : AppCompatActivity(), CHEGHeartBeatListener {
override fun onCheggoutHeartBeat() {
sessionManager.recordActivity()
}
}
It only reaches you if you launch with the overload that takes the implementing instance:
// Activity: pass `this`. Fragment: pass `getActivity()`.
CheggoutApplication.Companion.launchCheggout(
this, virtualId, sessionId, payload, instanceOfActivity
)
This directly determines where the user lands when they come back: with an active session they return to your home page, without one they return to your login page. See Launching.
TBD The heartbeat interval is not documented. Do not assume a fixed cadence — treat each call as "activity happened recently" and reset your timer, rather than deriving elapsed time from the gap between calls.
CHEGPaymentListener
Used by the deep payment flow, where the user buys something inside Cheggout and your app collects
the money. Set the callback on a CHEGPaymentManager instance:
val chegPaymentManager = CHEGPaymentManager()
chegPaymentManager.setCallback(object : CHEGPaymentListener {
override fun initPaymentCallFromCheggout(responseString: String?) {
val json = String(Base64.decode(responseString, Base64.DEFAULT))
val payment = parsePayment(json)
startPayment(payment)
}
})
responseString is Base64. Decoded, it looks like this:
{
"deepLink": "https://click.cheggout.com?type=pwa&id=<giftcard url>?token=tokenvalue/cheggoutRefNo=YOURCHANNEL123456/paymentType=YOURCHANNEL/amount=540.00/transactionId=bankTransactionID/status=bankStatus",
"cheggoutRefNo": "YOURCHANNEL123456",
"amount": "54000",
"responseCode": "COLLECTPAYMENT",
"virtualId": "pub_8f14e45fceea167a",
"merchantName": "Cheggout",
"merchantId": "REPLACE_WITH_MERCHANT_ID"
}
| Field | Meaning |
|---|---|
deepLink | Used to relaunch the SDK after payment. Replace bankTransactionID with your payment's transaction ID and bankStatus with the payment status. |
cheggoutRefNo | Unique reference number generated by Cheggout for this transaction. Store it — it is your reconciliation key. |
amount | Payment amount in paisa. "54000" is ₹540.00. |
responseCode | COLLECTPAYMENT. |
virtualId | The user this payment belongs to. |
merchantName | Identifies the transaction source within Cheggout, for example Cheggout. |
merchantId | A unique identifier per merchant name, issued by the bank during onboarding. |
amount is in paisaEvery other amount in the Cheggout contract — GetReward, getScratchCardDetails — is in rupees to
two decimals. This one is in paisa. Charging 54000 rupees instead of 540.00 is a real failure
mode; convert explicitly and assert on the result.
After the payment completes, rebuild the payload with the updated deep link and relaunch:
val payload =
"{'Component':'CHEGGOUT','IsEmployee':'1','Language':'EN','DeeplinkInfo':'$deepLink'}"
CheggoutApplication.launchCheggout(this, virtualId, sessionId, payload)
Full flow in Deep payment.
CHEGscratchRevealCallBack
Implemented on the calling Activity. Fires when a reward is revealed inside the SDK, so your app can react — refresh a points balance, log an analytics event, or show your own confirmation.
class ShopActivity : AppCompatActivity(), CHEGscratchRevealCallBack {
override fun onReveal(onRevealData: String?) {
Log.d("Cheggout", "onReveal: $onRevealData")
rewardsRepository.refresh()
}
}
TBD The schema of onRevealData is not documented. Log it in UAT to see what your
build delivers, and do not parse fields you have not observed. The iOS equivalent broadcasts a
HandleDominosScDetails notification; see iOS callbacks.
Push notifications
Push sits outside the callback system: Cheggout needs to reach the user when your app is not running. There are two integration options, and you pick one during onboarding. They differ in who owns the delivery infrastructure.
Option 1 — Push via your Bank API
You already have a push service. Cheggout calls it.
- You provide an API that sends a push notification to a user.
- Cheggout calls it with the
VirtualID— the same one your app passed when launching the SDK — and the message. - Cheggout includes deep-link information in that call. Your push service must carry the deep link through to the notification payload.
- Your app, on notification tap, launches the SDK with that deep link in the payload's
DeeplinkInfo.
This keeps device tokens and delivery entirely inside your infrastructure. It costs you an endpoint and the discipline of not dropping the deep-link field on the way through.
launchCheggout needs an Activity context, so a FirebaseMessagingService cannot make the call
itself. Carry the deep link through to an Activity and launch from there.
// 1. In your FirebaseMessagingService — extract the deep link and hand it to an Activity.
class PushService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val deepLink = remoteMessage.data["deepLink"] ?: return
val intent = Intent(this, ShopActivity::class.java)
.putExtra("cheggoutDeepLink", deepLink)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// Attach this intent to your notification's PendingIntent, so the tap opens ShopActivity.
showNotification(remoteMessage, intent)
}
}
// 2. In the Activity the notification opens — launch the SDK with the deep link.
class ShopActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val deepLink = intent.getStringExtra("cheggoutDeepLink") ?: ""
val payload =
"{'Component':'CHEGGOUT','IsEmployee':'0','Language':'EN','DeeplinkInfo':'$deepLink'}"
// virtualId and sessionId come from your backend, as on any other launch.
CheggoutApplication.launchCheggout(
this, virtualId, sessionId, payload, this, "YOURCHANNEL"
)
}
}
Option 2 — Push managed by Cheggout
Cheggout sends directly to the device.
- Your app communicates the FCM ID while launching the Cheggout SDK. TBD The
pushnotificationIDpayload key is documented for iOS; the documented Android payload string isComponent/IsEmployee/Language/DeeplinkInfo/customerId. Confirm with Cheggout how the FCM ID should be passed on Android. - You provide FCM API credentials to Cheggout so it can configure and send notifications.
This is less work in your codebase, but it means handing Firebase credentials to a third party and giving up visibility over what is sent. Most banks choose Option 1 for that reason.
| Option 1 — your API | Option 2 — Cheggout sends | |
|---|---|---|
| Who holds device tokens | You | Cheggout, via your FCM project |
| What you build | A send endpoint Cheggout can call | Passing pushnotificationID at launch |
| What you hand over | Nothing sensitive | FCM API credentials |
| Deep-link handling | You forward it | Cheggout embeds it |
| Visibility over sends | Full | Limited |
TBD Neither option is fully specified in the integration document. The request contract for your Bank API endpoint, its authentication, the FCM credential handover process, and the notification payload shape all need to be agreed with Cheggout before you build. Raise them in your onboarding call and record the answers.
FCM device tokens are user identifiers. Keep them out of logs you export, out of support tickets, and out of anything shared outside your team.
Next
- SDK methods — the calls these callbacks are passed into.
- Launching — the payload, the exit handshake and the heartbeat overload.
- Deep payment — the full payment round trip.