Deals
Integrate Deals
This guide provides practical implementation patterns for integrating CashIn's Deals endpoints. These endpoints enable transparent friend relationship mapping while using intelligent ranking to resolve duplicate deals and maximize conversion probability.
Deals Endpoints
|
Endpoint |
Method |
Purpose |
Key Parameters |
Response Data |
|---|---|---|---|---|
|
GET |
Get friend deals by relationship degree |
|
|
Authentication Setup
All Deals endpoints require Bearer token authentication using your partner secret key.
const headers = {
'Authorization': 'Bearer sk_live_abc123def456...',
'Content-Type': 'application/json'
};
Integration Patterns
Pattern 1: Display All Available Deals
Show users all deals available through their friend network with intelligent ranking.
class DealsManager {
constructor(secretKey) {
this.secretKey = secretKey;
this.headers = {
'Authorization': `Bearer ${secretKey}`,
'Content-Type': 'application/json'
};
}
async getAllUserDeals(userId, options = {}) {
const queryParams = new URLSearchParams({
user_id: userId,
limit: options.limit || 20,
offset: options.offset || 0
});
if (options.include_purchased !== undefined) {
queryParams.append('include_purchased', options.include_purchased);
}
if (options.campaign_id) {
queryParams.append('campaign_id', options.campaign_id);
}
try {
const response = await fetch(`/partner/v1/campaigns/deals?${queryParams}`, {
method: 'GET',
headers: this.headers
});
const result = await response.json();
if (result.success) {
return {
success: true,
campaigns: result.data.campaigns,
totalCampaigns: result.data.total_campaigns,
totalFriendsSharing: result.data.total_friends_sharing
};
}
return { success: false, error: result.message };
} catch (error) {
console.error('Failed to fetch deals:', error);
return { success: false, error: 'Network error' };
}
}
renderAllDeals(dealsData) {
const container = document.getElementById('deals-container');
container.innerHTML = '';
if (!dealsData.campaigns || dealsData.campaigns.length === 0) {
container.innerHTML = '<p class="no-deals">No deals available from friends at this time.</p>';
return;
}
dealsData.campaigns.forEach(campaign => {
const campaignElement = this.createCampaignElement(campaign);
container.appendChild(campaignElement);
});
}
createCampaignElement(campaign) {
const element = document.createElement('div');
element.className = 'campaign-deal';
element.innerHTML = `
<div class="campaign-header">
<img src="${campaign.image_url}" alt="${campaign.campaign_display_name}" class="campaign-image">
<div class="campaign-info">
<h3>${campaign.campaign_display_name}</h3>
<p class="description">${campaign.description}</p>
<p class="expires">Expires: ${new Date(campaign.expires_at).toLocaleDateString()}</p>
<span class="friends-count">${campaign.friends_sharing_count} friends sharing</span>
</div>
</div>
<div class="best-recommendation">
<h4>🎯 Best Option</h4>
<div class="friend-option recommended">
<div class="friend-details">
<span class="friend-name">${campaign.best_friend_to_use.friend_name}</span>
<span class="relationship-degree">${campaign.best_friend_to_use.relationship_degree} degree</span>
<span class="influence-score">Influence: ${campaign.best_friend_to_use.influence_score}</span>
</div>
<a href="${campaign.best_friend_to_use.referral_url}" class="use-deal-btn primary">
Use This Deal
</a>
<small class="reason">${campaign.best_friend_to_use.reason}</small>
</div>
</div>
${this.renderAllFriendOptions(campaign)}
`;
return element;
}
renderAllFriendOptions(campaign) {
let html = '<div class="all-friends-section">';
html += '<button class="toggle-all-friends">View All Friends Sharing</button>';
html += '<div class="all-friends-list" style="display: none;">';
['first_degree', 'second_degree', 'third_degree'].forEach(degree => {
const friends = campaign.available_through_friends[degree];
if (friends && friends.length > 0) {
html += `
<div class="degree-section">
<h5>${degree.replace('_', ' ').toUpperCase()} (${friends.length})</h5>
<div class="friends-grid">
`;
friends.forEach(friend => {
html += `
<div class="friend-option ${friend.deal_rank === 1 ? 'top-ranked' : ''}">
<div class="friend-info">
<span class="friend-name">${friend.friend_name}</span>
<span class="influence-score">Score: ${friend.influence_score}</span>
<span class="relationship-strength">${friend.relationship_strength}</span>
<div class="platforms">
${friend.shared_platforms.map(platform => `<span class="platform">${platform}</span>`).join('')}
</div>
${friend.has_purchased ? '<span class="purchased-badge">✓ Already purchased</span>' : ''}
</div>
<a href="${friend.referral_url}" class="use-deal-btn secondary">Use Deal</a>
</div>
`;
});
html += '</div></div>';
}
});
html += '</div></div>';
return html;
}
}
// Usage example
async function displayUserDeals(userId) {
const dealsManager = new DealsManager('your_secret_key');
const dealsData = await dealsManager.getAllUserDeals(userId, {
include_purchased: false,
limit: 10
});
if (dealsData.success) {
dealsManager.renderAllDeals(dealsData);
// Add toggle functionality for viewing all friends
document.querySelectorAll('.toggle-all-friends').forEach(button => {
button.addEventListener('click', (e) => {
const friendsList = e.target.nextElementSibling;
const isVisible = friendsList.style.display !== 'none';
friendsList.style.display = isVisible ? 'none' : 'block';
e.target.textContent = isVisible ? 'View All Friends Sharing' : 'Hide All Friends';
});
});
} else {
console.error('Failed to load deals:', dealsData.error);
}
}
Pattern 2: Filter by Relationship Degree
Display deals from specific relationship degrees (first, second, or third degree friends).
class DegreeFilteredDeals {
constructor(secretKey) {
this.secretKey = secretKey;
this.headers = {
'Authorization': `Bearer ${secretKey}`,
'Content-Type': 'application/json'
};
}
async getDealsByDegree(userId, degree, options = {}) {
const queryParams = new URLSearchParams({
user_id: userId,
degree: degree,
limit: options.limit || 20,
offset: options.offset || 0,
sort_by: options.sort_by || 'influence_score',
sort_order: options.sort_order || 'DESC'
});
try {
const response = await fetch(`/partner/v1/campaigns/deals?${queryParams}`, {
method: 'GET',
headers: this.headers
});
const result = await response.json();
if (result.success) {
return {
success: true,
degree: result.data.requested_degree,
campaigns: result.data.campaigns,
totalCampaigns: result.data.total_campaigns,
totalFriendsSharing: result.data.total_friends_sharing
};
}
return { success: false, error: result.message };
} catch (error) {
console.error(`Failed to fetch ${degree} degree deals:`, error);
return { success: false, error: 'Network error' };
}
}
async createDegreeTabInterface(userId) {
const container = document.getElementById('deals-container');
// Create tab interface
container.innerHTML = `
<div class="degree-tabs">
<button class="tab-btn active" data-degree="all">All Friends</button>
<button class="tab-btn" data-degree="first">Close Friends</button>
<button class="tab-btn" data-degree="second">Friends of Friends</button>
<button class="tab-btn" data-degree="third">Extended Network</button>
</div>
<div class="deals-content">
<div class="loading">Loading deals...</div>
</div>
`;
// Add tab functionality
const tabBtns = container.querySelectorAll('.tab-btn');
const dealsContent = container.querySelector('.deals-content');
tabBtns.forEach(btn => {
btn.addEventListener('click', async (e) => {
// Update active tab
tabBtns.forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
// Load deals for selected degree
const degree = e.target.dataset.degree;
dealsContent.innerHTML = '<div class="loading">Loading deals...</div>';
try {
let dealsData;
if (degree === 'all') {
const allDealsManager = new DealsManager(this.secretKey);
dealsData = await allDealsManager.getAllUserDeals(userId);
} else {
dealsData = await this.getDealsByDegree(userId, degree);
}
if (dealsData.success) {
this.renderDegreeDeals(dealsContent, dealsData, degree);
} else {
dealsContent.innerHTML = `<p class="error">Failed to load ${degree} degree deals: ${dealsData.error}</p>`;
}
} catch (error) {
dealsContent.innerHTML = `<p class="error">Error loading deals: ${error.message}</p>`;
}
});
});
// Load all deals initially
const allDealsManager = new DealsManager(this.secretKey);
const initialDeals = await allDealsManager.getAllUserDeals(userId);
if (initialDeals.success) {
this.renderDegreeDeals(dealsContent, initialDeals, 'all');
}
}
renderDegreeDeals(container, dealsData, degree) {
if (!dealsData.campaigns || dealsData.campaigns.length === 0) {
container.innerHTML = `
<div class="no-deals">
<h3>No deals available</h3>
<p>No ${degree === 'all' ? '' : degree + ' degree'} friends are sharing deals right now.</p>
</div>
`;
return;
}
let html = `
<div class="deals-summary">
<h3>${dealsData.totalCampaigns} ${degree === 'all' ? '' : degree + ' degree'} deals available</h3>
<p>${dealsData.totalFriendsSharing} friends sharing deals</p>
</div>
<div class="deals-grid">
`;
dealsData.campaigns.forEach(campaign => {
html += this.createCompactCampaignCard(campaign, degree);
});
html += '</div>';
container.innerHTML = html;
}
createCompactCampaignCard(campaign, degree) {
const friendsToShow = degree === 'all'
? this.getFriendsFromAllDegrees(campaign.available_through_friends)
: campaign[`${degree}_degree_friends`] || [];
return `
<div class="campaign-card compact">
<div class="campaign-preview">
<img src="${campaign.image_url}" alt="${campaign.campaign_display_name}">
<div class="campaign-details">
<h4>${campaign.campaign_display_name}</h4>
<p class="expires">Expires ${new Date(campaign.expires_at).toLocaleDateString()}</p>
</div>
</div>
<div class="best-friend-preview">
<div class="friend-info">
<span class="friend-name">${campaign.best_friend_to_use.friend_name}</span>
<span class="influence">Score: ${campaign.best_friend_to_use.influence_score}</span>
</div>
<a href="${campaign.best_friend_to_use.referral_url}" class="quick-use-btn">Use Deal</a>
</div>
${friendsToShow.length > 1 ? `
<div class="other-friends">
<span class="friends-count">+${friendsToShow.length - 1} other friend${friendsToShow.length > 2 ? 's' : ''}</span>
<button class="view-all-btn" onclick="showAllFriendsModal('${campaign.campaign_id}')">View All</button>
</div>
` : ''}
</div>
`;
}
getFriendsFromAllDegrees(availableThroughFriends) {
const allFriends = [];
['first_degree', 'second_degree', 'third_degree'].forEach(degree => {
if (availableThroughFriends[degree]) {
allFriends.push(...availableThroughFriends[degree]);
}
});
return allFriends.sort((a, b) => b.influence_score - a.influence_score);
}
}
// Usage example
async function setupDegreeFilteredInterface(userId) {
const degreeDeals = new DegreeFilteredDeals('your_secret_key');
await degreeDeals.createDegreeTabInterface(userId);
}
Pattern 3: Smart Recommendation System
Implement intelligent recommendations based on CashIn's friendship ranking ELO system.
class SmartRecommendationSystem {
constructor(secretKey) {
this.secretKey = secretKey;
this.headers = {
'Authorization': `Bearer ${secretKey}`,
'Content-Type': 'application/json'
};
}
async getPersonalizedRecommendations(userId, preferences = {}) {
const dealsManager = new DealsManager(this.secretKey);
const allDeals = await dealsManager.getAllUserDeals(userId, {
include_purchased: false,
limit: 50
});
if (!allDeals.success) return allDeals;
const recommendations = this.analyzeAndRankDeals(allDeals.campaigns, preferences);
return {
success: true,
recommendations,
totalAnalyzed: allDeals.campaigns.length
};
}
analyzeAndRankDeals(campaigns, preferences) {
return campaigns.map(campaign => {
const analysis = this.analyzeCampaign(campaign, preferences);
return {
...campaign,
recommendation_score: analysis.score,
recommendation_reasons: analysis.reasons,
conversion_probability: analysis.conversionProbability
};
}).sort((a, b) => b.recommendation_score - a.recommendation_score);
}
analyzeCampaign(campaign, preferences = {}) {
let score = 0;
const reasons = [];
// Best friend influence score (40% weight)
const influenceScore = campaign.best_friend_to_use.influence_score;
const influenceWeight = influenceScore / 1000 * 40;
score += influenceWeight;
if (influenceScore > 800) {
reasons.push('High-influence friend recommendation');
}
// Relationship degree (30% weight)
const degree = campaign.best_friend_to_use.relationship_degree;
let degreeWeight = 0;
if (degree === 'first') {
degreeWeight = 30;
reasons.push('Close friend sharing');
} else if (degree === 'second') {
degreeWeight = 20;
reasons.push('Friend of friend sharing');
} else {
degreeWeight = 10;
}
score += degreeWeight;
// Multiple friends sharing (20% weight)
if (campaign.friends_sharing_count > 1) {
const popularityWeight = Math.min(campaign.friends_sharing_count * 5, 20);
score += popularityWeight;
reasons.push(`${campaign.friends_sharing_count} friends sharing this deal`);
}
// Time urgency (10% weight)
const daysUntilExpiry = this.getDaysUntilExpiry(campaign.expires_at);
if (daysUntilExpiry <= 7) {
score += 10;
reasons.push('Expires soon');
}
// User preferences
if (preferences.preferred_friends &&
preferences.preferred_friends.includes(campaign.best_friend_to_use.friend_user_code)) {
score += 15;
reasons.push('From preferred friend');
}
return {
score: Math.round(score),
reasons,
conversionProbability: Math.min(score / 100, 0.95)
};
}
getDaysUntilExpiry(expiresAt) {
const expiry = new Date(expiresAt);
const now = new Date();
return Math.ceil((expiry - now) / (1000 * 60 * 60 * 24));
}
renderSmartRecommendations(recommendations) {
const container = document.getElementById('recommendations-container');
if (!recommendations || recommendations.length === 0) {
container.innerHTML = '<p class="no-recommendations">No personalized recommendations available.</p>';
return;
}
let html = `
<div class="recommendations-header">
<h2>🎯 Personalized Recommendations</h2>
<p>Based on friend influence, relationship strength, and deal popularity</p>
</div>
<div class="recommendations-list">
`;
recommendations.slice(0, 5).forEach((campaign, index) => {
html += `
<div class="recommendation-item rank-${index + 1}">
<div class="rank-badge">#${index + 1}</div>
<div class="campaign-info">
<img src="${campaign.image_url}" alt="${campaign.campaign_display_name}">
<div class="details">
<h3>${campaign.campaign_display_name}</h3>
<p class="friend-rec">Recommended by ${campaign.best_friend_to_use.friend_name}</p>
<div class="metrics">
<span class="score">Score: ${campaign.recommendation_score}/100</span>
<span class="probability">Conversion: ${Math.round(campaign.conversion_probability * 100)}%</span>
</div>
</div>
</div>
<div class="recommendation-reasons">
<h4>Why this recommendation?</h4>
<ul>
${campaign.recommendation_reasons.map(reason => `<li>${reason}</li>`).join('')}
</ul>
</div>
<div class="action-area">
<a href="${campaign.best_friend_to_use.referral_url}" class="use-deal-btn recommended">
Use Recommended Deal
</a>
<button class="view-alternatives" onclick="showAlternatives('${campaign.campaign_id}')">
View ${campaign.friends_sharing_count - 1} Other Friends
</button>
</div>
</div>
`;
});
html += '</div>';
container.innerHTML = html;
}
async generateUserInsights(userId) {
const dealsManager = new DealsManager(this.secretKey);
const allDeals = await dealsManager.getAllUserDeals(userId, { include_purchased: true });
if (!allDeals.success) return null;
const insights = {
networkSize: this.calculateNetworkSize(allDeals.campaigns),
topInfluencers: this.getTopInfluencers(allDeals.campaigns),
platformDistribution: this.getPlatformDistribution(allDeals.campaigns),
relationshipBreakdown: this.getRelationshipBreakdown(allDeals.campaigns)
};
return insights;
}
calculateNetworkSize(campaigns) {
const uniqueFriends = new Set();
campaigns.forEach(campaign => {
['first_degree', 'second_degree', 'third_degree'].forEach(degree => {
const friends = campaign.available_through_friends[degree];
if (friends) {
friends.forEach(friend => uniqueFriends.add(friend.friend_id));
}
});
});
return uniqueFriends.size;
}
getTopInfluencers(campaigns) {
const friendInfluence = new Map();
campaigns.forEach(campaign => {
['first_degree', 'second_degree', 'third_degree'].forEach(degree => {
const friends = campaign.available_through_friends[degree];
if (friends) {
friends.forEach(friend => {
const existing = friendInfluence.get(friend.friend_id) ||
{ name: friend.friend_name, maxScore: 0, dealsShared: 0 };
friendInfluence.set(friend.friend_id, {
...existing,
maxScore: Math.max(existing.maxScore, friend.influence_score),
dealsShared: existing.dealsShared + 1
});
});
}
});
});
return Array.from(friendInfluence.values())
.sort((a, b) => b.maxScore - a.maxScore)
.slice(0, 5);
}
getPlatformDistribution(campaigns) {
const platforms = {};
campaigns.forEach(campaign => {
['first_degree', 'second_degree', 'third_degree'].forEach(degree => {
const friends = campaign.available_through_friends[degree];
if (friends) {
friends.forEach(friend => {
friend.shared_platforms.forEach(platform => {
platforms[platform] = (platforms[platform] || 0) + 1;
});
});
}
});
});
return Object.entries(platforms)
.sort(([,a], [,b]) => b - a)
.slice(0, 5);
}
getRelationshipBreakdown(campaigns) {
const breakdown = { first: 0, second: 0, third: 0 };
campaigns.forEach(campaign => {
['first_degree', 'second_degree', 'third_degree'].forEach(degree => {
const friends = campaign.available_through_friends[degree];
if (friends) {
const degreeKey = degree.split('_')[0];
breakdown[degreeKey] += friends.length;
}
});
});
return breakdown;
}
}
// Usage example
async function setupSmartRecommendations(userId, userPreferences = {}) {
const smartSystem = new SmartRecommendationSystem('your_secret_key');
const recommendations = await smartSystem.getPersonalizedRecommendations(userId, userPreferences);
if (recommendations.success) {
smartSystem.renderSmartRecommendations(recommendations.recommendations);
// Generate additional insights
const insights = await smartSystem.generateUserInsights(userId);
if (insights) {
console.log('User Network Insights:', insights);
}
}
}
Complete Deals Integration
Unified Deals System
class CashInDealsSystem {
constructor(secretKey) {
this.secretKey = secretKey;
this.dealsManager = new DealsManager(secretKey);
this.degreeFilter = new DegreeFilteredDeals(secretKey);
this.smartRecommendations = new SmartRecommendationSystem(secretKey);
}
async initializeDealsSystem(userId, options = {}) {
try {
const [allDeals, recommendations, insights] = await Promise.all([
this.dealsManager.getAllUserDeals(userId),
this.smartRecommendations.getPersonalizedRecommendations(userId, options.preferences),
this.smartRecommendations.generateUserInsights(userId)
]);
return {
success: true,
allDeals: allDeals.success ? allDeals : null,
recommendations: recommendations.success ? recommendations : null,
insights,
networkSize: insights?.networkSize || 0
};
} catch (error) {
console.error('Failed to initialize deals system:', error);
return { success: false, error: 'System initialization failed' };
}
}
async createComprehensiveInterface(userId, containerId) {
const container = document.getElementById(containerId);
// Create main interface structure
container.innerHTML = `
<div class="deals-dashboard">
<div class="dashboard-header">
<h1>Your Friend Deals</h1>
<div class="network-stats">
<span class="stat">
<strong id="total-campaigns">-</strong>
<label>Available Deals</label>
</span>
<span class="stat">
<strong id="network-size">-</strong>
<label>Friends in Network</label>
</span>
<span class="stat">
<strong id="top-influence">-</strong>
<label>Top Influence Score</label>
</span>
</div>
</div>
<div class="interface-tabs">
<button class="interface-tab active" data-interface="recommendations">🎯 Smart Picks</button>
<button class="interface-tab" data-interface="degrees">👥 By Relationship</button>
<button class="interface-tab" data-interface="all">📋 All Deals</button>
</div>
<div class="interface-content">
<div id="recommendations-view" class="interface-view active">
<div class="loading">Loading personalized recommendations...</div>
</div>
<div id="degrees-view" class="interface-view">
<div class="loading">Loading relationship-based deals...</div>
</div>
<div id="all-view" class="interface-view">
<div class="loading">Loading all available deals...</div>
</div>
</div>
</div>
`;
// Initialize the system
const systemData = await this.initializeDealsSystem(userId);
if (systemData.success) {
this.populateStats(systemData);
this.setupInterfaceTabs(userId);
this.loadDefaultView(userId, systemData);
}
}
populateStats(systemData) {
if (systemData.allDeals) {
document.getElementById('total-campaigns').textContent = systemData.allDeals.totalCampaigns;
}
if (systemData.insights) {
document.getElementById('network-size').textContent = systemData.insights.networkSize;
const topInfluencer = systemData.insights.topInfluencers[0];
if (topInfluencer) {
document.getElementById('top-influence').textContent = topInfluencer.maxScore;
}
}
}
setupInterfaceTabs(userId) {
const tabs = document.querySelectorAll('.interface-tab');
const views = document.querySelectorAll('.interface-view');
tabs.forEach(tab => {
tab.addEventListener('click', async (e) => {
// Update active tab
tabs.forEach(t => t.classList.remove('active'));
views.forEach(v => v.classList.remove('active'));
e.target.classList.add('active');
const interfaceType = e.target.dataset.interface;
const targetView = document.getElementById(`${interfaceType}-view`);
targetView.classList.add('active');
// Load appropriate content
await this.loadInterfaceContent(interfaceType, userId, targetView);
});
});
}
async loadInterfaceContent(interfaceType, userId, container) {
container.innerHTML = '<div class="loading">Loading...</div>';
try {
switch (interfaceType) {
case 'recommendations':
const recommendations = await this.smartRecommendations.getPersonalizedRecommendations(userId);
if (recommendations.success) {
this.smartRecommendations.renderSmartRecommendations(recommendations.recommendations);
}
break;
case 'degrees':
await this.degreeFilter.createDegreeTabInterface(userId);
break;
case 'all':
const allDeals = await this.dealsManager.getAllUserDeals(userId);
if (allDeals.success) {
this.dealsManager.renderAllDeals(allDeals);
}
break;
}
} catch (error) {
container.innerHTML = `<div class="error">Failed to load ${interfaceType}: ${error.message}</div>`;
}
}
async loadDefaultView(userId, systemData) {
// Load recommendations by default
const recommendationsView = document.getElementById('recommendations-view');
if (systemData.recommendations) {
this.smartRecommendations.renderSmartRecommendations(systemData.recommendations.recommendations);
}
}
}
// Usage example
async function setupCompleteDealsSystem(userId) {
const dealsSystem = new CashInDealsSystem('your_secret_key');
await dealsSystem.createComprehensiveInterface(userId, 'deals-dashboard-container');
}
Error Handling and Best Practices
Comprehensive Error Management
class DealsErrorHandler {
static handleDealsError(error, context = {}) {
console.error('Deals API error:', error, context);
switch (error.status) {
case 400:
return {
userMessage: 'Invalid request. Please check the user ID and try again.',
retry: false
};
case 404:
return {
userMessage: 'No deals found for this user.',
retry: false,
showEmptyState: true
};
case 429:
return {
userMessage: 'Too many requests. Please wait a moment and try again.',
retry: true,
delay: 60000
};
default:
return {
userMessage: 'Something went wrong loading deals. Please try again.',
retry: true