Parent: #877
Depends on: #878, #879
Scope
REST API endpoints for the airdrop page to consume.
Endpoints
GET /api/airdrop/status
Campaign status overview (no auth required).
Response:
{
"campaignStart": "2026-XX-XX",
"campaignEnd": "2026-XX-XX",
"timeRemainingDays": 142,
"timeElapsedPercent": 38,
"poolAmount": 50000,
"currentMcap": 45000,
"latestPriceUsd": 0.00015,
"milestones": {
"bronze": { "mcap": 1000000, "pct": 10, "reached": false },
"silver": { "mcap": 10000000, "pct": 30, "reached": false },
"gold": { "mcap": 70000000, "pct": 100, "reached": false }
},
"totalPointsEarned": 54200,
"totalParticipants": 128,
"lockerId": 123
}
GET /api/airdrop/points?address=0x...
User's point breakdown + streak info.
Response:
{
"address": "0x...",
"totalPoints": 1250,
"sharePercent": 2.3,
"breakdown": {
"buy": 800,
"referral": 350,
"write": 100,
"rate": 0
},
"streak": {
"currentStreak": 32,
"boostPercent": 20,
"nextTier": { "days": 50, "boost": 30 },
"checkedInToday": true,
"lastCheckin": "2026-XX-XX"
},
"referral": {
"code": "project7",
"isFarcasterUsername": true,
"referredBy": "alice",
"referredUsersCount": 5
},
"estimatedAirdrop": {
"bronze": 115,
"silver": 345,
"gold": 1150
}
}
GET /api/airdrop/leaderboard
Top 50 by total points.
Response:
{
"entries": [
{ "rank": 1, "address": "0x...", "username": "project7", "totalPoints": 5200, "sharePercent": 9.6 },
...
],
"userRank": 12
}
Query param: address (optional) — to include user's own rank if not in top 50.
GET /api/airdrop/snapshots
Weekly snapshot history.
Response:
{
"snapshots": [
{
"weekNumber": 8,
"weekStart": "2026-04-14",
"newStories": 12,
"tokenBuys": 340,
"newReferrals": 28,
"mcapStart": 45000,
"mcapEnd": 52000,
"totalPlEarned": 4200
},
...
]
}
Files
src/app/api/airdrop/status/route.ts
src/app/api/airdrop/points/route.ts
src/app/api/airdrop/leaderboard/route.ts
src/app/api/airdrop/snapshots/route.ts
Acceptance Criteria
Parent: #877
Depends on: #878, #879
Scope
REST API endpoints for the airdrop page to consume.
Endpoints
GET /api/airdrop/statusCampaign status overview (no auth required).
Response:
{ "campaignStart": "2026-XX-XX", "campaignEnd": "2026-XX-XX", "timeRemainingDays": 142, "timeElapsedPercent": 38, "poolAmount": 50000, "currentMcap": 45000, "latestPriceUsd": 0.00015, "milestones": { "bronze": { "mcap": 1000000, "pct": 10, "reached": false }, "silver": { "mcap": 10000000, "pct": 30, "reached": false }, "gold": { "mcap": 70000000, "pct": 100, "reached": false } }, "totalPointsEarned": 54200, "totalParticipants": 128, "lockerId": 123 }GET /api/airdrop/points?address=0x...User's point breakdown + streak info.
Response:
{ "address": "0x...", "totalPoints": 1250, "sharePercent": 2.3, "breakdown": { "buy": 800, "referral": 350, "write": 100, "rate": 0 }, "streak": { "currentStreak": 32, "boostPercent": 20, "nextTier": { "days": 50, "boost": 30 }, "checkedInToday": true, "lastCheckin": "2026-XX-XX" }, "referral": { "code": "project7", "isFarcasterUsername": true, "referredBy": "alice", "referredUsersCount": 5 }, "estimatedAirdrop": { "bronze": 115, "silver": 345, "gold": 1150 } }GET /api/airdrop/leaderboardTop 50 by total points.
Response:
{ "entries": [ { "rank": 1, "address": "0x...", "username": "project7", "totalPoints": 5200, "sharePercent": 9.6 }, ... ], "userRank": 12 }Query param:
address(optional) — to include user's own rank if not in top 50.GET /api/airdrop/snapshotsWeekly snapshot history.
Response:
{ "snapshots": [ { "weekNumber": 8, "weekStart": "2026-04-14", "newStories": 12, "tokenBuys": 340, "newReferrals": 28, "mcapStart": 45000, "mcapEnd": 52000, "totalPlEarned": 4200 }, ... ] }Files
src/app/api/airdrop/status/route.tssrc/app/api/airdrop/points/route.tssrc/app/api/airdrop/leaderboard/route.tssrc/app/api/airdrop/snapshots/route.tsAcceptance Criteria
/pointsincludes streak info and referral info/leaderboardreturns top 50 sorted by total points/leaderboardincludes requesting user's rank ifaddressparam provided/statusincludes current mcap from latestpl_daily_prices