Skip to main content

Scratch cards in the mobile SDK

On mobile there are two ways to issue a scratch card, and they are not equivalent. This page covers both, explains why one is materially safer, and shows how to receive the reveal callback when the user scratches inside the SDK.

PathWho calls CheggoutRecommended
Server-to-serverYour backend, with a signed envelope, after validating the orderYes
Client SDK callThe app, through an SDK helperOnly where the server path is not viable

Both paths end the same way: Cheggout returns a deep link, and the app launches the SDK with it to show the card.

Which path to use

Prefer server-to-server issuance

A client-initiated issuance path allows requests that are not tied to a verified transaction — the app is asserting that a payment happened, and the app is the least trustworthy place to assert that from. The server path lets your backend validate the order first and only then make a signed request for a card.

The rule that follows from this: bind virtualId and extTransactionId to a verified order on your server. Never accept them from client input. See Security best practices.

Use the client SDK call when your architecture genuinely cannot route the event through a backend — for example a transaction that completes entirely inside a third-party payment component your server never sees. Even then, treat it as a temporary state and plan the server path.

GetScratchCardForBank issues a card from your backend using the signed envelope — the same mechanism as the session API.

EnvironmentURL
Productionhttps://bankapi.cheggout.com/api/GetScratchCardForBank
UAThttps://bankapi-uat.cheggout.com/api/GetScratchCardForBank

Flow

Request

The envelope is standard. The BDATA payload is:

{
"virtualId": "pub_8f14e45fceea167a",
"transDateAndTime": "2026-07-31 14:15:30",
"amount": "499.00",
"mcc": "5814",
"extTransactionId": "PUB_TXN_20260731_000117",
"campaignId": "902",
"deviceToken": "REPLACE_WITH_DEVICE_TOKEN"
}
FieldDescription
virtualIdYour pseudonymous user identifier
transDateAndTimeTransaction timestamp, documented in the form 2026-07-31 14:15:30
amountTransaction amount. TBD The unit is not documented — confirm with Cheggout whether this field is rupees or paisa before going live, because sending the wrong unit changes which campaign tier a transaction qualifies for and will not surface as an error
mccMerchant category code for the transaction
extTransactionIdYour unique reference for this issuance. TBD Replay semantics for this endpoint are not documented — see GetScratchCardForBank
campaignIdThe campaign this issuance belongs to. This endpoint takes a campaign identifier, not a trigger code — see Trigger events
deviceTokenPush device token, used for reward notifications

Note that transDateAndTime here uses a different format from the dateandtime (DDMMYYYYHHMMSS) used by the client SDK call and the headless GetReward. Do not share a formatter between them.

GetScratchCardForBank
curl -X POST https://bankapi-uat.cheggout.com/api/GetScratchCardForBank \
-H "Content-Type: application/json" \
-d '{
"CHANNELID": "YOURCHANNEL",
"SIGN": "REPLACE_WITH_SIGNATURE",
"BDATA": "<base64 of the payload above>"
}'

Response

Success, after verifying and decoding BDATA:

{
"status": true,
"deepLink": "https://click.cheggout.com?type=reward&scratchCardId=1",
"message": "success",
"banner": "https://cdn.example.com/scratch-card-banner.png"
}

Failure:

{
"status": false,
"deepLink": "",
"message": "failure",
"banner": ""
}
Handle both response framings

The failure case may come back unsigned and bare rather than inside a signed envelope. Check for the failure shape before attempting signature verification, or your client will throw on a legitimate "not eligible" answer.

status: false here carries the same meaning as everywhere else in this module: the user is not eligible right now. Render nothing and move on.

Full contract: GetScratchCardForBank.

Client SDK issuance

The SDK exposes a helper that performs issuance directly from the app. It is the shortest path to a working demo and the weakest path for production.

Parameters

FieldTypeRequiredNotes
triggerEventTypeStringYesPredefined campaign or trigger code, for example UPI, WITHINBANK, IMPS, RTGS
amountDoubleYesTwo decimal places
extTransactionIdStringYesUnique alphanumeric, maximum 256 characters
dateandtimeStringYesFormat DDMMYYYYHHMMSS
virtualIdStringYesYour pseudonymous user identifier
sessionIdStringYesPass the literal " " — a single space — as documented
subTriggerEventTypeStringNoFiner-grained sub-category
merchantVPAStringConditionalRequired only for UPI
additionalParamsStringNoA JSON string

additionalParams accepts these optional inner keys: country, state, district, city, pincode, storeId, ipaddress, lat, long, gender, age, modeType, isNewUser.

sessionId is not a real session here

Unlike the marketplace launch, this call takes the literal " " — a single space — for sessionId. It is an issuance call, not a session handoff. The source material calls this "an empty string" and then writes it as " "; pass the single space exactly as documented.

TBD Whether a truly empty string "" is also accepted is not documented. Confirm with Cheggout before changing it. See Session and SSO for where a real sessionId belongs.

Code

CHEGNetworkCallHelper.Companion.getScratchCardDetails(
triggerEventType = "UPI",
amount = 499.00,
extTransactionId = "PUB_TXN_20260731_000117",
dateandtime = "31072026141530",
virtualId = "pub_8f14e45fceea167a",
sessionId = " ",
subTriggerEventType = "",
merchantVPA = "merchant@examplebank",
object : CHEGScratchCardCallBack {
override fun onResponse(responseString: String?) {
// responseString carries status, banner, deepLink and popup fields.
// Parse it, show the banner, and launch the SDK with the deep link on tap.
}
}
)

Response

{
"message": "Success",
"status": true,
"banner": "https://cdn.example.com/scratch-card-banner.png",
"deepLink": "https://click.cheggout.com?type=reward&scratchCardId=1",
"isPopup": true,
"popupBanner": "https://cdn.example.com/scratch-card-popup.png",
"popupDeepLink": "https://click.cheggout.com?type=reward&scratchCardId=5"
}
FieldMeaning
statusWhether a card was issued
bannerCreative to display inline in your app
deepLinkLaunch this in the SDK to open the card
isPopupWhether Cheggout also wants a modal presentation
popupBannerCreative for the modal
popupDeepLinkDeep link for the modal's card

When isPopup is true you have been given two presentations to render — an inline banner and a modal — each with its own deep link. Respect the flag rather than always showing one or the other.

Launching the card

Both issuance paths hand you a deepLink. Pass it to the SDK launch method in the payload's DeeplinkInfo slot.

val payload = "{'Component':'CHEGGOUT'," +
"'IsEmployee':'0'," +
"'Language':'EN'," +
"'DeeplinkInfo':'$deepLink'," +
"'customerId':''}"

CheggoutApplication.launchCheggout(
this,
virtualId,
sessionId,
payload,
activityContext,
channelName
)
An invalid identity produces a white screen, not an error

An invalid userID or sessionInfo prevents the SDK from proceeding past the claimer page, resulting in a blank page rather than a message. If you see a white SDK screen, check the identity values first.

Reveal notifications

When the user scratches a card inside the SDK, the SDK tells your app what was revealed. Use this to update your own store, refresh a rewards badge, or trigger your own analytics.

class ShopActivity : AppCompatActivity(), CHEGscratchRevealCallBack {

override fun onReveal(onRevealData: String?) {
// onRevealData carries the revealed scratch card details.
// Persist it, then refresh any rewards UI you own.
Log.d("Cheggout", "onReveal: $onRevealData")
}
}

Implement CHEGscratchRevealCallBack in the Activity that launches the SDK and override onReveal().

TBD The reveal callback payload schema is not documented. Both callbacks are described as delivering "the scratch card details" without a field list, and the iOS notification name is product-specific in a way that suggests it may change. What is missing: the exact JSON schema of onRevealData and scDetails, and whether a miss (BETTER LUCK NEXT TIME) is delivered through the same callback. Parse defensively and confirm during UAT. Tracked in Open Items.

Tracking

Inside the SDK, impression and click tracking for the card itself is handled by the SDK. If you render the returned banner in your own UI, you are showing a Cheggout creative in a publisher surface and the advertisement tracking contract applies to it.

Checklist

  • Issuance happens server-side, after transaction validation, wherever possible.
  • virtualId and extTransactionId are derived server-side, never taken from the client.
  • status: false renders nothing and is not treated as an error.
  • Unsigned failure bodies are handled on the server path.
  • isPopup is respected rather than ignored.
  • The reveal callback is implemented and persists what it receives.
  • Retries reuse the original extTransactionId.

Next