Endpoints support GET, POST, PUT, PATCH, and DELETE methods. CORS is open to any origin. Data may be cached by the server and proxies for up to 1 hour; user stats may also be served from a Mongo snapshot up to 60 minutes old.
Protected endpoints require a valid Clerk JWT token in the Authorization header:
Authorization: Bearer <clerk_session_token>
The middleware extracts userId from the verified token and attaches it to req.auth.userId. Endpoints marked with π require authentication; public endpoints marked with π do not.
- Purpose: Return the user's contribution stats for frontend streak display.
- Auth: Optional - uses
req.auth.userIdif authenticated, falls back toidquery param. - Window: Last 365 calendar days (UTC-midnight bounded).
- Response:
{ "username": "github-username", "avatar": "https://github.com/user.png", "currentStreak": { "count": 15, "startDate": "2025-12-20T00:00:00Z" }, "longestStreak": { "count": 45, "startDate": "2025-10-01T00:00:00Z", "endDate": "2025-11-14T00:00:00Z" }, "contributions": 1234, "lastContributionDate": "2026-01-04T00:00:00Z", "contributionDays": [{ "date": "2026-01-04", "count": 5 }], "weeklyStats": { "Sun": 45, "Mon": 120, "Tue": 135, "Wed": 140, "Thu": 125, "Fri": 110, "Sat": 60 }, "monthlyStats": [{ "month": "2026-01", "count": 32 }] } - Errors: 400 if no userId; 500 otherwise.
- Purpose: Manually trigger a GitHub data refresh.
- Rate Limit: 1 sync per user per 5 minutes.
- Request Body:
{ "userId": "clerk_user_id" }(optional if authenticated) - Response:
{ success, message, data: { currentStreak, contributions, lastSyncedAt } } - Errors: 400, 429 (rate limited), 500.
- Purpose: Use a streak freeze token.
- Request Body:
{ "userId": "clerk_user_id" }(optional if authenticated) - Response:
{ success, data: { usedFreezes, availableFreezes, currentStreak, streakRestored } }
- Purpose: Lookup public stats for streak battles.
- Response:
{ success, data: { username, avatarUrl, currentStreak, longestStreak, contributions, isPublic } }
- Purpose: Get public profile data with tier and rank.
- Response:
{ username, avatar, currentStreak, longestStreak, contributions, tier, rank }
- Purpose: Rank up to 100 users by contributions.
- Response:
[{ rank, username, avatar, contributions, currentStreak }]
- Purpose: Create a new squad.
- Request Body:
{ "name": "string", "weeklyGoal": 5|7, "isPrivate": boolean } - Response: Full squad object with generated 6-char invite code.
- Limits: Max 10 members per squad, name max 30 chars.
- Purpose: List public squads.
- Response:
{ squads: [...], total, page, limit, totalPages }
- Purpose: Get user's squads.
- Response: Array of squad objects.
- Purpose: Join squad by invite code (code in body).
- Request Body:
{ "code": "ABC123" } - Errors: INVALID_INVITE_CODE, ALREADY_MEMBER, SQUAD_FULL
- Purpose: Join squad by invite code (code in URL).
- Errors: INVALID_INVITE_CODE, ALREADY_MEMBER, SQUAD_FULL
- Purpose: Leave a squad.
- Note: If leader leaves, new leader is assigned; if empty, squad is deleted.
- Purpose: Get squad details.
- Note: userId required for private squads (via auth or query param).
- Response: Full squad with members, XP multiplier (1 + memberCount * 0.1, max 2.0).
- Purpose: Get available pledge templates.
- Response:
[ { "id": "7-day", "name": "Week Warrior", "days": 7, "reward": "Week Warrior badge", "xpBonus": 100 }, { "id": "30-day", "name": "Monthly Master", "days": 30, "reward": "Monthly Master badge + Freeze Token", "xpBonus": 500 }, { "id": "100-day", "name": "Century Legend", "days": 100, "reward": "Century badge + Profile flair", "xpBonus": 2000 }, { "id": "365-day", "name": "Yearly Champion", "days": 365, "reward": "Yearly Champion title + All badges", "xpBonus": 10000 } ]
- Purpose: Create a new pledge.
- Request Body:
{ "templateId": "7-day|30-day|100-day|365-day" } - Errors: PLEDGE_ALREADY_ACTIVE, TEMPLATE_ALREADY_COMPLETED, INVALID_TEMPLATE
- Purpose: Get user's active and completed pledges.
- Response:
{ active: Pledge|null, completed: ["7-day", "30-day"] }
- Purpose: Get user's active pledge.
- Response: Pledge object or null.
- Purpose: Get user's completed pledge template IDs.
- Response:
["7-day", "30-day"]
- Purpose: Complete pledge and claim rewards.
- Validation: currentStreak >= pledge.targetDays
- Response:
{ xpAwarded, badgeUnlocked, pledge } - Errors: PLEDGE_INCOMPLETE, PLEDGE_NOT_FOUND
- Purpose: Abandon a pledge.
- Purpose: Generate embeddable SVG profile card.
- Themes:
dark,midnight,fire,ocean,forest - Response:
image/svg+xmlwithCache-Control: public, max-age=3600 - Card includes: Avatar, username, streak count, tier badge, contributions, branding.
- Purpose: Alias for
/v1/embed/:username(frontend compatibility).
- Purpose: Generate simple streak badge.
- Styles:
flat,plastic,for-the-badge - Themes:
dark,light
- Purpose: Aggregate GitHub contributors across community repos.
- Response:
[{ login, contributions, avatarUrl }]
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/v1/users/stat |
GET | Optional | Get user stats (365 days) |
/v1/users/leaderboard |
GET | π | Get top contributors |
/v1/users/sync |
POST | π | Force sync GitHub data |
/v1/users/use-freeze |
POST | π | Use a streak freeze |
/v1/users/public/:username |
GET | π | Get public user stats |
/v1/users/:username/profile |
GET | π | Get public profile |
/v1/squads |
POST | π | Create squad |
/v1/squads/public |
GET | π | List public squads |
/v1/squads/my |
GET | π | Get user's squads |
/v1/squads/join |
POST | π | Join squad (code in body) |
/v1/squads/join/:code |
POST | π | Join squad (code in URL) |
/v1/squads/:id/leave |
DELETE | π | Leave squad |
/v1/squads/:id |
GET | π | Get squad details |
/v1/pledges/templates |
GET | π | Get pledge templates |
/v1/pledges |
POST | π | Create pledge |
/v1/pledges/my |
GET | π | Get active + completed |
/v1/pledges/active |
GET | π | Get active pledge |
/v1/pledges/completed |
GET | π | Get completed pledges |
/v1/pledges/:id/complete |
PUT | π | Complete pledge |
/v1/pledges/:id |
DELETE | π | Abandon pledge |
/v1/embed/:username |
GET | π | SVG profile card |
/v1/embed/:username/card |
GET | π | SVG profile card (alias) |
/v1/badges/:username |
GET | π | Simple streak badge |
| Tier | Days | Color |
|---|---|---|
| Starter | 0-6 | Gray |
| Rising | 7-29 | Blue |
| Warrior | 30-99 | Green |
| Master | 100-364 | Gold |
| Legendary | 365+ | Purple |
{
"error": true,
"message": "Human readable error message",
"code": "ERROR_CODE"
}Common error codes: SQUAD_NOT_FOUND, INVALID_INVITE_CODE, ALREADY_MEMBER, SQUAD_FULL, PLEDGE_ALREADY_ACTIVE, PLEDGE_INCOMPLETE, UNAUTHORIZED, RATE_LIMITED
- Timezone: All dates are UTC. Streak resets at midnight UTC.
- Weekly progress: Resets every Sunday at midnight UTC.
- XP multiplier: Squad XP = base _ (1 + memberCount _ 0.1), max 2.0
- Sync frequency: Snapshots cached 60 minutes unless refresh=true.