Skip to main content

API conventions

Patterns that repeat across Cheggout's APIs. Reading this once will save you debugging time later — several conventions here are genuinely surprising.

Transport

  • HTTPS only, in both environments.
  • JSON request and response bodies, UTF-8 encoded.
  • Content-Type: application/json on every request with a body.
  • Server-to-server calls originate from whitelisted IPs.

Status codes

This is the convention most likely to catch you out.

Deals Store responses carry the status inside the body, as a status field, in an HTTP-like style:

{
"status": 401,
"errorCode": "UNAUTHORIZED",
"message": "Invalid AppKey/SecKey."
}

Rewards Center business outcomes also arrive in the body, as a boolean:

{ "status": false, "message": "failure", "rewards": [] }
Always inspect the body

Do not branch on the HTTP status line alone. Parse the response and check the body's status field. A request that reached the platform and was answered — including with an error — may not be reflected in the transport status.

The practical rule:

1. Did the HTTP call complete? → transport-level failure if not
2. What does body.status say? → the real outcome
3. Is this a business "no" or a fault? → see below

"No" is not an error

Several normal outcomes look like failures if you treat them as exceptions.

ResponseMeaningHandle as
{"status": false, "message": "failure", "rewards": []}User not eligible right nowShow nothing. Not an error.
BETTER LUCK NEXT TIMENo reward allocated for this revealA valid reveal outcome. Show the "no luck" state.
403 NON_ELIGIBLETargeting rules exclude this userHide or disable the offer.
409 COUPON_EXHAUSTEDStock ran outShow "sold out".
429 MAX_LIMIT_REACHEDPer-user redemption limit hitShow the limit message.

None of these should trigger a retry, an alert, or a token refresh. A campaign with frequency caps will legitimately return "no" most of the time.

Error shapes

Error bodies are not uniform across product lines. Write a tolerant parser.

Signed APIs — failure:

{ "STATUS": "FAILURE", "ERRORSTRING": "Signature Mismatch!" }

Note the uppercase keys, and that this body carries no SIGN — signature verification must be skipped for it.

Rewards Center — business failure:

{ "status": false, "message": "failure", "rewards": [] }

Rewards Center reveal — business failure (inside the BDATA payload):

{ "status": false, "message": "REWARD NOT FOUND" }

Deals Store — error:

{ "status": 404, "errorCode": "INVALID_OFFER", "message": "Offer not found or inactive." }

A defensive parser checks, in order: an uppercase STATUS/ERRORSTRING pair, then a numeric or boolean status with errorCode/message, then the success shape.

The full catalogue is on Error codes.

TBD Error coverage is uneven. The Deals Store publishes a proper error table; the Rewards Center and Bank APIs document only a few failure strings. Treat any undocumented non-success body as a generic failure, log it with the endpoint and your extTransactionId, and report it so it can be added.

The signed envelope

Signed APIs wrap both request and response:

{ "CHANNELID": "...", "SIGN": "...", "BDATA": "<base64 payload>" }

The business payload is inside BDATA. Endpoint pages document the payload fields, not the envelope. Full construction rules: The signed envelope.

BDATA alone is not security

One endpoint — FetchRewardInfo — uses the BDATA wrapper without a SIGN. There, Base64 is an encoding layer, not a signature; the authentication is the bearer token. Do not assume a BDATA field implies a signed request.

Field naming

Naming is not consistent across product lines, and several payloads match keys case-sensitively.

ConceptAppears as
Your channelCHANNELID, X-CHANNELID, channelName, bName
The uservirtualId; userID as the iOS SDK launch parameter
Your referenceextTransactionId
The cardrewardId, scratchcardId

Two rules follow:

  1. Use the exact key the endpoint page documents. getSecuredReferenceToken reads bName; GetAuthToken reads channelName. Sending the wrong one silently omits the value.
  2. Do not assume a field is echoed back under the same name. rewardId is a number in GetReward responses and is sent as a string to FetchRewardInfo.

Idempotency

extTransactionId is your idempotency key on any call that can issue a reward or coupon.

RuleDetail
UniquenessGlobally unique per event. Never reuse.
FormatAlphanumeric, up to 256 characters
RetryReplay the same extTransactionId after a network failure
NeverReuse one ID across different offers or different events

Rewards Center — replaying an extTransactionId returns the same set of cards rather than creating new ones. After a card has been scratched, the response returns unscratched cards first, then scratched ones carrying full reward detail.

Deals Store — replaying returns the previously processed result, or is rejected as a duplicate.

TBD Idempotency has documented edge cases. The exact behaviour for a duplicate on the Deals Store is ambiguous in the source contract, and replay behaviour after certain reward types or expiries is not fully specified. Keep your own ledger of what you requested and what you received, and reconcile on extTransactionId — do not rely on the platform's idempotency as your only protection against double-issuance. See Security best practices.

Dates and times

FieldDocumented format
dateandtime (GetReward)DDMMYYYYHHMMSS
transDateAndTime (GetScratchCardForBank)YYYY-MM-DD HH:mm:ss
createdDateTime, endDate (responses)YYYY-MM-DD HH:mm:ss.SSS
offer_validity, coupon_validityISO 8601 date
expiredDate (webhook)ISO 8601 with offset

TBD Time zones are not specified on most fields, and expireDate on token responses has no documented format at all. Do not parse expireDate as a contract — drive token refresh from authentication failures instead. See Tokens.

Amounts

  • Transaction amounts in reward APIs are decimal values, two decimal places.
  • Deep payment amounts are in paisa"amount": "54000" means ₹540.00. See Deep payment.
  • Coin costs in the deals catalogue are numeric, where 0 means a free offer.

Pagination

Only GetAllScratchCardsByUserId documents pagination, via page and limit query parameters. It is 1-based and returns a bare array with no total count — detect the end by receiving fewer items than limit.

TBD Default and maximum limit, and pagination for catalogue endpoints, are not documented.

Rate limits

TBD No rate limits, quotas or throttling behaviour are published. Design defensively:

  • Cache what is cacheable — the catalogue especially.
  • Pre-fetch tokens rather than minting per request.
  • Back off exponentially on transport failures.
  • Agree expected peak volumes with Cheggout before launch.

Timeouts and retries

TBD No timeout or retry contract is published. Sensible defaults until one exists:

Call typeSuggested timeoutRetry
Token minting5sOnce, then fail
Reward creation5sOnce with the same extTransactionId
Reveal10sDo not blind-retry — reveal is one-shot; reconcile via history instead
Catalogue10sSafe to retry — read-only
Coupon delivery10sRetry with the same extTransactionId

The reveal rule matters: re-issuing a reveal after a timeout can leave you unable to recover the reward. Fetch the user's card list to find out what actually happened.

Versioning

TBD No API version policy is published. Paths are unversioned, and change notification happens through your Cheggout contact. See Versioning.

Next