Skip to main content

Scores & Leaderboard

The contributor scoring API exposes leaderboard data and individual user scores. Scores are computed by the civicpulse-score-v1 algorithm and reflect a contributor's civic activity over time.

See Scoring Algorithm for the full weight table, tier definitions, and badge criteria.


GET /api/scores​

Retrieve the contributor leaderboard. No authentication required.

Query parameters:

ParameterTypeDefaultDescription
citystringβ€”Filter leaderboard to contributors from a specific city
limitnumber50Number of entries to return (1–100)
formatstringfullfull or minimal β€” minimal omits breakdown and badges

Request:

GET /api/scores?city=bangalore&limit=10

Response β€” 200 OK (full format):

{
"success": true,
"data": {
"count": 10,
"algorithm": "civicpulse-score-v1",
"generatedAt": "2025-01-15T10:30:00.000Z",
"items": [
{
"rank": 1,
"userId": "usr_01HN...",
"displayName": "Priya S.",
"avatarUrl": "https://lh3.googleusercontent.com/...",
"city": "bangalore",
"score": 1240,
"tier": "Legend",
"badges": ["Pioneer", "Community Voice", "Problem Solver", "Legend"],
"breakdown": {
"reportsField": 8,
"reportsResolved": 4,
"upvotesReceived": 210,
"imagesAdded": 12,
"videosAdded": 3,
"highPriorityBonus": 5,
"votesCast": 89,
"commentsMade": 44,
"eventsJoined": 6,
"streakBonus": 2,
"categoryBonus": 4
}
}
]
}
}

Request with minimal format:

GET /api/scores?limit=100&format=minimal

Response β€” 200 OK (minimal format):

{
"success": true,
"data": {
"count": 100,
"algorithm": "civicpulse-score-v1",
"generatedAt": "2025-01-15T10:30:00.000Z",
"items": [
{
"rank": 1,
"userId": "usr_01HN...",
"displayName": "Priya S.",
"city": "bangalore",
"score": 1240,
"tier": "Legend"
}
]
}
}

The minimal format is suitable for rendering compact leaderboard tables or maps without the overhead of badge and breakdown data.


GET /api/scores/:userId​

Retrieve the score and rank for a specific user. No authentication required.

Request:

GET /api/scores/usr_01HN...

Response β€” 200 OK:

{
"success": true,
"data": {
"userId": "usr_01HN...",
"displayName": "Priya S.",
"avatarUrl": "https://lh3.googleusercontent.com/...",
"city": "bangalore",
"score": 1240,
"tier": "Legend",
"rank": 1,
"globalRank": 7,
"badges": [
{
"id": "Pioneer",
"displayName": "Pioneer",
"description": "One of the first 100 reporters on the platform",
"earnedAt": "2025-01-01T00:00:00.000Z"
},
{
"id": "Community Voice",
"displayName": "Community Voice",
"description": "Received 100+ upvotes across all reported issues",
"earnedAt": "2025-01-10T14:22:00.000Z"
},
{
"id": "Problem Solver",
"displayName": "Problem Solver",
"description": "Had 5+ reported issues resolved",
"earnedAt": "2025-01-12T09:00:00.000Z"
},
{
"id": "Legend",
"displayName": "Legend",
"description": "Reached Legend tier (600+ points)",
"earnedAt": "2025-01-14T17:45:00.000Z"
}
],
"breakdown": {
"reportsField": 8,
"reportsResolved": 4,
"upvotesReceived": 210,
"imagesAdded": 12,
"videosAdded": 3,
"highPriorityBonus": 5,
"votesCast": 89,
"commentsMade": 44,
"eventsJoined": 6,
"streakBonus": 2,
"categoryBonus": 4
},
"algorithm": "civicpulse-score-v1",
"shareUrl": "https://civicpulse.in/contributors/usr_01HN...",
"computedAt": "2025-01-15T10:30:00.000Z"
}
}

Response β€” 404 (user not found or no activity):

{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "User not found or has no contribution score"
}
}

Score Payload Field Reference​

FieldTypeDescription
userIdstringUnique user identifier
displayNamestringUser's display name
citystringUser's registered city
scorenumberTotal computed score
tierstringCitizen, Contributor, Champion, or Legend
ranknumberRank within the user's city
globalRanknumberRank across all cities (only in /api/scores/:userId)
badgesarrayList of earned badge objects
breakdownobjectPer-action point breakdown (omitted in minimal format)
algorithmstringScore algorithm version β€” currently civicpulse-score-v1
shareUrlstringPublic shareable URL for this contributor's profile
computedAtstringISO 8601 timestamp when the score was last computed

Breakdown Fields​

The breakdown object maps each scoring action to the number of times it has been credited (not the point value β€” multiply by the weight to get the contribution):

FieldWeight per occurrenceDescription
reportsField50 ptsIssues reported
reportsResolved100 ptsReported issues that reached resolved status
upvotesReceived2 ptsUpvotes received on all reported issues
imagesAdded15 ptsImages attached to issues
videosAdded25 ptsVideos attached to issues
highPriorityBonus30 ptsHigh-priority issues reported
votesCast5 ptsIssues upvoted by this user
commentsMade3 ptsMessages posted in issue threads
eventsJoined20 ptsCommunity impact events joined
streakBonus50 ptsWeekly activity streaks completed
categoryBonus10 ptsActivity across multiple categories

See Scoring Algorithm for the complete algorithm specification, tier thresholds, and badge criteria.