Skip to content

Offers API

The Offers API provides access to active promotional offers including percentage discounts, fixed amount discounts, and buy-one-get-one (BOGO) deals.

Do Not Cache Locally

Offers have time-sensitive validity rules (expiration dates, usage limits). The CDN always serves fresh data and is automatically invalidated when offers change, but you should not cache offer data in your application for extended periods.

Endpoints

MethodEndpointDescription
GET/api/v1/public/offersList active offers
GET/api/v1/public/offers/{id}Get offer details

List Offers

Retrieve a paginated list of currently active and valid offers.

http
GET /api/v1/public/offers

Query Parameters

ParameterTypeDefaultDescription
per_pageinteger20Number of items per page (1-50)
pageinteger1Page number
typestring-Filter by offer type

Offer Types

TypeDescription
percentagePercentage discount (e.g., 10% off)
fixedFixed amount discount (e.g., $5 off)
bogoBuy-one-get-one offers

Validity Rules

Only offers meeting ALL conditions are returned:

  1. Status is active
  2. Current time >= valid_from (if set)
  3. Current time < valid_until (if set)
  4. usage_count < usage_limit (if limit set)

Example Request

javascript
const response = await fetch(
  'https://cdn.engagehq.retailsuccessplatform.com/api/v1/public/offers?type=percentage',
  {
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  }
);

Response

json
{
  "success": true,
  "message": "Offers retrieved",
  "data": [
    {
      "id": "ofr_00000p1Q2r3S4t5",
      "name": "Summer Savings",
      "description": "10% off all summer essentials",
      "type": "percentage",
      "discount": {
        "type": "percentage",
        "value": 10,
        "display": "10% off"
      },
      "valid_from": "2024-06-01T00:00:00+00:00",
      "valid_until": "2024-08-31T23:59:59+00:00"
    },
    {
      "id": "ofr_00000x1Y2z3A4b5",
      "name": "Weekly Special",
      "description": "$5 off your purchase of $25 or more",
      "type": "fixed",
      "discount": {
        "type": "fixed",
        "value": 5,
        "display": "$5.00 off"
      },
      "valid_from": "2024-06-03T00:00:00+00:00",
      "valid_until": "2024-06-09T23:59:59+00:00"
    },
    {
      "id": "ofr_00000m1N2o3P4q5",
      "name": "Mix & Match",
      "description": "Buy 2 get 1 free on select items",
      "type": "bogo",
      "discount": {
        "type": "bogo",
        "buy": 2,
        "get": 1,
        "display": "Buy 2 Get 1 Free"
      },
      "valid_from": null,
      "valid_until": null
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 20,
    "total": 3
  }
}

Response Fields (List)

FieldTypeDescription
idstringUnique offer identifier (hashkey)
namestringOffer name
descriptionstringOffer description
typestringOffer type (percentage, fixed, bogo)
discountobjectFormatted discount information
valid_fromstring|nullStart date (ISO 8601) or null for no start date
valid_untilstring|nullEnd date (ISO 8601) or null for ongoing

Discount Object by Type

Percentage Discount

json
{
  "type": "percentage",
  "value": 10,
  "display": "10% off"
}
FieldTypeDescription
typestringAlways "percentage"
valuenumberPercentage value (e.g., 10 for 10%)
displaystringFormatted display string

Fixed Discount

json
{
  "type": "fixed",
  "value": 5.00,
  "display": "$5.00 off"
}
FieldTypeDescription
typestringAlways "fixed"
valuenumberDollar amount
displaystringFormatted display string

BOGO Discount

json
{
  "type": "bogo",
  "buy": 2,
  "get": 1,
  "display": "Buy 2 Get 1 Free"
}
FieldTypeDescription
typestringAlways "bogo"
buyintegerQuantity to purchase
getintegerQuantity received free
displaystringFormatted display string

Sort Order

Results are sorted by:

  1. Offers expiring soonest first (valid_until ascending, nulls last)
  2. Most recently created (created_at descending)

Caching

CacheTTL
Browser (max-age)0 seconds
CDN24 hours (invalidated on publish)
Stale-while-revalidate30 seconds

Do Not Cache Locally

Offers can become invalid at any time due to expiration or usage limits. Always fetch fresh data from the CDN when displaying offers.


Get Offer

Retrieve detailed information about a specific offer.

http
GET /api/v1/public/offers/{id}

Path Parameters

ParameterTypeDescription
idstringThe offer hashkey (e.g., ofr_00000p1Q2r3S4t5)

Example Request

javascript
const response = await fetch(
  'https://cdn.engagehq.retailsuccessplatform.com/api/v1/public/offers/ofr_00000p1Q2r3S4t5',
  {
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  }
);

Response

json
{
  "success": true,
  "message": "Offer retrieved",
  "data": {
    "id": "ofr_00000p1Q2r3S4t5",
    "name": "Summer Savings",
    "description": "10% off all summer essentials",
    "type": "percentage",
    "discount": {
      "type": "percentage",
      "value": 10,
      "display": "10% off"
    },
    "valid_from": "2024-06-01T00:00:00+00:00",
    "valid_until": "2024-08-31T23:59:59+00:00",
    "configuration": {
      "percentage": 10,
      "minimum_purchase": 25.00,
      "maximum_discount": 50.00,
      "eligible_categories": ["summer", "outdoor"],
      "exclude_sale_items": true
    },
    "terms": "Valid on regular-priced summer items only. Cannot be combined with other offers. Maximum discount $50."
  }
}

Additional Response Fields (Detail)

The detail response includes all list fields plus:

FieldTypeDescription
configurationobjectOffer configuration (sanitized)
termsstringTerms and conditions text

Configuration Object

The configuration varies by offer type. Common fields include:

FieldTypeDescription
percentagenumberPercentage for percentage offers
amountnumberDollar amount for fixed offers
buy_quantityintegerBuy quantity for BOGO
get_quantityintegerGet quantity for BOGO
minimum_purchasenumberMinimum purchase required
maximum_discountnumberMaximum discount cap
eligible_categoriesarrayCategories offer applies to
exclude_sale_itemsbooleanWhether sale items are excluded

Sanitized Configuration

Internal fields like internal_notes, cost_center, and budget_code are removed from the public response.

Caching

CacheTTL
Browser (max-age)0 seconds
CDN24 hours (invalidated on publish)
Stale-while-revalidate30 seconds

Error Responses

400 Bad Request

json
{
  "success": false,
  "message": "Organization context required",
  "errors": null
}

404 Not Found

json
{
  "success": false,
  "message": "Offer not found",
  "errors": null
}

The offer either:

  • Doesn't exist
  • Is not currently active
  • Has expired
  • Has reached its usage limit
  • Belongs to a different organization

Usage Example: Displaying Offers

javascript
async function displayOffers() {
  const response = await fetch('/api/v1/public/offers', {
    headers: { 'Authorization': `Bearer ${token}` }
  });

  const { data: offers } = await response.json();

  offers.forEach(offer => {
    console.log(`${offer.name}: ${offer.discount.display}`);

    if (offer.valid_until) {
      const expiresIn = new Date(offer.valid_until) - new Date();
      const daysLeft = Math.ceil(expiresIn / (1000 * 60 * 60 * 24));
      console.log(`  Expires in ${daysLeft} days`);
    }
  });
}

Changelog
DateChange
2026-02-23Updated for CloudFront CDN delivery.
2026-01-28Expanded documentation.
2026-01-15Initial publication.

EngageHQ Public Content Delivery API