Security best practices
Cheggout integrations issue things of monetary value. These practices are what separates a demo-quality integration from one you can run in production at a bank.
Credentials
Keys and secrets live on your backend. A private key or API secret in a mobile binary, a JavaScript bundle, or a repository is compromised — assume extraction and rotate.
| Credential | Where it belongs | Never |
|---|---|---|
| RSA private key | Secret manager, backend only | App package, JS, source control |
APP_KEY / SEC_KEY | Secret manager, backend only | Client of any kind |
| Reference token | Backend only | Any client — it is channel-wide |
| User token | Backend, or the client surface that needs it | Logs, URLs, analytics |
CHANNELID | Anywhere | — (identifier, not a secret) |
Separate credentials per environment, and make sure UAT credentials cannot reach production.
Request integrity
- Sign exactly what you send. Compute
BDATAonce, sign that string, transmit that string. - Verify Cheggout's response signature before acting on the payload.
- Treat a signature failure as fatal. Never fall back to trusting an unverified body.
TBD The envelope carries no nonce or timestamp today, so it does not itself prevent replay. Compensate with IP whitelisting, TLS, and idempotency keys — and do not build a flow whose safety depends on a request being unrepeatable.
Issue rewards from your server, not your client
This is the single most important design decision in a rewards integration.
If a client can ask for a scratch card directly, anyone who can call that endpoint can mint reward eligibility without transacting. Put the request behind your backend, and verify the underlying order or payment before asking Cheggout for a card.
Where a server-to-server variant of an endpoint exists, prefer it. The
GetScratchCardForBank flow exists specifically
so issuance originates from your backend after order validation.
Practical rules:
- Bind the reward request to a verified transaction you can prove happened.
- Derive
virtualIdfrom your authenticated session — never from a client-supplied parameter. - Make
extTransactionIdyour real transaction reference so it can be reconciled and disputed.
Identity and PII
virtualIdmust be pseudonymous — no email, mobile number, account number or name.- Never put
virtualIdor tokens in URLs you control. Query strings end up in access logs, referrer headers and analytics. - Keep the mapping from
virtualIdto your real customer on your side only. - Collect any additional personal data (a mobile number for a wallet link, for instance) directly with the customer's consent — do not route it through Cheggout unnecessarily.
Tokens
- Short-lived, refreshed on
401, never on a business failure. - Single-flight refresh to avoid stampedes.
- Never log them. Redact
Authorizationheaders in your logging pipeline. - Never place a channel-scoped reference token on a client.
Client-side surfaces
The web widget and mobile SDKs necessarily hold a user token in the browser or app. Accept the implications:
- Anything in
localStorageorsessionStorageis readable by every script on the page. Keep your page's third-party script surface tight. - A user token can act as that user. Keep lifetimes short.
- Do not put reward decisions in the client. The client renders what the server decided.
Idempotency and double-issuance
extTransactionIdmust be globally unique and never reused.- Read the idempotency guarantees — they hold in the common case but have documented exceptions. Do not rely on them as your only defence against double-issuance.
- Where money or inventory is involved, keep your own ledger of what you requested and what you received, and reconcile.
Coin-burn ordering
If you run your own points or coin economy with the Deals Store, the ordering is prescribed:
- Burn coins in your wallet, atomically.
- Request the coupon from Cheggout.
- On failure, either retry with the same
extTransactionIdor refund the coins.
Never deliver a coupon before the burn is committed, and never leave a burn without either a coupon or a refund.
Logging and monitoring
Log enough to debug, never enough to leak.
| Log | Don't log |
|---|---|
extTransactionId, rewardId, orderId | Tokens, signatures, keys |
| Endpoint, latency, status | Full request bodies containing coupon codes |
| Error codes and messages | virtualId in systems that also hold customer identity |
Alert on: signature failures (a spike means a key or config problem), authentication failures, and a sudden change in reward-issuance rate.
Incident response
If a key, secret or token is exposed:
- Contact Cheggout immediately via Support.
- Request rotation of the affected credential.
- Review issuance logs for the exposure window.
- Rotate anything that shared the exposure path.
Checklist
- Private key and API secrets in a secret manager, backend only
- Separate credentials per environment
- Response signatures verified; unsigned error bodies handled without crashing
- Reward requests originate from your backend after order verification
-
virtualIdderived from your authenticated session, never client input -
virtualIdcontains no PII -
extTransactionIdunique, persisted, reconcilable - Tokens refreshed on
401only, single-flight, never logged -
Authorizationredacted in logs - Alerting on signature and auth failure rates