Public Feeds
Public Campaign Feeds provide JSON feeds of available campaigns for your organization. These feeds are designed for mass user access via CloudFront CDN and can be embedded directly in your web or mobile applications.
Overview
CloudFront Distribution: Fast global access with edge caching
JSON Format: Easy to parse and integrate
Time-based Filtering: View past, current, or future campaigns
Tag Filtering: Filter campaigns by tags
Public Access: No authentication required
Auto-refresh: Feeds update automatically when campaigns change
Feed Types
Current Campaigns
Get all currently active campaigns.
URL: https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/current.json
Returns campaigns where startDate <= now <= endDate.
Upcoming Campaigns
Get future campaigns that haven't started yet.
URL: https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/upcoming.json
Returns campaigns where startDate > now.
Past Campaigns
Get campaigns that have ended.
URL: https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/past.json
Returns campaigns where endDate < now.
All Campaigns
Get all published campaigns (past, current, and future).
URL: https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/all.json
Returns all campaigns with status: 'published'.
Query Parameters
All feeds support the following optional parameters:
tags
string
Comma-separated list of tags to filter by
?tags=featured,seasonal
includeUnpublished
boolean
Include draft/unpublished campaigns (requires config)
?includeUnpublished=true
limit
number
Max campaigns to return (default: 100)
?limit=50
Tag Filtering
Tag filtering uses OR logic - campaigns matching ANY of the specified tags will be included.
Examples:
# Featured campaigns only
/campaigns/current.json?tags=featured
# Featured OR seasonal campaigns
/campaigns/current.json?tags=featured,seasonal
# VIP campaigns in the past
/campaigns/past.json?tags=vipResponse Format
{
"orgId": "550e8400-e29b-41d4-a716-446655440000",
"feedType": "current",
"generatedAt": "2025-10-06T15:00:00Z",
"cacheExpiresAt": "2025-10-06T15:15:00Z",
"filters": {
"tags": ["featured"],
"includeUnpublished": false
},
"campaigns": [
{
"campaignId": "camp_abc123",
"name": "Weekend Bonus Points",
"description": "Earn double points on all activities this weekend!",
"type": "points_multiplier",
"status": "active",
"startDate": "2025-10-05T00:00:00Z",
"endDate": "2025-10-07T23:59:59Z",
"tags": ["featured", "weekend"],
"triggers": [
{
"eventType": "user.activity",
"conditions": []
}
],
"effects": [
{
"type": "add_points",
"config": {
"amount": 100,
"multiplier": 2,
"reason": "Weekend Bonus"
}
}
],
"metadata": {
"imageUrl": "https://cdn.monterosa.cloud/campaigns/weekend-bonus.jpg",
"bannerColor": "#FF6B35",
"priority": 1
},
"segmentIds": [],
"createdAt": "2025-10-01T10:00:00Z",
"updatedAt": "2025-10-05T09:00:00Z"
}
],
"count": 1,
"hasMore": false
}Field Descriptions
Campaign Fields
campaignId
string
Unique campaign identifier
name
string
Campaign display name
description
string
Campaign description
type
string
Campaign type (e.g., points_multiplier, streak_bonus)
status
string
Campaign status (active, scheduled, completed)
startDate
string
When campaign starts (ISO 8601)
endDate
string
When campaign ends (ISO 8601)
tags
array
Tags for filtering and categorization
triggers
array
Event triggers that activate the campaign
effects
array
Rewards and actions when triggered
metadata
object
Custom display properties (images, colors, etc.)
segmentIds
array
User segments this campaign applies to
Integration Examples
JavaScript / React
async function fetchCurrentCampaigns(orgId, tags = []) {
const url = new URL(`https://cdn.monterosa.cloud/loyalty/${orgId}/campaigns/current.json`);
if (tags.length > 0) {
url.searchParams.set('tags', tags.join(','));
}
const response = await fetch(url);
const data = await response.json();
return data.campaigns;
}
// Usage
const campaigns = await fetchCurrentCampaigns('your-org-id', ['featured']);
// Display in React
function CampaignList() {
const [campaigns, setCampaigns] = useState([]);
useEffect(() => {
fetchCurrentCampaigns('your-org-id')
.then(setCampaigns);
}, []);
return (
<div>
{campaigns.map(campaign => (
<div key={campaign.campaignId}>
<h3>{campaign.name}</h3>
<p>{campaign.description}</p>
<span>Ends: {new Date(campaign.endDate).toLocaleDateString()}</span>
</div>
))}
</div>
);
}Swift / iOS
struct Campaign: Codable {
let campaignId: String
let name: String
let description: String
let startDate: String
let endDate: String
let tags: [String]
}
struct CampaignFeed: Codable {
let orgId: String
let campaigns: [Campaign]
let count: Int
}
func fetchCampaigns(orgId: String, tags: [String] = []) async throws -> [Campaign] {
var components = URLComponents(string: "https://cdn.monterosa.cloud/loyalty/\(orgId)/campaigns/current.json")!
if !tags.isEmpty {
components.queryItems = [
URLQueryItem(name: "tags", value: tags.joined(separator: ","))
]
}
let (data, _) = try await URLSession.shared.data(from: components.url!)
let feed = try JSONDecoder().decode(CampaignFeed.self, from: data)
return feed.campaigns
}Kotlin / Android
data class Campaign(
val campaignId: String,
val name: String,
val description: String,
val startDate: String,
val endDate: String,
val tags: List<String>
)
data class CampaignFeed(
val orgId: String,
val campaigns: List<Campaign>,
val count: Int
)
suspend fun fetchCampaigns(orgId: String, tags: List<String> = emptyList()): List<Campaign> {
val url = buildString {
append("https://cdn.monterosa.cloud/loyalty/$orgId/campaigns/current.json")
if (tags.isNotEmpty()) {
append("?tags=")
append(tags.joinToString(","))
}
}
val response = httpClient.get(url)
val feed = response.body<CampaignFeed>()
return feed.campaigns
}Caching
CloudFront Cache Behavior
Cache Duration: 15 minutes (configurable)
Cache Key: URL + query parameters
Invalidation: Automatic on campaign publish/update
Client-Side Caching
The cacheExpiresAt field indicates when the client should refresh:
const CACHE_KEY = 'loyalty_campaigns';
async function getCachedCampaigns(orgId) {
const cached = localStorage.getItem(CACHE_KEY);
if (cached) {
const data = JSON.parse(cached);
// Check if cache is still valid
if (new Date(data.cacheExpiresAt) > new Date()) {
return data.campaigns;
}
}
// Fetch fresh data
const response = await fetch(`https://cdn.monterosa.cloud/loyalty/${orgId}/campaigns/current.json`);
const data = await response.json();
// Store in cache
localStorage.setItem(CACHE_KEY, JSON.stringify(data));
return data.campaigns;
}Unpublished Campaigns
By default, only campaigns with status: 'published' are included in feeds. To include draft/unpublished campaigns, set includeUnpublished=true.
⚠️ Important: This feature must be enabled in your organization settings. Contact support to enable.
/campaigns/all.json?includeUnpublished=trueWhen enabled, campaigns with any status will be included, allowing you to preview upcoming campaigns before publishing.
CORS Configuration
All feeds include CORS headers for cross-origin access:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD
Access-Control-Max-Age: 3600This allows feeds to be loaded from any domain.
Best Practices
Performance
Cache aggressively: Use the provided
cacheExpiresAttimestampImplement ETags: Check
ETagheader to avoid unnecessary transfersUse CDN: Always use the CloudFront URL, not the origin API
Display
Show end dates: Display campaign end dates prominently
Filter by relevance: Use tags to show relevant campaigns to users
Sort by priority: Use
metadata.priorityfor display orderHandle images: Load campaign images from
metadata.imageUrl
Error Handling
async function fetchCampaignsWithFallback(orgId) {
try {
const response = await fetch(`https://cdn.monterosa.cloud/loyalty/${orgId}/campaigns/current.json`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Failed to fetch campaigns:', error);
// Return cached data as fallback
const cached = localStorage.getItem('loyalty_campaigns_fallback');
return cached ? JSON.parse(cached) : { campaigns: [] };
}
}Feed URLs Reference
Replace {orgId} with your organization ID:
# Current campaigns
https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/current.json
# Upcoming campaigns
https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/upcoming.json
# Past campaigns
https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/past.json
# All campaigns
https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/all.json
# With tag filtering
https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/current.json?tags=featured,vip
# With unpublished campaigns (if enabled)
https://cdn.monterosa.cloud/loyalty/{orgId}/campaigns/all.json?includeUnpublished=trueMonitoring
Track feed usage in your analytics:
// Google Analytics example
async function fetchAndTrackCampaigns(orgId) {
const start = Date.now();
try {
const data = await fetch(`https://cdn.monterosa.cloud/loyalty/${orgId}/campaigns/current.json`).then(r => r.json());
// Track successful load
gtag('event', 'campaign_feed_loaded', {
feed_type: 'current',
campaign_count: data.count,
load_time: Date.now() - start
});
return data.campaigns;
} catch (error) {
// Track errors
gtag('event', 'campaign_feed_error', {
error_type: error.message
});
throw error;
}
}Troubleshooting
Feed not updating
Wait up to 15 minutes for CDN cache to expire
Check if campaign was actually published
Verify campaign dates are correct
CORS errors
Ensure you're using the CDN URL, not the API origin
Check browser console for specific CORS error
Verify your domain is allowlisted (if using restricted CORS)
Missing campaigns
Check campaign
statusis'published'Verify campaign dates match the feed type (current/upcoming/past)
Check if tags filter is too restrictive
Slow loads
Implement client-side caching
Use CDN edge locations closest to users
Consider using a service worker for offline support
Last updated

