Skip to main content
GET
https://api-mainnet.onzks.com
/
v1
/
achievements
/
:identity
Get User Achievements
curl --request GET \
  --url https://api-mainnet.onzks.com/v1/achievements/:identity \
  --header 'Authorization: Bearer <token>'
{
  "success": true,
  "address": "<string>",
  "zksId": "<string>",
  "achievements": [
    {
      "id": "<string>",
      "title": "<string>",
      "description": "<string>",
      "category": "<string>",
      "rarity": "<string>",
      "points": 123,
      "scoreBonus": 123,
      "icon": "<string>",
      "earned": true,
      "earnedAt": "<string>",
      "progress": {
        "current": 123,
        "required": 123,
        "percentage": 123,
        "requirements": {}
      }
    }
  ],
  "claimableAchievements": [
    {}
  ],
  "claimableCount": 123,
  "summary": {
    "totalEarned": 123,
    "totalPoints": 123,
    "totalScoreBonus": 123,
    "rarityBreakdown": {},
    "categoryBreakdown": {}
  },
  "timestamp": "<string>"
}

Overview

Retrieve all achievements that have been earned by a specific user. This endpoint returns both earned achievements and progress toward unearned ones, making it perfect for building user profiles and achievement galleries.
Use this endpoint to display a user’s achievement collection, show their progress, and highlight their accomplishments.

Parameters

identity
string
required
User identity (ZKS ID or wallet address)
ZKS ID is recommended for better performance and user experience
category
string
Filter by achievement category
  • wallet_age - Wallet longevity achievements
  • transaction_volume - Volume-based achievements
  • protocol_usage - Protocol interaction achievements
  • governance - DAO participation achievements
  • social - Social reputation achievements
  • defi - DeFi-specific achievements
  • nft - NFT-related achievements
  • trading - Trading achievements
status
string
Filter by achievement status
  • earned - Only earned achievements
  • in_progress - Only achievements in progress
  • all - Both earned and in progress (default)
rarity
string
Filter by rarity level
  • common - Easy to earn
  • uncommon - Moderate difficulty
  • rare - Challenging
  • epic - Very challenging
  • legendary - Extremely rare
limit
number
Number of results to return (default: 50, max: 100)
offset
number
Number of results to skip for pagination (default: 0)

Response

success
boolean
Indicates if the request was successful
address
string
Resolved wallet address
zksId
string
ZKS ID if available, null otherwise
achievements
array
Array of user achievement objects
claimableAchievements
array
Array of achievements ready to be claimed
claimableCount
number
Number of achievements ready to be claimed
summary
object
Achievement summary statistics
timestamp
string
ISO 8601 timestamp of the response

Examples

curl "https://api.onzks.com/v1/achievements/alice.zks" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Example

{
  "success": true,
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "zksId": "alice.zks",
  "achievements": [
    {
      "id": "defi-pioneer",
      "title": "DeFi Pioneer",
      "description": "Interact with 50+ different DeFi protocols across multiple chains",
      "category": "defi",
      "rarity": "legendary",
      "points": 5000,
      "scoreBonus": 500,
      "icon": "https://cdn.onzks.com/achievements/defi-pioneer.png",
      "earned": true,
      "earnedAt": "2024-01-15T10:30:00Z",
      "progress": null
    },
    {
      "id": "whale-trader",
      "title": "Whale Trader",
      "description": "Execute a single transaction worth over $1M",
      "category": "trading",
      "rarity": "epic",
      "points": 3000,
      "scoreBonus": 300,
      "icon": "https://cdn.onzks.com/achievements/whale-trader.png",
      "earned": false,
      "earnedAt": null,
      "progress": {
        "current": 750000,
        "required": 1000000,
        "percentage": 75,
        "requirements": {
          "singleTransactionValue": "1000000",
          "currentMax": "750000"
        }
      }
    },
    {
      "id": "governance-guru",
      "title": "Governance Guru",
      "description": "Vote on 100+ DAO proposals",
      "category": "governance",
      "rarity": "rare",
      "points": 2000,
      "scoreBonus": 200,
      "icon": "https://cdn.onzks.com/achievements/governance-guru.png",
      "earned": true,
      "earnedAt": "2024-01-10T14:20:00Z",
      "progress": null
    }
  ],
  "claimableAchievements": [
    {
      "id": "defi-pioneer",
      "title": "DeFi Pioneer",
      "points": 5000,
      "scoreBonus": 500
    }
  ],
  "claimableCount": 1,
  "summary": {
    "totalEarned": 2,
    "totalPoints": 7000,
    "totalScoreBonus": 700,
    "rarityBreakdown": {
      "legendary": 1,
      "epic": 0,
      "rare": 1,
      "uncommon": 0,
      "common": 0
    },
    "categoryBreakdown": {
      "defi": 1,
      "governance": 1,
      "trading": 0,
      "social": 0,
      "nft": 0,
      "wallet_age": 0,
      "transaction_volume": 0,
      "protocol_usage": 0
    }
  },
  "timestamp": "2024-01-20T15:45:00Z"
}

Use Cases

Display a user’s achievement collection:
async function displayUserAchievements(identity) {
  const data = await getUserAchievements(identity);

  console.log(`\n🏆 ${data.zksId || data.address}'s Achievements`);
  console.log(`Total: ${data.summary.totalEarned} earned, ${data.claimableCount} claimable`);
  console.log(`Points: ${data.summary.totalPoints}, Score Bonus: ${data.summary.totalScoreBonus}\n`);

  // Group by category
  const byCategory = data.achievements.reduce((acc, achievement) => {
    if (!acc[achievement.category]) {
      acc[achievement.category] = { earned: [], inProgress: [] };
    }
    
    if (achievement.earned) {
      acc[achievement.category].earned.push(achievement);
    } else {
      acc[achievement.category].inProgress.push(achievement);
    }
    
    return acc;
  }, {});

  // Display by category
  Object.entries(byCategory).forEach(([category, achievements]) => {
    console.log(`\n📂 ${category.toUpperCase()}:`);
    
    if (achievements.earned.length > 0) {
      console.log('  ✅ Earned:');
      achievements.earned.forEach(achievement => {
        console.log(`    ${achievement.title} (${achievement.rarity}) - ${achievement.points} points`);
      });
    }
    
    if (achievements.inProgress.length > 0) {
      console.log('  🔄 In Progress:');
      achievements.inProgress.forEach(achievement => {
        console.log(`    ${achievement.title} - ${achievement.progress.percentage}% complete`);
      });
    }
  });
}

2. Achievement Progress Tracking

Track progress toward specific achievements:
async function trackAchievementProgress(identity, achievementId) {
  const data = await getUserAchievements(identity);
  
  const achievement = data.achievements.find(a => a.id === achievementId);
  
  if (!achievement) {
    console.log('Achievement not found');
    return;
  }
  
  if (achievement.earned) {
    console.log(`✅ ${achievement.title} - Earned on ${new Date(achievement.earnedAt).toLocaleDateString()}`);
  } else {
    console.log(`🔄 ${achievement.title}`);
    console.log(`Progress: ${achievement.progress.current}/${achievement.progress.required} (${achievement.progress.percentage}%)`);
    
    if (achievement.progress.requirements) {
      console.log('Requirements:');
      Object.entries(achievement.progress.requirements).forEach(([key, value]) => {
        console.log(`  ${key}: ${value}`);
      });
    }
  }
}

3. Claimable Achievements Notification

Show achievements ready to be claimed:
async function getClaimableAchievements(identity) {
  const data = await getUserAchievements(identity);
  
  if (data.claimableCount === 0) {
    console.log('No achievements ready to claim');
    return;
  }
  
  console.log(`🎉 ${data.claimableCount} achievements ready to claim!`);
  
  data.claimableAchievements.forEach(achievement => {
    console.log(`- ${achievement.title}: ${achievement.points} points, ${achievement.scoreBonus} score bonus`);
  });
  
  return data.claimableAchievements;
}

4. Achievement Statistics

Show detailed achievement statistics:
async function getAchievementStats(identity) {
  const data = await getUserAchievements(identity);
  const summary = data.summary;
  
  console.log(`\n📊 Achievement Statistics for ${data.zksId || data.address}`);
  console.log(`Total Earned: ${summary.totalEarned}`);
  console.log(`Total Points: ${summary.totalPoints.toLocaleString()}`);
  console.log(`Score Bonus: ${summary.totalScoreBonus}`);
  console.log(`Claimable: ${data.claimableCount}\n`);
  
  console.log('Rarity Breakdown:');
  Object.entries(summary.rarityBreakdown).forEach(([rarity, count]) => {
    if (count > 0) {
      console.log(`  ${rarity}: ${count}`);
    }
  });
  
  console.log('\nCategory Breakdown:');
  Object.entries(summary.categoryBreakdown).forEach(([category, count]) => {
    if (count > 0) {
      console.log(`  ${category}: ${count}`);
    }
  });
}

Best Practices

1. Cache User Achievements

User achievements don’t change frequently:
let userAchievementCache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedUserAchievements(identity, filters = {}) {
  const cacheKey = `${identity}-${JSON.stringify(filters)}`;
  const cached = userAchievementCache.get(cacheKey);
  
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }
  
  const data = await getUserAchievements(identity, filters);
  userAchievementCache.set(cacheKey, {
    data,
    timestamp: Date.now()
  });
  
  return data;
}

2. Filter by Status

Optimize queries by filtering status:
// Get only earned achievements
const earnedAchievements = await getUserAchievements(identity, { status: 'earned' });

// Get only achievements in progress
const inProgressAchievements = await getUserAchievements(identity, { status: 'in_progress' });

3. Paginate Large Results

Handle users with many achievements:
async function getAllUserAchievements(identity, filters = {}) {
  const allAchievements = [];
  let offset = 0;
  const limit = 50;
  
  while (true) {
    const data = await getUserAchievements(identity, {
      ...filters,
      limit,
      offset
    });
    
    allAchievements.push(...data.achievements);
    
    if (data.achievements.length < limit) {
      break;
    }
    
    offset += limit;
  }
  
  return allAchievements;
}

4. Real-time Updates

Subscribe to achievement updates:
function subscribeToAchievementUpdates(identity, callback) {
  // WebSocket connection for real-time updates
  const ws = new WebSocket(`wss://api.onzks.com/v1/achievements/${identity}/subscribe`);
  
  ws.onmessage = (event) => {
    const update = JSON.parse(event.data);
    callback(update);
  };
  
  return () => ws.close();
}

// Usage
const unsubscribe = subscribeToAchievementUpdates('alice.zks', (update) => {
  console.log('New achievement earned:', update.achievement.title);
});

Troubleshooting

”User not found”

Cause: Invalid identity or user doesn’t exist. Solution:
  • Verify the identity format (ZKS ID or wallet address)
  • Check if the user has any activity on the platform
  • Try with a different identity

”No achievements found”

Cause: User has no achievements or filters are too restrictive. Solution:
  • Remove filters to see all achievements
  • Check if user has any platform activity
  • Verify achievement categories exist

”Invalid status filter”

Cause: Unsupported status value. Solution:
  • Use supported statuses: earned, in_progress, all
  • Check for typos in filter values

Rate Limits

User achievement requests are subject to rate limits:
  • Free tier: 60 requests per minute
  • Starter tier: 300 requests per minute
  • Professional tier: 1,000 requests per minute
  • Enterprise tier: Custom limits
Implement caching to reduce API calls.