Skip to main content

My Coupons

Where users find what they bought. This screen is yours to build, and your own store should be the primary source for it.

Your store is the source of truth

You persist every coupon at delivery time. Render "My Coupons" from that store, not from a live Cheggout call:

  • It is faster. No round trip on a screen users open often.
  • It works offline, or when Cheggout is briefly unavailable.
  • It is complete. getUserCoupons is scoped to a single offer, so building a full list from it means one call per offer the user has ever bought.

Use the Cheggout endpoint for reconciliation and recovery, not for rendering.

What to show

For each coupon:

ElementSource
Brand and product nameYour catalogue cache
Coupon code, prominentlyYour store, from delivery
A copy action
Validitycoupon_validity from delivery
Redemption instructionshow_to_redeem from your catalogue cache
Termstnc from your catalogue cache
Redeem actionThe url from delivery

Sort unexpired coupons first, then expired. Users open this screen to use something, not to browse history.

Reconciliation

Run a scheduled job over any delivery your ledger recorded as uncertain — a timeout, an INTERNAL_ERROR, an ambiguous retry.

The match is exact because extTransactionId is echoed on every returned coupon. That is the whole reason to use your real reference rather than a random value.

getUserCoupons response (synthetic)
{
"status": 200,
"message": "Fetched Successfully",
"data": {
"id": "517",
"brand_name": "Example Brand",
"product_name": "Sample Product Voucher",
"offer_validity": "2026-12-31T16:34:00.000Z",
"tnc": "One redemption per customer.",
"how_to_redeem": "Present the code at checkout.",
"url": "https://click.cheggout.com/REPLACE",
"coupons": [
{
"coupon_code": "REPLACE-COUPON-CODE",
"extTransactionId": "PUB_OFFERBUY_20260731_000045",
"purchase_time": "2026-07-31T14:15:31.000Z"
}
]
}
}
Coupons carry no status

Each entry has a code, your reference and a timestamp — no per-coupon expiry, no used/unused flag, no invalidation state. Validity comes from the offer's offer_validity. If you need redemption state, track it yourself. TBD

Invalidation

A coupon can stop being honourable after you have given it to a customer — a brand withdraws the campaign, stock turns out to be short, or an issue is rolled back. Cheggout can notify you through a webhook you host.

Reason codes: BRAND_CALLED_OUT, OUT_OF_STOCK, TECHNICAL_GLITCH, FRAUD_DETECTED, OFFER_TERMINATED. Whether to refund coins is your business decision — Cheggout does not hold your coin balance.

Significant limitations

The webhook payload identifies the offer, not the coupon or the user — there is no virtualId, coupon_code or extTransactionId in it. You cannot tell whose coupon was invalidated, only that an offer is affected.

It also has no signature, and no published retry policy. Verify before acting: cross-check with getUserCoupons rather than issuing refunds off the notification alone. TBD — see Open items.

If you do not implement the webhook, a periodic reconciliation job over getUserCoupons is a partial substitute — it will not tell you why something changed, but it will keep your store aligned.

Handling an invalid coupon well

The worst outcome is a customer at a till with a code that does not work. In order of preference:

  1. Mark it expired in your UI as soon as you learn, with a clear explanation.
  2. Refund the coins if your policy allows, and tell the user you have.
  3. Notify proactively rather than letting them discover it.
  4. Log it against the referenceId so support can explain what happened.

Next