Skip to main content

Migration Guide

Guide for upgrading Loyalteez integrations and handling API changes.


Current Version

SDK Version: 2.0
API Version: v2

This is the current production version with full support and all features documented in this guide.


Upgrading to v2.0

What's New

New Features:

  • OAuth wallet pregeneration (8 providers)
  • Idempotent API endpoints
  • Enhanced error messages
  • created_new flag in responses
  • Gas Relayer EIP-2612 permit support
  • Real-time reward toasts in SDK
  • Client-side event deduplication (2s window)

🔧 Improvements:

  • Faster event tracking (< 50ms)
  • Better rate limit handling
  • Comprehensive error codes
  • TypeScript definitions
  • Enhanced security

🐛 Bug Fixes:

  • Fixed duplicate event tracking
  • Resolved wallet creation race conditions
  • Fixed Privy token expiration handling

Breaking Changes

1. SDK Initialization

❌ Old (v1.x):

LoyalteezAutomation.init({
brand: 'your-brand-id',
apiEndpoint: 'https://api.loyalteez.app'
});

✅ New (v2.0):

LoyalteezAutomation.init('your-brand-id', {
endpoint: 'https://api.loyalteez.app', // Changed key
debug: false,
autoDetect: false
});

Migration:

// Find in your code:
LoyalteezAutomation.init({
brand: brandId,
apiEndpoint: endpoint
});

// Replace with:
LoyalteezAutomation.init(brandId, {
endpoint: endpoint
});

2. Event Response Format

❌ Old Response (v1.x):

{
"success": true,
"event_id": "123",
"reward": 100
}

✅ New Response (v2.0):

{
"success": true,
"eventId": "123",
"rewardAmount": 100,
"walletCreated": true,
"walletAddress": "0x..."
}

Migration:

// ❌ Old
const { event_id, reward } = response;

// ✅ New
const { eventId, rewardAmount, walletAddress } = response;

3. Error Response Format

❌ Old (v1.x):

{
"error": true,
"message": "Failed"
}

✅ New (v2.0):

{
"error": "Rate limit exceeded",
"message": "Too many events from this email. Maximum 1 reward per event type per day per user.",
"details": ["Additional context"]
}

Migration:

// ❌ Old
if (response.error) {
console.log(response.message);
}

// ✅ New
if (response.error) {
console.log(`${response.error}: ${response.message}`);
if (response.details) {
console.log('Details:', response.details);
}
}

4. Gas Relayer Authentication

❌ Old (v1.x):

// Used API key
headers: {
'X-API-Key': 'your-api-key'
}

✅ New (v2.0):

// Uses Privy token
const token = await privy.getAccessToken();
headers: {
'Authorization': `Bearer ${token}`
}

Migration:

// ❌ Old
async function executeTransaction(txData) {
const response = await fetch('https://relayer.loyalteez.app/relay', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.API_KEY
},
body: JSON.stringify(txData)
});
}

// ✅ New
async function executeTransaction(txData) {
const token = await privy.getAccessToken();
const response = await fetch('https://relayer.loyalteez.app/relay', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(txData)
});
}

Non-Breaking Changes

These changes are backward compatible but recommended:

1. Event Name Mapping

New Feature (v2.0):

LoyalteezAutomation.init('your-brand-id', {
eventNameMapping: {
'newsletter_signup': 'newsletter_subscribe',
'user_registered': 'account_creation'
}
});

Migration (Optional):

// Instead of manually mapping in your code:
let eventType = detectedEventType;
if (eventType === 'newsletter_signup') {
eventType = 'newsletter_subscribe';
}
LoyalteezAutomation.track(eventType, data);

// Use built-in mapping:
LoyalteezAutomation.init('your-brand-id', {
eventNameMapping: {
'newsletter_signup': 'newsletter_subscribe'
}
});
LoyalteezAutomation.track('newsletter_signup', data); // Auto-mapped

2. OAuth Pregeneration

New Feature (v2.0):

Create wallets before user login:

// New endpoint
const response = await fetch(
'https://register.loyalteez.app/loyalteez-api/pregenerate-user',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brand_id: 'your-brand-id',
oauth_provider: 'discord',
oauth_user_id: discordUserId,
oauth_username: discordUsername
})
}
);

const { wallet_address, created_new } = await response.json();

No migration needed - This is a new feature.


3. Reward Toast Notifications

New Feature (v2.0):

SDK now automatically shows toast notifications when rewards are earned.

Customize:

// Override default toast
LoyalteezAutomation.showRewardToast = function(amount, eventType, userEmail) {
// Your custom notification logic
alert(`You earned ${amount} LTZ!`);
};

Migration Steps

Step 1: Update SDK

If using CDN:

<!-- ❌ Old -->
<script src="https://api.loyalteez.app/sdk.js?v=1"></script>

<!-- ✅ New -->
<script src="https://api.loyalteez.app/sdk.js"></script>

If using npm (future):

npm update @loyalteez/sdk

Step 2: Update Initialization

// ❌ Old
LoyalteezAutomation.init({
brand: 'your-brand-id',
apiEndpoint: 'https://api.loyalteez.app',
debug: true
});

// ✅ New
LoyalteezAutomation.init('your-brand-id', {
endpoint: 'https://api.loyalteez.app',
debug: true
});

Step 3: Update Response Handling

// ❌ Old
async function trackEvent(eventType, userEmail) {
const response = await fetch(...);
const { event_id, reward } = await response.json();
console.log(`Event ${event_id}: ${reward} LTZ`);
}

// ✅ New
async function trackEvent(eventType, userEmail) {
const response = await fetch(...);
const { eventId, rewardAmount, walletAddress } = await response.json();
console.log(`Event ${eventId}: ${rewardAmount} LTZ to ${walletAddress}`);
}

Step 4: Update Error Handling

// ❌ Old
try {
await trackEvent(...);
} catch (error) {
console.error(error.message);
}

// ✅ New
try {
await trackEvent(...);
} catch (error) {
console.error(`${error.error}: ${error.message}`);

// Handle specific errors
if (error.status === 429) {
// Rate limited
} else if (error.status === 403) {
// Automation disabled
}
}

Step 5: Update Gas Relayer Calls

// ❌ Old
async function relayTransaction(txData) {
await fetch('https://relayer.loyalteez.app/relay', {
headers: {
'X-API-Key': apiKey
},
body: JSON.stringify(txData)
});
}

// ✅ New
async function relayTransaction(txData) {
const token = await privy.getAccessToken();
await fetch('https://relayer.loyalteez.app/relay', {
headers: {
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(txData)
});
}

Step 6: Test Thoroughly

Run through these tests:

  1. ✅ Event tracking works
  2. ✅ Error handling works
  3. ✅ Rate limiting works
  4. ✅ Gas relayer works (if used)
  5. ✅ Toast notifications appear
  6. ✅ Wallet creation works

Automated Migration Script

migrate-v1-to-v2.js:

#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

function migrateFile(filePath) {
let content = fs.readFileSync(filePath, 'utf8');

// Update SDK initialization
content = content.replace(
/LoyalteezAutomation\.init\(\{[\s\S]*?brand:\s*['"]([^'"]+)['"][\s\S]*?\}\)/g,
(match, brandId) => {
return `LoyalteezAutomation.init('${brandId}', {\n endpoint: 'https://api.loyalteez.app',\n debug: true\n})`;
}
);

// Update response property names
content = content.replace(/\.event_id\b/g, '.eventId');
content = content.replace(/\.reward\b/g, '.rewardAmount');

// Update Gas Relayer auth
content = content.replace(
/'X-API-Key':\s*[^,\}]+/g,
"'Authorization': `Bearer ${token}`"
);

fs.writeFileSync(filePath, content);
console.log(`✅ Migrated: ${filePath}`);
}

// Find and migrate all JS files
function migrateDirectory(dir) {
const files = fs.readdirSync(dir);

for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);

if (stat.isDirectory()) {
if (!file.startsWith('.') && file !== 'node_modules') {
migrateDirectory(filePath);
}
} else if (file.endsWith('.js') || file.endsWith('.jsx')) {
migrateFile(filePath);
}
}
}

// Run migration
migrateDirectory(process.cwd());
console.log('🎉 Migration complete!');

Usage:

node migrate-v1-to-v2.js

Rollback Plan

If you encounter issues after upgrading:

Quick Rollback (CDN)

<!-- Rollback to v1 -->
<script src="https://api.loyalteez.app/sdk.js?v=1"></script>

Full Rollback (npm)

# Rollback SDK
npm install @loyalteez/[email protected]

# Revert code changes
git revert HEAD

Getting Help

Migration Support

Having trouble migrating?

  1. 📖 Check our Migration Checklist
  2. 💬 Ask in Discord #migrations
  3. 📧 Email: [email protected] (include "Migration v2" in subject)

Report Issues

Found a bug after migrating?

  1. 🐛 Check Known Issues
  2. 📋 File issue: [email protected]
  3. Include:
    • Version migrating from/to
    • Error messages
    • Code snippets
    • Browser/environment details

Known Issues

Issue: Toast Not Showing

Cause: Custom CSS conflicting with toast styles

Fix:

// Override toast styles
LoyalteezAutomation.showRewardToast = function(amount, eventType, userEmail) {
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed !important;
z-index: 999999 !important;
/* ... rest of styles */
`;
// ... rest of implementation
};

Issue: Rate Limit Errors After Upgrade

Cause: v2 has stricter deduplication (2s window)

Fix: This is expected behavior. The SDK prevents duplicate events more aggressively.

// If you need to retry sooner:
setTimeout(() => {
LoyalteezAutomation.track(eventType, data);
}, 2500); // Wait 2.5s

Issue: Privy Token Errors

Cause: Token expired or not refreshed

Fix:

// Always get fresh token
const token = await privy.getAccessToken();

// Don't cache tokens

Best Practices

1. Test in Staging First

// Use staging Brand ID
const BRAND_ID = process.env.NODE_ENV === 'production'
? 'prod_brand_id'
: 'staging_brand_id';

LoyalteezAutomation.init(BRAND_ID, options);

2. Gradual Rollout

// Feature flag
const USE_V2 = localStorage.getItem('loyalteez_v2') === 'true';

if (USE_V2) {
// Use v2 format
} else {
// Use v1 format
}

3. Monitor Errors

// Track migration errors
try {
await LoyalteezAutomation.track(eventType, data);
} catch (error) {
// Log to monitoring service
Sentry.captureException(error, {
tags: { version: 'v2', migration: true }
});
}

Current Feature Set

v2.0 includes all production-ready features:

FeatureStatus
Event Tracking
Auto-Detection
Gas Relayer
OAuth Pregeneration
Idempotent APIs
Toast Notifications
EIP-2612 Permits
TypeScript Definitions
Enhanced Error Messages


Questions? Join our Discord or email [email protected]