Streak Service API Reference
The Streak Service manages user activity streaks for daily check-ins and other activities across all platform integrations. It provides consistent streak tracking with multipliers, milestones, and grace periods.
Base URL
https://services.loyalteez.app
Endpoints
Record Activity
Records a user's activity and extends their streak. This is the main entry point for all platforms when users perform daily check-ins or other streak-tracked activities.
Endpoint: POST /streak/record-activity
Request Body:
{
"brandId": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"userIdentifier": "[email protected]",
"platform": "discord",
"streakType": "daily"
}
Parameters:
brandId(required): The brand's wallet addressuserIdentifier(required): User identifier in format{platform}_{id}@loyalteez.appplatform(required): Platform name (discord,telegram,twitter,farcaster,shopify,wordpress)streakType(optional): Type of streak, defaults to"daily"
Response:
{
"success": true,
"isNewActivity": true,
"wasNew": false,
"previousStreak": 0,
"currentStreak": 5,
"multiplier": 1.5,
"totalStreakDays": 5,
"unclaimedMilestones": [
{ "days": 7, "bonus": 100 }
],
"message": "Day 5 streak!"
}
Response Fields:
success: Whether the operation succeededisNewActivity: Whether this was a new activity (true) or user already checked in today (false)wasNew: Whether streak was reset (true) or continued (false)previousStreak: Previous streak length (if reset)currentStreak: Current streak lengthmultiplier: Reward multiplier based on streak lengthtotalStreakDays: Total days user has maintained streaksunclaimedMilestones: Array of milestone bonuses available to claimmessage: Human-readable status message
Example:
const response = await fetch('https://services.loyalteez.app/streak/record-activity', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brandId: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
userIdentifier: '[email protected]',
platform: 'discord',
streakType: 'daily'
})
});
const result = await response.json();
console.log(`Current streak: ${result.currentStreak} days`);
console.log(`Reward multiplier: ${result.multiplier}x`);
Claim Milestone
Claims a milestone bonus when a user reaches a streak milestone (e.g., 7 days, 30 days).
Endpoint: POST /streak/claim-milestone
Request Body:
{
"brandId": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"userIdentifier": "[email protected]",
"platform": "discord",
"milestoneDays": 7,
"streakType": "daily"
}
Parameters:
brandId(required): The brand's wallet addressuserIdentifier(required): User identifierplatform(required): Platform namemilestoneDays(required): Milestone to claim (e.g., 7, 30, 100, 365)streakType(optional): Type of streak, defaults to"daily"
Response:
{
"success": true,
"bonus": 100,
"bonusLtz": 100,
"milestone": 7,
"streak": 10
}
Error Response:
{
"success": false,
"reason": "streak_too_short",
"required": 7,
"current": 5
}
Error Reasons:
streak_too_short: User hasn't reached the milestone yetalready_claimed: Milestone was already claimedinvalid_milestone: Milestone doesn't exist in configuration
Example:
const response = await fetch('https://services.loyalteez.app/streak/claim-milestone', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brandId: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
userIdentifier: '[email protected]',
platform: 'discord',
milestoneDays: 7,
streakType: 'daily'
})
});
const result = await response.json();
if (result.success) {
console.log(`Claimed ${result.milestone}-day milestone! +${result.bonus} LTZ`);
} else {
console.log(`Cannot claim: ${result.reason}`);
}
Get Status
Retrieves a user's current streak status, including current streak, multiplier, unclaimed milestones, and next milestone.
Endpoint: GET /streak/status/:brandId/:userIdentifier?streakType=daily
URL Parameters:
brandId(path): The brand's wallet addressuserIdentifier(path): User identifier (URL-encoded)streakType(query, optional): Type of streak, defaults to"daily"
Response:
{
"currentStreak": 5,
"longestStreak": 10,
"multiplier": 1.5,
"nextMilestone": {
"days": 7,
"bonus": 100
},
"daysToNextMilestone": 2,
"unclaimedMilestones": [],
"checkedInToday": true,
"lastActivityAt": "2024-01-15T10:30:00.000Z"
}
Response Fields:
currentStreak: Current streak lengthlongestStreak: Longest streak the user has achievedmultiplier: Current reward multipliernextMilestone: Next milestone details (days and bonus)daysToNextMilestone: Days until next milestoneunclaimedMilestones: Array of unclaimed milestone bonusescheckedInToday: Whether user has checked in todaylastActivityAt: ISO timestamp of last activity
Example:
const brandId = encodeURIComponent('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
const userIdentifier = encodeURIComponent('[email protected]');
const response = await fetch(
`https://services.loyalteez.app/streak/status/${brandId}/${userIdentifier}?streakType=daily`
);
const status = await response.json();
console.log(`Current streak: ${status.currentStreak} days`);
console.log(`Next milestone: ${status.daysToNextMilestone} days (${status.nextMilestone.bonus} LTZ)`);
Streak Configuration
Streak behavior is configurable per brand through the Partner Portal. Default configuration:
Default Multipliers:
- 3-day streak: 1.25x
- 7-day streak: 1.5x
- 14-day streak: 1.75x
- 30-day streak: 2.0x
Default Milestones:
- 7 days: +100 LTZ
- 30 days: +500 LTZ
- 100 days: +2000 LTZ
- 365 days: +10000 LTZ
Grace Period:
- Default: 36 hours
- Users have 36 hours to maintain their streak before it resets
How Streaks Work
- First Activity: User's first activity starts a 1-day streak
- Continuing Streak: If user checks in within the grace period, streak increments
- Streak Reset: If user doesn't check in within grace period, streak resets to 1
- Multipliers: Longer streaks unlock higher reward multipliers
- Milestones: Users can claim bonus LTZ at milestone points (7, 30, 100, 365 days)
Error Handling
All endpoints return standard error responses:
{
"success": false,
"error": "Error message"
}
Common Errors:
400 Bad Request: Missing required fields or invalid parameters404 Not Found: Invalid endpoint or user not found500 Internal Server Error: Server error
Integration Examples
Discord Bot
// Daily check-in command
async function handleDailyCheckin(userId, brandId) {
const userIdentifier = `discord_${userId}@loyalteez.app`;
const response = await fetch('https://services.loyalteez.app/streak/record-activity', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brandId,
userIdentifier,
platform: 'discord',
streakType: 'daily'
})
});
const result = await response.json();
return result;
}
Telegram Bot
// /daily command
async function handleDaily(message, env) {
const userId = message.from.id;
const userIdentifier = `telegram_${userId}@loyalteez.app`;
const brandId = env.BRAND_ID;
const response = await fetch('https://services.loyalteez.app/streak/record-activity', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brandId,
userIdentifier,
platform: 'telegram',
streakType: 'daily'
})
});
const result = await response.json();
if (result.isNewActivity) {
bot.sendMessage(message.chat.id,
`🔥 Day ${result.currentStreak} streak! ` +
`Multiplier: ${result.multiplier}x`
);
} else {
bot.sendMessage(message.chat.id, 'Already checked in today! ✅');
}
}
Web Application
// Daily check-in button
async function checkInDaily(userEmail, brandId) {
const response = await fetch('https://services.loyalteez.app/streak/record-activity', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brandId,
userIdentifier: userEmail, // Direct email for web apps
platform: 'web',
streakType: 'daily'
})
});
const result = await response.json();
if (result.success) {
showNotification(`Day ${result.currentStreak} streak! ${result.multiplier}x multiplier`);
// Show unclaimed milestones
if (result.unclaimedMilestones.length > 0) {
showMilestoneAlert(result.unclaimedMilestones);
}
}
}
Best Practices
- Call on Check-in: Call
/streak/record-activitywhen users perform daily check-ins - Check Status First: Use
/streak/statusto show users their current streak before check-in - Claim Milestones: Prompt users to claim milestone bonuses when available
- Handle Grace Period: Users can maintain streaks with up to 36 hours between check-ins
- Cache Responses: Cache streak status to reduce API calls, but refresh on check-in
- Error Handling: Always handle errors gracefully and provide user feedback