Catalogue & inventory
The catalogue is the offer list your storefront renders. Inventory is how much of each offer is left. They have very different freshness requirements, and treating them the same is the most common performance mistake in this module.
Two endpoints, two lifetimes
getCatalogue | getCatalogueInventory | |
|---|---|---|
| Contains | Offer content, pricing, imagery, terms | Remaining stock per offer |
| User-specific | No | No |
| Freshness | Hours | 180 seconds |
| Call it | On a schedule | Before showing a buy action |
| Cache | Aggressively | For the returned ttlSeconds |
Caching the catalogue
Because the catalogue is identical for every user, calling it on a page view wastes a round trip on data you already have.
Refresh on a schedule into your own store. Hourly suits a fast-moving campaign calendar; nightly is fine if your offers change rarely. Match it to how often your campaigns actually change.
Store the whole offer object — imagery URLs, terms, redemption steps, everything. Your storefront should render an offer page without any further Cheggout call.
Serve reads from your cache, including search, filtering and category browsing. Those are your features, built on your copy of the data.
Handle disappearing offers. An offer can be withdrawn between refreshes. If
fetchCouponCode returns 404 INVALID_OFFER, treat
it as "no longer available", refund the coins, and trigger a catalogue refresh.
TBD No recommended refresh cadence is published, and there is no change feed or ETag to detect updates cheaply. Agree a cadence with Cheggout based on your campaign velocity.
Offer fields
The fields you will actually build a storefront on:
| Field | Use it for |
|---|---|
id | The offer identifier. Pass as offerId everywhere else. |
brand_name, brand_description | Brand attribution |
product_name | The offer title |
brand_logo, grey_brand_logo | Brand mark. Use the grey variant for sold-out or disabled states. |
product_min_pic, product_pic_large | Listing and detail imagery |
offer_category, offer_category_name | Your category navigation |
amount | Coin cost. 0 means free — surface these prominently. |
is_free | Free-offer indicator |
purchase_limit | How many times one user may claim. Show it, and enforce it optimistically. |
dealRank | Cheggout's suggested ordering. A sensible default sort. |
stock | Approximate. Not authoritative — see below. |
strip_note | Short promotional strip |
tnc, how_to_redeem | Terms and redemption instructions |
offer_validity | When the offer expires |
tags | Targeting — see below |
CPE | Cost per engagement |
Full field reference: getCatalogue.
stock in the catalogue is stale by designIt is a cached value carried for convenience. Never gate a purchase on it — use
getCatalogueInventory, which is current within
180 seconds.
Checking inventory
Call inventory when the user is close to buying — opening an offer detail page is the natural
moment — and cache the response for the ttlSeconds it returns.
{
"status": 200,
"ttlSeconds": 180,
"data": [
{ "offerId": "517", "couponsLeft": 124 },
{ "offerId": "518", "couponsLeft": 0 }
],
"message": "REPLACE_STATUS_MESSAGE"
}
A workable presentation policy:
couponsLeft | Show |
|---|---|
0 | "Sold out", buy action disabled, grey brand logo |
| Below your own threshold | "Limited stock", buy action enabled |
| Otherwise | Normal |
A non-zero count reserves nothing. Stock can be exhausted between your check and your delivery call,
which then returns 409 COUPON_EXHAUSTED. Handle that at delivery time — and if you have already
burned coins, refund them. See Coupon delivery.
TBD Inventory may include offer identifiers absent from your catalogue response.
Treat the catalogue as the authority on what to show, join on offerId, and ignore entries you do
not recognise.
Targeting with tags
Each offer carries tags — targeting labels. Applying them is your responsibility. Cheggout
supplies the labels; you decide which users see which offers, using the segments you already hold.
A typical implementation:
- Compute a tag set for each user from your own profile data.
- Filter cached offers to those whose
tagsintersect the user's set. - Fall back to untagged or broadly-tagged offers so no user sees an empty store.
TBD No tag taxonomy is published — no list of valid tags, no semantics, no documented mapping from user attributes to tags. Agree your vocabulary with Cheggout during campaign setup.
A user may see an offer you showed them and still be refused with 403 NON_ELIGIBLE. Your tag
filtering is a UX optimisation, not the enforcement point. Handle the refusal gracefully and refund.
Performance
The whole point of caching here is that the store opens instantly.
- Pre-fetch the catalogue into your cache before the user asks for it.
- Warm inventory for the offers on the first screen, so a tap into a detail page is instant.
- Serve imagery from your CDN if you can, rather than hot-linking on every render.
- Never block the storefront on a Cheggout call — render from cache and reconcile in the background.
Next
- Coupon delivery — the purchase flow.
getCatalogue·getCatalogueInventory