Skip to main content

Error codes

Cheggout does not use one error format across all product lines. This page catalogues every documented failure and the shape it arrives in.

Start with API conventions for the parsing strategy.

The four response shapes

Write a parser that recognises all four before branching on the content.

ShapeExampleWhere
Signed-API failure{"STATUS":"FAILURE","ERRORSTRING":"..."}Rewards Center token APIs, Bank APIs
Rewards business result{"status":false,"message":"failure","rewards":[]}GetReward
Reveal business result{"status":false,"message":"REWARD NOT FOUND"}FetchRewardInfo, inside BDATA
Deals Store error{"status":404,"errorCode":"INVALID_OFFER","message":"..."}Deals Store
Status codes can live in the body

Deals Store responses carry the status as a status field in the JSON body. Always parse the body rather than branching only on the HTTP status line.

Not every "no" is an error

These are successful responses that happen to say no. They must not trigger retries, token refreshes or alerts.

ResponseMeaningHandle by
{"status": false, "rewards": []}User not eligible for a card right nowRendering nothing
BETTER LUCK NEXT TIMENo reward behind this cardShowing your "no luck" state
403 NON_ELIGIBLETargeting excludes this userHiding or disabling the offer
409 COUPON_EXHAUSTEDStock exhaustedShowing "sold out"
429 MAX_LIMIT_REACHEDPer-user limit reachedShowing the limit message
Empty array from reward historyUser has no cardsShowing an empty state

With frequency caps and probability-based campaigns, "no" will be the common answer. Design for it first.

Signed APIs

Applies to getSecuredReferenceToken, GetAuthToken, GenerateSessionInfoV2, GetScratchCardForBank.

ERRORSTRINGMeaningWhat to do
Signature Mismatch!The signature could not be verifiedCheck you signed the Base64 BDATA string, not the decoded JSON; check CHANNELID; check padding is PKCS#1 v1.5
Internal Error!Platform-side failureRetry with backoff. Escalate if persistent.
These bodies carry no signature

Check for the STATUS/ERRORSTRING shape before attempting signature verification, or your client will throw on a legitimate error.

Common causes of Signature Mismatch!, in the order worth checking:

  1. Signing the decoded JSON instead of the Base64 BDATA string.
  2. Re-serialising the payload after computing BDATA, so the signed bytes differ from the sent bytes.
  3. A wrong or mistyped CHANNELID, so Cheggout verifies with a different key.
  4. PSS padding instead of PKCS#1 v1.5.
  5. Using the wrong key pair for the environment.

Rewards Center

GetReward

ResponseMeaning
{"status": false, "message": "failure", "rewards": []}Not eligible — a normal outcome
HTTP 401Token missing, malformed, expired, or the wrong token type

A 401 here most often means a user token was sent where the reference token is required. See Tokens.

FetchRewardInfo

Failure messages arrive inside the decoded BDATA as {"status": false, "message": "..."}.

messageMeaningHandling
BETTER LUCK NEXT TIMENo reward allocated — inactive campaign, frequency cap, empty pool, probability miss, or exhausted budgetA normal outcome. Show the no-luck state.
REWARD NOT FOUNDNo card matches this rewardId for this user — including one already revealedLook it up in reward history
SCRATCHCARDID NOT FOUNDrewardId missing or not a valid numberFix the request
CHEGCUSTOMERID NOT FOUNDThe user could not be resolvedCheck the token matches the user
VIRTUALID NOT FOUNDvirtualId missing from the payloadFix the request
BANKNAME NOT FOUNDchannelName missing from the payloadFix the request
REWARD NOT FOUND after a timeout is ambiguous

It may mean the card never existed, or that your earlier reveal succeeded and you lost the response. Do not assume failure — check GetAllScratchCardsByUserId. If the card shows isSeen: true, the reveal happened and the reward is in that response.

GetAllScratchCardsByUserId

ResponseMeaning
HTTP 401Token missing, malformed, expired, or the wrong type
[]No cards — a normal outcome

Deals Store

The most complete error catalogue on the platform.

statuserrorCodeMessageEndpointsHandling
400INVALID_REQUESTAllFix the request. Refund coins if already burned.
401UNAUTHORIZEDInvalid AppKey/SecKey.AllFix credentials. Refund coins.
403FORBIDDENRequest blocked. IP not whitelisted.getCatalogueRegister your egress IPs
403NON_ELIGIBLEUser not eligible for this offer based on targeting rules.fetchCouponCodeRefund coins. Hide the offer.
404INVALID_OFFEROffer not found or inactive.fetchCouponCodeRefund coins. Refresh your catalogue cache.
409COUPON_EXHAUSTEDfetchCouponCodeRefund coins. Show "sold out".
429MAX_LIMIT_REACHEDMaximum redemption limit reached for this user.fetchCouponCodeRefund coins. Show the limit message.
500INTERNAL_ERRORSomething went wrong.AllRetry with the same extTransactionId, then refund
Every delivery failure needs a coin decision

Because coins are burned before fetchCouponCode is called, each failure leaves the user short. Retry safely or refund — there is no option that leaves the user whole without one of the two.

Note that 403 carries two different errorCode values depending on the endpoint, and 429 is a business limit rather than rate limiting. Branch on errorCode, not on status alone.

Handling strategy

Rules worth encoding once:

  • Retry only transport failures, with the same extTransactionId.
  • Never retry a business no. Re-minting a token or re-sending will not change the answer.
  • Never blind-retry a reveal. Reconcile through reward history instead.
  • Log unrecognised bodies with the endpoint and your extTransactionId, and report them.

Undocumented failures

TBD Error coverage is uneven. The Rewards Center and Bank APIs publish only a few strings, and there are no distinct codes for an unknown channel, an unwhitelisted IP, a malformed payload or a rate limit.

Treat any unrecognised non-success body as a generic failure: log it, fail the operation safely, and report it via Support so it can be added here. Closing this gap is a P0 item on Open items.

Next