Loyalty Program Example
Build a complete loyalty program with points, tiers, and automated upgrades.
Setup
typescript
import { WalletHero } from '@wallethero/sdk';
const client = new WalletHero({
apiToken: process.env.WALLETHERO_API_TOKEN!
});
const WORKSPACE_ID = 'your-workspace-id';
const PROJECT_ID = 'your-project-id';1. Create Templates for Each Tier
typescript
// Bronze tier template
const bronzeTemplate = await client.passTemplates.create({
name: 'Bronze Member',
workspace_id: WORKSPACE_ID,
project_id: PROJECT_ID,
apple_pass_type_identifier: 'pass.com.example.loyalty',
background_color: '#CD7F32',
label_color: '#FFFFFF',
value_color: '#FFFFFF',
logo_text: 'ACME Rewards',
barcode_type: 'qr',
top_field_label: 'POINTS',
top_field_value: '{{points}}',
front_fields: [
{ label: 'Member', value: '{{full_name}}' },
{ label: 'Status', value: 'Bronze' }
],
secondary_fields: [
{ label: 'Member Since', value: '{{member_since}}' }
]
});
// Silver tier template
const silverTemplate = await client.passTemplates.create({
name: 'Silver Member',
workspace_id: WORKSPACE_ID,
project_id: PROJECT_ID,
apple_pass_type_identifier: 'pass.com.example.loyalty',
background_color: '#C0C0C0',
label_color: '#333333',
value_color: '#333333',
logo_text: 'ACME Rewards',
barcode_type: 'qr',
top_field_label: 'POINTS',
top_field_value: '{{points}}',
front_fields: [
{ label: 'Member', value: '{{full_name}}' },
{ label: 'Status', value: 'Silver' }
]
});
// Gold tier template
const goldTemplate = await client.passTemplates.create({
name: 'Gold Member',
workspace_id: WORKSPACE_ID,
project_id: PROJECT_ID,
apple_pass_type_identifier: 'pass.com.example.loyalty',
background_color: '#FFD700',
label_color: '#333333',
value_color: '#333333',
logo_text: 'ACME Rewards',
barcode_type: 'qr',
top_field_label: 'POINTS',
top_field_value: '{{points}}',
front_fields: [
{ label: 'Member', value: '{{full_name}}' },
{ label: 'Status', value: 'Gold VIP' }
]
});2. Enroll New Members
typescript
async function enrollMember(name: string, email: string) {
const pass = await client.passes.create({
pass_template_id: bronzeTemplate.id,
project_id: PROJECT_ID,
workspace_id: WORKSPACE_ID,
full_name: name,
email: email,
custom_fields: {
points: 0,
tier: 'Bronze',
member_since: new Date().toISOString().split('T')[0],
lifetime_spend: 0
}
});
console.log(`Enrolled ${name} - Pass URL: ${pass.apple_pass_url}`);
return pass;
}
// Enroll a member
const member = await enrollMember('Jane Doe', '[email protected]');3. Process Purchases
typescript
async function processPurchase(passId: string, amount: number, items: string[]) {
// Get current pass data
const pass = await client.passes.get(passId);
const currentPoints = pass.custom_fields?.points || 0;
const currentSpend = pass.custom_fields?.lifetime_spend || 0;
// Calculate points (1 point per dollar)
const earnedPoints = Math.floor(amount);
const newPoints = currentPoints + earnedPoints;
const newSpend = currentSpend + amount;
// Record the transaction event
await client.events.recordPurchase(passId, {
amount,
currency: 'USD',
metadata: { items }
});
// Update the pass
await client.passes.update(passId, {
notification: `You earned ${earnedPoints} points!`,
custom_fields: {
points: newPoints,
lifetime_spend: newSpend,
last_purchase: new Date().toISOString()
}
});
console.log(`Processed $${amount} purchase. Points: ${currentPoints} → ${newPoints}`);
// Check for tier upgrade
await checkTierUpgrade(passId, newPoints);
return { earnedPoints, newPoints };
}4. Automated Tier Upgrades
typescript
async function checkTierUpgrade(passId: string, points: number) {
const pass = await client.passes.get(passId);
const currentTier = pass.custom_fields?.tier;
let newTier = currentTier;
let newTemplateId = pass.pass_template_id;
// Determine new tier based on points
if (points >= 5000 && currentTier !== 'Gold') {
newTier = 'Gold';
newTemplateId = goldTemplate.id;
} else if (points >= 1000 && currentTier === 'Bronze') {
newTier = 'Silver';
newTemplateId = silverTemplate.id;
}
// Upgrade if tier changed
if (newTier !== currentTier) {
await client.passes.update(passId, {
pass_template_id: newTemplateId,
notification: `🎉 Congratulations! You've been upgraded to ${newTier}!`,
custom_fields: {
tier: newTier,
upgraded_at: new Date().toISOString()
}
});
console.log(`Upgraded ${pass.full_name} to ${newTier}!`);
}
}5. Create Segments for Marketing
typescript
// High-value members who haven't purchased recently
const lapsedVIPs = await client.segments.create({
workspace_id: WORKSPACE_ID,
name: 'Lapsed VIPs',
filters: [
{
filter_type: 'custom_field',
filter_config: {
custom_field_filters: {
tier: { operator: '_in', value: ['Silver', 'Gold'] }
}
}
},
{
filter_type: 'event_recency',
filter_config: {
event_category: 'transaction',
event_types: ['purchase'],
operator: 'not_within_days',
days: 30
}
}
]
});
// Check segment size
const size = await client.segments.calculate(lapsedVIPs.id);
console.log(`Found ${size.total} lapsed VIP members`);6. Run Re-engagement Campaign
typescript
// Create campaign
const campaign = await client.campaigns.create({
workspace_id: WORKSPACE_ID,
name: 'Win Back VIPs',
segment_id: lapsedVIPs.id
});
// Add bonus points action
await client.campaigns.addAction(campaign.id, {
action_type: 'custom_field_update',
action_config: {
custom_field_updates: {
bonus_points: 100,
bonus_expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
}
}
});
// Add notification
await client.campaigns.addAction(campaign.id, {
action_type: 'push_notification',
action_config: {
notification_message: '💎 We miss you! Here\'s 100 bonus points - visit us this week!'
}
});
// Execute campaign
await client.campaigns.startNow(campaign.id);7. Analytics
typescript
// Get total revenue this month
const monthlyRevenue = await client.events.aggregate({
workspace_id: WORKSPACE_ID,
function: 'sum',
field: 'amount',
event_category: 'transaction',
event_types: ['purchase'],
time_window: 'month'
});
console.log(`Monthly revenue: $${monthlyRevenue.value.toFixed(2)}`);
// Get top spenders
const topSpenders = await client.events.aggregate({
workspace_id: WORKSPACE_ID,
function: 'sum',
field: 'amount',
event_category: 'transaction',
time_window: 'year',
group_by_pass: true
});
console.log('Top 10 Spenders:');
topSpenders
.sort((a, b) => b.value - a.value)
.slice(0, 10)
.forEach((s, i) => console.log(`${i + 1}. Pass ${s.pass_id}: $${s.value}`));