Scratch Cards
A scratch card turns a completed action into a moment worth repeating. The user pays a bill, reads an article or finishes a transfer; a card appears; they scratch it; they get a coupon, some points, or a friendly miss. Cheggout supplies the campaign, the inventory, the eligibility rules and the reward. You supply the moment.
The problem it solves
Most transactions in a banking or content app are functional and forgettable. There is nothing to anticipate, so there is nothing to come back for. A scratch card inserts a small, cheap, variable-outcome reward at exactly the point where the user has already done what you wanted.
Three properties make it work commercially:
- It is post-action. Cost is only incurred after the behaviour you wanted has happened.
- It is variable. Not every card pays out, so the cost per engagement stays low while the anticipation stays high.
- It is targeted server-side. Eligibility, frequency caps, budget and probability all live in Cheggout's campaign configuration, so you change the economics without shipping an app release.
Business value
| Outcome | Mechanism |
|---|---|
| Higher transaction frequency | Users repeat the qualifying action to get another card |
| Higher engagement per session | An unscratched card is a reason to open the app |
| Measurable attribution | Every card carries impression and click tracking |
| No inventory risk for unopened cards | Rewards are assigned at reveal, not at issue |
| Campaign changes without a release | Targeting and payout rules are server-side configuration |
The two-phase model
This is the single most important thing to understand before reading any of the integration pages. Issuing a card and assigning its reward are two separate operations, at two separate moments.
Phase 1 creates temporary cards. They prove the user is eligible. No coupon is attached to them yet. The targeting parameters you send at this point — location, demographics, transaction context — are stored and applied later.
Phase 2 performs the actual reward assignment at the moment the user scratches. Cheggout calls this late binding, and its purpose is stated plainly in the source contract: it prevents inventory burn. If a million cards are issued and a hundred thousand are opened, only a hundred thousand pieces of inventory are consumed.
Three consequences fall out of this, and every integration must handle them:
- Reveal is one-shot. Once a card is revealed, re-revealing the same
rewardIdreturnsREWARD NOT FOUND— not the reward you got the first time. You must persist what you receive. - A miss is a normal outcome.
BETTER LUCK NEXT TIMEis a successful business response, not an error. Design the UI for it before you design the win state. - Issuance is idempotent, reveal is not. Replaying the same
extTransactionIdreturns the same set of cards. Replaying a reveal does not return the same reward.
Read Lifecycle for the full state machine.
Integration options by surface
There are three ways to put a scratch card in front of a user, plus a hosted listing page. They are not mutually exclusive — a bank commonly uses the SDK in-app and the headless API for its web channel.
| Path | You render | You call | Best when |
|---|---|---|---|
| Headless API | Everything | Rewards Center HTTP APIs | You need full design control, or you are not on a supported SDK surface |
| Mobile SDK | Nothing — the SDK does | One SDK method, or one signed server API | You have a native app and want the shortest path |
| Web widget | Nothing — the widget does | Two JavaScript functions | You are a website and want a drop-in overlay |
On mobile, there are two ways to issue a card: a client SDK call, or a signed
GetScratchCardForBank call from your backend after you have validated the order. Prefer the
server call. A client-initiated path allows issuance requests that are not tied to a verified
transaction. The reasoning and both code paths are on
SDK integration.
What you need before starting
| Prerequisite | Applies to | Where it comes from |
|---|---|---|
CHANNELID / channel name | All paths | Cheggout onboarding |
| RSA key pair, public certs exchanged | All paths | Key generation |
| Outbound IPs whitelisted | All server calls | Shared with Cheggout during onboarding |
A stable, immutable virtualId per user | All paths | Your own identity system |
A unique extTransactionId per event | All paths | Your own transaction system |
| At least one trigger event code | All paths | Agreed during campaign setup — see Trigger events |
| A campaign configured for your channel | All paths | Cheggout campaign operations |
| SDK artefact, or the widget script URL | SDK / web paths | Cheggout, per surface |
There is no console for creating campaigns, allocating inventory, or registering trigger-event codes. All of it is configured by Cheggout for your channel. Until a campaign exists and is active, every issuance call correctly returns "no rewards" — which looks identical to a broken integration. Confirm your campaign is live in UAT before debugging your code.
What Cheggout decides, and what you decide
| Decision | Owner |
|---|---|
| Whether this user gets a card at all | Cheggout |
| How many cards per event | Cheggout |
| Which reward is behind the card | Cheggout, at reveal |
| Frequency caps, budget, probability | Cheggout |
| When the qualifying event fires | You |
| What the card looks like, in headless mode | You |
| Where revealed rewards are stored and re-displayed | You |
| When impression and click are fired | You |
Next
- Lifecycle — the full state machine, expiry, idempotency and the one-shot reveal.
- Trigger events — the codes that connect your event to a campaign.
- Tracking — the impression and click contract you must implement.
- Headless integration, SDK integration, Web integration — pick your path.