Skip to main content

Coupon status webhook

This contract runs in the opposite direction: you host the endpoint, and Cheggout calls it when a coupon that was already delivered becomes invalid before its expected validity.

TBD Availability is not confirmed. The contract is published, but whether the webhook is actively delivered for your channel — and the operational details below — must be confirmed with Cheggout before you rely on it. Tracked in Open Items.

Why it exists

A coupon can stop being honourable after you have handed it to a customer — a brand withdraws the campaign, stock turns out to be short, or a technical issue is rolled back. The webhook lets you mark it expired in your "My Coupons" view and decide whether to refund the coins, rather than letting a customer discover the failure at the till.

The endpoint you build

POST https://<your-domain>/cheggout/webhook/coupon-status

The path shown is the documented convention. Confirm the exact URL with Cheggout during onboarding and register it with them.

Authentication

The documented control is IP whitelisting of Cheggout's outbound addresses.

TBD There is no request signature, and the published contract describes IP whitelisting as recommended rather than required. Cheggout's outbound IP list is also not published.

Treat inbound calls as untrusted until you can verify them

Without a signature, an unauthenticated caller who knows your URL can assert that a coupon was invalidated. Mitigate on your side:

  • Restrict the endpoint to Cheggout's IP ranges at your edge, once you have them.
  • Treat the call as a trigger to verify, not as authority. Confirm against getUserCoupons before taking an irreversible action such as a refund.
  • Never expose the endpoint publicly without at least IP restriction.

Ask Cheggout for the outbound IP list and for signature support before going live.

Request from Cheggout

FieldTypeDescription
channelNamestringYour channel identifier
offerIdstringThe offer whose coupons are affected
eventTypestring"COUPON_INVALIDATED"
expiredDatestringWhen the invalidation takes effect, ISO 8601 with offset
reasonstringMachine-readable reason — see below
reasonMessagestringHuman-readable explanation
referenceIdstringCheggout's reference for this event

reason values

ValueMeaningTypical handling
BRAND_CALLED_OUTThe brand withdrew the offerMark expired, consider a refund
OUT_OF_STOCKStock could not be honouredMark expired, refund
TECHNICAL_GLITCHIssued in error, rolled backMark expired, refund
FRAUD_DETECTEDFraud controls triggeredMark expired, review the account
OFFER_TERMINATEDCampaign ended earlyMark expired, consider a refund

Whether to refund coins is a business decision, not a platform one — Cheggout does not hold your coin balance.

Request body (synthetic)
{
"channelName": "YOURCHANNEL",
"offerId": "517",
"eventType": "COUPON_INVALIDATED",
"expiredDate": "2026-08-02T12:30:00+05:30",
"reason": "OUT_OF_STOCK",
"reasonMessage": "Brand inventory could not be fulfilled.",
"referenceId": "REPLACE_EVENT_REFERENCE"
}

Your response

{ "status": "OK" }

Return this once you have accepted the event. Acknowledge quickly and process asynchronously — long-running work inside the handler risks a timeout on Cheggout's side.

Significant gaps

These are limitations of the current contract that will shape your implementation.

The payload identifies the offer, not the coupon

There is no virtualId, no coupon_code and no extTransactionId in the body. You cannot tell which user's coupon was invalidated — only that an offer is affected.

In practice this means the event applies at offer granularity. If you must act on individual coupons, you have to look up every coupon you delivered for that offerId yourself, and decide whether all of them are affected. Confirm the intended semantics with Cheggout before implementing refunds off the back of it. TBD

Also unspecified:

GapImpact
No retry or backoff policyYou do not know whether a failed delivery will be re-attempted. Make your handler resilient and reconcile independently.
No signatureSee the authentication warning above.
referenceId semanticsWhether it is safe as a de-duplication key is unconfirmed — de-duplicate on it defensively anyway.
No eventType values beyond invalidationAssume more may be added; ignore unknown types rather than failing.

Implementation guidance

A robust handler:

  1. Verifies the source against Cheggout's IP range.
  2. Acknowledges immediately with {"status":"OK"} and queues the work.
  3. De-duplicates on referenceId so a repeat delivery is harmless.
  4. Ignores unknown eventType values rather than erroring.
  5. Verifies before refunding — cross-check with getUserCoupons rather than acting on the notification alone.
  6. Logs every event with its referenceId for reconciliation.

If you don't implement it

The webhook is optional. Without it you will not learn about invalidations proactively, and a customer may present a coupon that is no longer honoured. A periodic reconciliation job over getUserCoupons is a partial substitute.

Next