Skip to main content

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 address
  • userIdentifier (required): User identifier in format {platform}_{id}@loyalteez.app
  • platform (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 succeeded
  • isNewActivity: 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 length
  • multiplier: Reward multiplier based on streak length
  • totalStreakDays: Total days user has maintained streaks
  • unclaimedMilestones: Array of milestone bonuses available to claim
  • message: 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 address
  • userIdentifier (required): User identifier
  • platform (required): Platform name
  • milestoneDays (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 yet
  • already_claimed: Milestone was already claimed
  • invalid_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 address
  • userIdentifier (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 length
  • longestStreak: Longest streak the user has achieved
  • multiplier: Current reward multiplier
  • nextMilestone: Next milestone details (days and bonus)
  • daysToNextMilestone: Days until next milestone
  • unclaimedMilestones: Array of unclaimed milestone bonuses
  • checkedInToday: Whether user has checked in today
  • lastActivityAt: 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

  1. First Activity: User's first activity starts a 1-day streak
  2. Continuing Streak: If user checks in within the grace period, streak increments
  3. Streak Reset: If user doesn't check in within grace period, streak resets to 1
  4. Multipliers: Longer streaks unlock higher reward multipliers
  5. 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 parameters
  • 404 Not Found: Invalid endpoint or user not found
  • 500 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

  1. Call on Check-in: Call /streak/record-activity when users perform daily check-ins
  2. Check Status First: Use /streak/status to show users their current streak before check-in
  3. Claim Milestones: Prompt users to claim milestone bonuses when available
  4. Handle Grace Period: Users can maintain streaks with up to 36 hours between check-ins
  5. Cache Responses: Cache streak status to reduce API calls, but refresh on check-in
  6. Error Handling: Always handle errors gracefully and provide user feedback