API Implementation Best Practices
Follow this outline of best practices for implementing the Cardlytics API
Abstract
This document presents a comprehensive guide to implementing secure, performant, and user-centric integrations with the Cardlytics API. It covers best practices for authentication and session management, including secure token caching, customer ID protection with HMAC-SHA-256, and robust secret management. The guide details strategies for seamless account linking, personalized offer retrieval and display, and accurate event tracking and analytics to measure user engagement and system performance. It emphasizes resilient error handling, multi-level caching, and request optimization to ensure high availability and low latency.
The document also outlines rigorous testing, development, and deployment procedures, with a focus on security verification, monitoring, and operational readiness. Key technical, business, and user experience metrics are highlighted to track implementation success. By following these guidelines, developers can achieve a scalable, secure, and high-quality integration that maximizes value for both institutions and end users.
Authentication and Session Management
Token Management Best Practices
1. Implement Token Caching
- Cache bearer tokens for their full 15-minute lifespan
- Store tokens in memory or secure cache (Redis, Memcached)
- Never store tokens in localStorage or persistent storage for security
- Implement automatic token refresh before expiration
// Example token management
class TokenManager {
constructor() {
this.token = null;
this.tokenExpiry = null;
}
async getValidToken() {
if (!this.token || Date.now() >= this.tokenExpiry) {
await this.refreshToken();
}
return this.token;
}
async refreshToken() {
// Request new token 30 seconds before expiration
const response = await fetch('/v2/session/startSession', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ clientId, secret })
});
this.token = response.token;
this.tokenExpiry = Date.now() + (14.5 * 60 * 1000); // 14.5 minutes
}
}
2. Handle Authentication States
- NEW USERS: Use
"no-user-available"
asx-source-customer-id
for welcome offers - EXISTING USERS: Use properly hashed customer IDs (HMAC-SHA-256)
- Implement graceful fallback when authentication fails
3. Session Lifecycle Management
- Initialize sessions early in user journey
- Maintain session state throughout user interactions
- Handle session expiration gracefully with automatic re-authentication
Security Implementation
Customer ID Protection
1. HMAC-SHA-256 Hashing
Always hash customer IDs before sending to the API:
const crypto = require('crypto');
function hashCustomerId(customerId, secret) {
return crypto.createHmac('sha256', secret).update(customerId).digest('hex');
}
// Usage
const hashedId = hashCustomerId(userCustomerId, sharedSecret);
2. Secret Management
- Store
clientId
andsecret
in secure environment variables - Never expose secrets in client-side code
- Rotate secrets regularly following security policies
- Use different secrets for different environments (dev, staging, prod)
3. Request Security
- Always use HTTPS for all API communications
- Implement request signing where applicable
- Validate all incoming webhook signatures
- Use secure headers and follow OWASP guidelines
Account Linking Integration
Link SDK Implementation
1. Progressive Enhancement
- Implement account linking as an optional enhancement
- Provide value even without linked accounts (welcome offers)
- Guide users through linking process with clear benefits
2. Error Recovery
- Handle linking failures gracefully
- Provide clear error messages and recovery steps
- Implement retry mechanisms for transient failures
class AccountLinkManager {
async initializeLink(userId, redirectUri) {
try {
const token = await this.tokenManager.getValidToken();
const hashedId = hashCustomerId(userId, this.secret);
await CardlyticsLinkSDK.startAccountLink(
token,
'PLAID_HOSTED',
redirectUri,
hashedId
);
} catch (error) {
this.handleLinkError(error);
}
}
handleLinkError(error) {
// Log error for monitoring
// Show user-friendly message
// Offer alternative actions
}
}
3. Link Status Monitoring
- Regularly check account link status
- Handle link degradation or expiration
- Notify users when re-linking is needed
Offer Retrieval and Display
Offer Fetching Strategy
1. Smart Filtering and Pagination
- Use appropriate filters to reduce payload size
- Implement
maxAdLimit
based on UI capacity - Consider user context (channel, section) when fetching
const offerRequest = {
channel: "OLB",
sections: ["Dashboard", "Landing"],
maxAdLimit: 20,
visibilityStates: ["VISIBLE"],
activationStates: ["NEW", "SERVED"],
returnMetadata: true
};
2. Content Personalization
- Use
categoryIds
andcurationIds
for targeted content - Implement user preference filtering
- Consider geographic relevance
3. Offer State Management
- Track offer progression through states (NEW → SERVED → ACTIVATED)
- Handle state transitions appropriately
- Update UI based on current offer states
Display Best Practices
1. Image Optimization
- Use
assets.logo.small
for list/tile views (128x128) - Use
assets.logo.large
for detail views (627x627) - Implement lazy loading for images
- Provide fallback images for missing assets
2. Content Rendering
- Display
assets.copy.shortPreMessage
for compact views - Use
assets.copy.rewardCopy
for detailed descriptions - Show
assets.copy.termsAndConditions
prominently - Format expiration dates clearly
3. Rankings Implementation
- Use the
rankings.all
array for default ordering - Implement section-specific rankings when available
- Maintain ranking order in UI display
Event Tracking and Analytics
Comprehensive Event Strategy
1. Session Events
- Send
LogEnrollment
when user first sees offers - Track all major user interactions
- Maintain event sequence and timing
2. Impression Tracking
- Implement viewability detection for
AdViewableImpression
- Track impressions only when offers are actually visible
- Use Intersection Observer API for accurate tracking
class ImpressionTracker {
constructor() {
this.observer = new IntersectionObserver(
this.handleIntersection.bind(this),
{ threshold: 0.5 }
);
}
trackOffer(element, serveToken, section, channel) {
element.dataset.serveToken = serveToken;
element.dataset.section = section;
element.dataset.channel = channel;
this.observer.observe(element);
}
handleIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.sendImpressionEvent(entry.target);
this.observer.unobserve(entry.target);
}
});
}
}
3. Interaction Events
- Track offer activations immediately
- Record display element expansions/collapses
- Monitor URL link clicks
- Handle parking/hiding actions
Event Data Quality
1. Required Metadata
- Always include
serveToken
from original offer response - Specify accurate
section
andchannel
information - Include
displayPosition
for list-based displays - Generate unique
clientEventId
for each event
2. Timing Accuracy
- Use ISO-8601 timestamps
- Capture events at actual interaction time
- Maintain event sequence integrity
Reward Notification Handling
Notification Infrastructure
1. Webhook Implementation
- Set up secure webhook endpoints
- Validate incoming webhook signatures
- Implement idempotent processing for duplicate notifications
- Handle webhook retries and failures
app.post('/webhook/rewards', (req, res) => {
try {
// Validate signature
const isValid = validateWebhookSignature(req.body, req.headers);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// Process reward notification
await processRewardNotification(req.body);
res.status(200).send('OK');
} catch (error) {
console.error('Webhook processing failed:', error);
res.status(500).send('Processing failed');
}
});
2. File Transfer Setup
- Configure S3 file transfer for batch reward data
- Implement file processing pipelines
- Handle file parsing and validation
- Maintain processing logs and error tracking
3. Real-Time vs Batch Processing
- Use webhooks for immediate user notifications
- Use file transfer for reconciliation and reporting
- Implement dual-path verification for critical rewards
Error Handling and Resilience
API Error Management
1. Status Code Handling
- 401 Unauthorized: Trigger token refresh and retry
- 500 Internal Server Error: Implement exponential backoff
- Network errors: Retry with circuit breaker pattern
class APIClient {
async makeRequest(url, options, retries = 3) {
try {
const response = await fetch(url, options);
if (response.status === 401) {
await this.tokenManager.refreshToken();
options.headers.Authorization = `Bearer ${await this.tokenManager.getValidToken()}`;
return this.makeRequest(url, options, retries - 1);
}
if (!response.ok && retries > 0) {
await this.delay(Math.pow(2, 4 - retries) * 1000);
return this.makeRequest(url, options, retries - 1);
}
return response;
} catch (error) {
if (retries > 0) {
await this.delay(Math.pow(2, 4 - retries) * 1000);
return this.makeRequest(url, options, retries - 1);
}
throw error;
}
}
}
2. Graceful Degradation
- Show cached offers when API is unavailable
- Provide offline functionality where possible
- Display appropriate error messages to users
3. Monitoring and Alerting
- Implement comprehensive logging
- Set up error rate monitoring
- Create alerts for API failures and performance issues
Performance Optimization
Caching Strategy
1. Multi-Level Caching
- L1 Cache: In-memory offer cache (5-15 minutes)
- L2 Cache: Redis/Memcached for shared state
- L3 Cache: CDN for static assets (images, terms)
2. Cache Invalidation
- Implement cache warming strategies
- Use cache tags for selective invalidation
- Handle cache coherency across multiple servers
Request Optimization
1. Batch Operations
- Group multiple events into single API calls
- Implement request queuing for high-traffic scenarios
- Use connection pooling for API requests
2. Asset Optimization
- Implement image resizing and optimization
- Use WebP format where supported
- Implement progressive image loading
Testing and Development
Development Environment
1. Mock Data Usage
- Use
x-mock-data: true
header for testing - Implement comprehensive test data sets
- Create realistic user scenarios for testing
2. Environment Configuration
- Separate configurations for dev/staging/production
- Use environment-specific API endpoints
- Implement feature flags for gradual rollouts
Testing Strategy
1. Integration Testing
- Test complete user journeys
- Validate event tracking accuracy
- Test error scenarios and recovery
2. Performance Testing
- Load test API integrations
- Validate caching effectiveness
- Test under various network conditions
Production Deployment
Deployment Checklist
1. Security Verification
- Ensure all secrets are properly configured
- Validate HMAC implementation
- Verify HTTPS enforcement
2. Monitoring Setup
- Configure API response time monitoring
- Set up error rate alerting
- Implement business metric tracking
3. Rollout Strategy
- Implement gradual feature rollout
- Monitor key metrics during deployment
- Have rollback procedures ready
Operational Considerations
1. Capacity Planning
- Monitor API rate limits
- Plan for traffic spikes
- Implement auto-scaling where applicable
2. Maintenance Windows
- Plan for API maintenance periods
- Implement graceful degradation during outages
- Communicate maintenance to users appropriately
3. Data Retention
- Implement appropriate data retention policies
- Ensure compliance with privacy regulations
- Plan for data archival and deletion
Key Success Metrics
Technical Metrics
- API response times < 500ms (95th percentile)
- Error rates < 0.1%
- Token refresh success rate > 99.9%
- Event delivery success rate > 99.5%
Business Metrics
- Offer impression rates
- Activation conversion rates
- User engagement with linked accounts
- Reward redemption rates
User Experience Metrics
- Page load times
- Offer display accuracy
- User satisfaction scores
- Support ticket volumes
Conclusion
Successful Cardlytics API implementation requires careful attention to security, performance, and user experience. Follow these best practices to ensure a robust, scalable integration that delivers value to both your institution and your customers.
Regular review and optimization of your implementation will help maintain high performance and user satisfaction as your program grows.
Updated about 23 hours ago