Skip to content

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}`));

WalletHero Documentation