Appearance
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
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/public/offers | List 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/offersQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
per_page | integer | 20 | Number of items per page (1-50) |
page | integer | 1 | Page number |
type | string | - | Filter by offer type |
Offer Types
| Type | Description |
|---|---|
percentage | Percentage discount (e.g., 10% off) |
fixed | Fixed amount discount (e.g., $5 off) |
bogo | Buy-one-get-one offers |
Validity Rules
Only offers meeting ALL conditions are returned:
- Status is
active - Current time >=
valid_from(if set) - Current time <
valid_until(if set) 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)
| Field | Type | Description |
|---|---|---|
id | string | Unique offer identifier (hashkey) |
name | string | Offer name |
description | string | Offer description |
type | string | Offer type (percentage, fixed, bogo) |
discount | object | Formatted discount information |
valid_from | string|null | Start date (ISO 8601) or null for no start date |
valid_until | string|null | End date (ISO 8601) or null for ongoing |
Discount Object by Type
Percentage Discount
json
{
"type": "percentage",
"value": 10,
"display": "10% off"
}| Field | Type | Description |
|---|---|---|
type | string | Always "percentage" |
value | number | Percentage value (e.g., 10 for 10%) |
display | string | Formatted display string |
Fixed Discount
json
{
"type": "fixed",
"value": 5.00,
"display": "$5.00 off"
}| Field | Type | Description |
|---|---|---|
type | string | Always "fixed" |
value | number | Dollar amount |
display | string | Formatted display string |
BOGO Discount
json
{
"type": "bogo",
"buy": 2,
"get": 1,
"display": "Buy 2 Get 1 Free"
}| Field | Type | Description |
|---|---|---|
type | string | Always "bogo" |
buy | integer | Quantity to purchase |
get | integer | Quantity received free |
display | string | Formatted display string |
Sort Order
Results are sorted by:
- Offers expiring soonest first (
valid_untilascending, nulls last) - Most recently created (
created_atdescending)
Caching
| Cache | TTL |
|---|---|
| Browser (max-age) | 0 seconds |
| CDN | 24 hours (invalidated on publish) |
| Stale-while-revalidate | 30 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
| Parameter | Type | Description |
|---|---|---|
id | string | The 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:
| Field | Type | Description |
|---|---|---|
configuration | object | Offer configuration (sanitized) |
terms | string | Terms and conditions text |
Configuration Object
The configuration varies by offer type. Common fields include:
| Field | Type | Description |
|---|---|---|
percentage | number | Percentage for percentage offers |
amount | number | Dollar amount for fixed offers |
buy_quantity | integer | Buy quantity for BOGO |
get_quantity | integer | Get quantity for BOGO |
minimum_purchase | number | Minimum purchase required |
maximum_discount | number | Maximum discount cap |
eligible_categories | array | Categories offer applies to |
exclude_sale_items | boolean | Whether sale items are excluded |
Sanitized Configuration
Internal fields like internal_notes, cost_center, and budget_code are removed from the public response.
Caching
| Cache | TTL |
|---|---|
| Browser (max-age) | 0 seconds |
| CDN | 24 hours (invalidated on publish) |
| Stale-while-revalidate | 30 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
| Date | Change |
|---|---|
| 2026-02-23 | Updated for CloudFront CDN delivery. |
| 2026-01-28 | Expanded documentation. |
| 2026-01-15 | Initial publication. |