# V1 ## Global XP leaderboard **get** `/api/v1/leaderboard` Returns the top users platform-wide, ranked by XP descending. ### Query Parameters - `limit: optional number` Max results (1–100, default 25) ### Returns - `entries: optional array of LeaderboardEntry` - `image: optional string` - `name: optional string` - `rank: optional number` - `streakDays: optional number` - `username: optional string` - `xp: optional number` ### Example ```http curl https://racks.cash/api/v1/leaderboard ``` #### Response ```json { "entries": [ { "image": "image", "name": "Alice", "rank": 1, "streakDays": 12, "username": "alice", "xp": 9800 } ] } ``` ## Domain Types ### Leaderboard Entry - `LeaderboardEntry = object { image, name, rank, 3 more }` - `image: optional string` - `name: optional string` - `rank: optional number` - `streakDays: optional number` - `username: optional string` - `xp: optional number` # Me ## Current user profile **get** `/api/v1/me` Returns the authenticated user's profile, stats (cents earned/tipped), XP, level, and default AI model. ### Returns - `id: optional string` - `bio: optional string` - `createdAt: optional string` - `defaultAiModel: optional string` - `email: optional string` - `image: optional string` - `lastPostAt: optional string` - `level: optional number` - `name: optional string` - `postCount: optional number` - `streakDays: optional number` - `totalEarned: optional number` Lifetime earnings in cents - `totalTipped: optional number` Lifetime tips given in cents - `username: optional string` - `xp: optional number` ### Example ```http curl https://racks.cash/api/v1/me ``` #### Response ```json { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "bio": "bio", "createdAt": "2019-12-27T18:11:19.117Z", "defaultAiModel": "anthropic/claude-sonnet-4-5", "email": "alice@example.com", "image": "https://avatars.githubusercontent.com/u/1234567", "lastPostAt": "2019-12-27T18:11:19.117Z", "level": 8, "name": "Alice", "postCount": 17, "streakDays": 5, "totalEarned": 42000, "totalTipped": 1000, "username": "alice", "xp": 3400 } ``` ## Earned badges for the token owner **get** `/api/v1/me/badges` Earned badges for the token owner ### Returns - `badges: optional array of object { description, earnedAt, emoji, 3 more }` - `description: optional string` - `earnedAt: optional string` - `emoji: optional string` - `name: optional string` - `slug: optional string` - `xpThreshold: optional number` ### Example ```http curl https://racks.cash/api/v1/me/badges ``` #### Response ```json { "badges": [ { "description": "description", "earnedAt": "2019-12-27T18:11:19.117Z", "emoji": "⚔️", "name": "First Quest", "slug": "first-quest", "xpThreshold": 100 } ] } ``` ## Circle memberships for the token owner **get** `/api/v1/me/circles` Returns all circles the authenticated user belongs to, with role and timestamps. ### Returns - `circles: optional array of object { id, createdAt, emoji, 5 more }` - `id: optional string` - `createdAt: optional string` - `emoji: optional string` - `isOwner: optional boolean` - `isPrivate: optional boolean` - `joinedAt: optional string` - `name: optional string` - `role: optional "OWNER" or "ADMIN" or "MEMBER"` - `"OWNER"` - `"ADMIN"` - `"MEMBER"` ### Example ```http curl https://racks.cash/api/v1/me/circles ``` #### Response ```json { "circles": [ { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "createdAt": "2019-12-27T18:11:19.117Z", "emoji": "🔥", "isOwner": true, "isPrivate": true, "joinedAt": "2019-12-27T18:11:19.117Z", "name": "Degen Questers", "role": "OWNER" } ] } ``` # Circles ## Circle profile and summary stats **get** `/api/v1/circles/{id}` Returns the circle's profile and aggregate counts (members, quests, posts). The caller must be a member of the circle, or use a circle API key scoped to it. ### Path Parameters - `id: string` ### Returns - `id: optional string` - `createdAt: optional string` - `description: optional string` - `discordUrl: optional string` - `emoji: optional string` - `isPrivate: optional boolean` - `memberCount: optional number` - `name: optional string` - `ownerId: optional string` - `postCount: optional number` - `questCount: optional number` - `xUrl: optional string` ### Example ```http curl https://racks.cash/api/v1/circles/$ID ``` #### Response ```json { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "createdAt": "2019-12-27T18:11:19.117Z", "description": "description", "discordUrl": "https://discord.gg/abc", "emoji": "🔥", "isPrivate": true, "memberCount": 42, "name": "Degen Questers", "ownerId": "ownerId", "postCount": 300, "questCount": 7, "xUrl": "https://x.com/degenraiders" } ``` ## Members of a circle **get** `/api/v1/circles/{id}/members` Returns the circle member list with username, role, XP, level, and join date. Ordered by role (owner first) then join date. ### Path Parameters - `id: string` ### Query Parameters - `limit: optional number` Max results (1–100, default 50) - `offset: optional number` Pagination offset (default 0) ### Returns - `members: optional array of object { id, image, joinedAt, 6 more }` - `id: optional string` - `image: optional string` - `joinedAt: optional string` - `level: optional number` - `name: optional string` - `role: optional "OWNER" or "ADMIN" or "MEMBER"` - `"OWNER"` - `"ADMIN"` - `"MEMBER"` - `streakDays: optional number` - `username: optional string` - `xp: optional number` ### Example ```http curl https://racks.cash/api/v1/circles/$ID/members ``` #### Response ```json { "limit": 0, "offset": 0, "total": 0, "members": [ { "id": "id", "image": "image", "joinedAt": "2019-12-27T18:11:19.117Z", "level": 0, "name": "name", "role": "OWNER", "streakDays": 0, "username": "username", "xp": 0 } ] } ``` ## XP leaderboard for a circle **get** `/api/v1/circles/{id}/leaderboard` Returns circle members ranked by XP descending. ### Path Parameters - `id: string` ### Query Parameters - `limit: optional number` Max results (1–100, default 25) ### Returns - `entries: optional array of LeaderboardEntry` - `id: optional string` - `joinedAt: optional string` - `level: optional number` - `role: optional "OWNER" or "ADMIN" or "MEMBER"` - `"OWNER"` - `"ADMIN"` - `"MEMBER"` ### Example ```http curl https://racks.cash/api/v1/circles/$ID/leaderboard ``` #### Response ```json { "entries": [ { "image": "image", "name": "Alice", "rank": 1, "streakDays": 12, "username": "alice", "xp": 9800, "id": "id", "joinedAt": "2019-12-27T18:11:19.117Z", "level": 0, "role": "OWNER" } ] } ``` # Quests ## Quests for a circle **get** `/api/v1/circles/{id}/quests` Returns quests belonging to the circle, ordered by creation date descending. Supports status filtering and offset pagination. ### Path Parameters - `id: string` ### Query Parameters - `limit: optional number` Max results (1–100, default 20) - `offset: optional number` Pagination offset (default 0) - `status: optional "ACTIVE" or "ENDED" or "CANCELLED"` Filter by quest status - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` ### Returns - `quests: optional array of Quest` - `id: optional string` - `createdAt: optional string` - `deadline: optional string` - `description: optional string` - `rewardPoolCents: optional number` Total reward pool in cents - `status: optional "ACTIVE" or "ENDED" or "CANCELLED"` - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` - `submissionCount: optional number` - `targetUrl: optional string` - `title: optional string` ### Example ```http curl https://racks.cash/api/v1/circles/$ID/quests ``` #### Response ```json { "limit": 0, "offset": 0, "total": 0, "quests": [ { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "createdAt": "2019-12-27T18:11:19.117Z", "deadline": "2019-12-27T18:11:19.117Z", "description": "description", "rewardPoolCents": 5000, "status": "ACTIVE", "submissionCount": 14, "targetUrl": "https://x.com/racks/status/123", "title": "RT our launch tweet" } ] } ``` ## Create a quest in a circle **post** `/api/v1/circles/{id}/quests` Creates a new quest for the circle. **Authorization:** Requires a circle API key, or a user key / session from the **circle owner**. Only the circle owner can create quests via the API. **Quest types:** | `questType` | Required field | Description | | ----------------------- | -------------- | --------------------------- | | `QUOTE_TWEET` (default) | `targetUrl` | Quote-tweet a specific post | | `RETWEET` | `targetUrl` | Retweet a specific post | | `LIKE` | `targetUrl` | Like a specific post | | `FOLLOW` | `targetHandle` | Follow a specific @handle | | `TELEGRAM_REACTION` | `targetUrl` | React to a Telegram message | ### Path Parameters - `id: string` ### Body Parameters - `title: string` Quest title shown to members - `deadline: optional string` Optional deadline after which the quest closes - `description: optional string` Optional longer description - `questType: optional "QUOTE_TWEET" or "RETWEET" or "LIKE" or 2 more` Type of on-chain action required - `"QUOTE_TWEET"` - `"RETWEET"` - `"LIKE"` - `"FOLLOW"` - `"TELEGRAM_REACTION"` - `rewardPool: optional number` Total reward pool in cents (default 0) - `targetHandle: optional string` Required for FOLLOW — X/Twitter @handle (with or without @) - `targetUrl: optional string` Required for QUOTE_TWEET, RETWEET, LIKE, and TELEGRAM_REACTION ### Returns - `Quest = object { id, createdAt, deadline, 6 more }` - `id: optional string` - `createdAt: optional string` - `deadline: optional string` - `description: optional string` - `rewardPoolCents: optional number` Total reward pool in cents - `status: optional "ACTIVE" or "ENDED" or "CANCELLED"` - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` - `submissionCount: optional number` - `targetUrl: optional string` - `title: optional string` ### Example ```http curl https://racks.cash/api/v1/circles/$ID/quests \ -H 'Content-Type: application/json' \ -d '{ "title": "Quote-tweet our launch post", "deadline": "2026-05-01T00:00:00Z", "description": "Quote-tweet with your thoughts to earn 500 XP", "rewardPool": 5000, "targetHandle": "racks_cash", "targetUrl": "https://x.com/racks_cash/status/1234567890" }' ``` #### Response ```json { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "createdAt": "2019-12-27T18:11:19.117Z", "deadline": "2019-12-27T18:11:19.117Z", "description": "description", "rewardPoolCents": 5000, "status": "ACTIVE", "submissionCount": 14, "targetUrl": "https://x.com/racks/status/123", "title": "RT our launch tweet" } ``` ## Domain Types ### Pagination - `Pagination = object { limit, offset, total }` - `limit: number` Page size used for this response - `offset: number` Offset used for this response - `total: number` Total number of matching records ### Quest - `Quest = object { id, createdAt, deadline, 6 more }` - `id: optional string` - `createdAt: optional string` - `deadline: optional string` - `description: optional string` - `rewardPoolCents: optional number` Total reward pool in cents - `status: optional "ACTIVE" or "ENDED" or "CANCELLED"` - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` - `submissionCount: optional number` - `targetUrl: optional string` - `title: optional string` # Posts ## Recent posts in a circle **get** `/api/v1/circles/{id}/posts` Returns posts in the circle feed, newest first. Supports offset pagination. ### Path Parameters - `id: string` ### Query Parameters - `limit: optional number` Max results (1–100, default 20) - `offset: optional number` Pagination offset (default 0) ### Returns - `posts: optional array of Post` - `id: optional string` - `author: optional object { id, image, name, username }` - `id: optional string` - `image: optional string` - `name: optional string` - `username: optional string` - `content: optional string` - `createdAt: optional string` - `mediaType: optional "TEXT" or "IMAGE" or "VIDEO"` - `"TEXT"` - `"IMAGE"` - `"VIDEO"` - `mediaUrl: optional string` ### Example ```http curl https://racks.cash/api/v1/circles/$ID/posts ``` #### Response ```json { "limit": 0, "offset": 0, "total": 0, "posts": [ { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "author": { "id": "id", "image": "image", "name": "name", "username": "username" }, "content": "GM frens! Big news dropping today.", "createdAt": "2019-12-27T18:11:19.117Z", "mediaType": "TEXT", "mediaUrl": "mediaUrl" } ] } ``` ## Create a post in a circle **post** `/api/v1/circles/{id}/posts` Creates a new text post in the circle feed. Optionally cross-posts to connected social accounts (Zernio). **Authorization:** Circle API key (posts as circle owner) or a user key / session from any circle member. **Rate limit:** 30 requests per minute (write tier). ### Path Parameters - `id: string` ### Body Parameters - `content: string` Post text content (max 2000 chars) - `crossPost: optional boolean` Also publish to connected social accounts - `mediaUrl: optional string` Media URL to include in cross-posts - `socialAccounts: optional array of string` Specific Zernio account IDs to cross-post to (default all connected) ### Returns - `social: optional object { error, ok, postId }` Cross-post result (only present when crossPost is true) - `error: optional string` - `ok: optional boolean` - `postId: optional string` ### Example ```http curl https://racks.cash/api/v1/circles/$ID/posts \ -H 'Content-Type: application/json' \ -d '{ "content": "GM frens! Big news dropping today." }' ``` #### Response ```json { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "author": { "id": "id", "image": "image", "name": "name", "username": "username" }, "content": "GM frens! Big news dropping today.", "createdAt": "2019-12-27T18:11:19.117Z", "mediaType": "TEXT", "mediaUrl": "mediaUrl", "social": { "error": "error", "ok": true, "postId": "postId" } } ``` ## Domain Types ### Post - `Post = object { id, author, content, 3 more }` - `id: optional string` - `author: optional object { id, image, name, username }` - `id: optional string` - `image: optional string` - `name: optional string` - `username: optional string` - `content: optional string` - `createdAt: optional string` - `mediaType: optional "TEXT" or "IMAGE" or "VIDEO"` - `"TEXT"` - `"IMAGE"` - `"VIDEO"` - `mediaUrl: optional string` # Social ## Connected social accounts for a circle **get** `/api/v1/circles/{id}/social/accounts` Returns active (non-disconnected) social accounts connected to this circle. Use the `zernioAccountId` values with the publish endpoint. ### Path Parameters - `id: string` ### Returns - `accounts: optional array of object { id, avatarUrl, connectedAt, 3 more }` - `id: optional string` - `avatarUrl: optional string` - `connectedAt: optional string` - `displayName: optional string` - `platform: optional string` - `zernioAccountId: optional string` Use this ID with the publish endpoint ### Example ```http curl https://racks.cash/api/v1/circles/$ID/social/accounts ``` #### Response ```json { "accounts": [ { "id": "clxxxxxxxxxxxxxxxxxxxxxxxx", "avatarUrl": "avatarUrl", "connectedAt": "2019-12-27T18:11:19.117Z", "displayName": "@racks_cash", "platform": "twitter", "zernioAccountId": "acc_abc123" } ] } ``` ## Publish to connected social accounts **post** `/api/v1/circles/{id}/social/publish` Publish content directly to the circle's connected social accounts via Zernio. Does **not** create a post in the circle feed — use `POST /api/v1/circles/{id}/posts` with `crossPost: true` if you want both. **Authorization:** Circle API key, or user key / session from the circle owner or an admin. **Rate limit:** 12 requests per minute (social posting tier). Zernio recommends spacing posts at least 4 minutes apart per account to avoid platform-level throttling. ### Path Parameters - `id: string` ### Body Parameters - `content: string` Text to publish (max 2000 chars) - `accounts: optional array of string` Zernio account IDs to post to (default all connected) - `mediaUrl: optional string` Media URL to attach to the post ### Returns - `accountCount: optional number` - `ok: optional boolean` - `platforms: optional array of string` - `postId: optional string` Zernio post ID ### Example ```http curl https://racks.cash/api/v1/circles/$ID/social/publish \ -H 'Content-Type: application/json' \ -d '{ "content": "We just hit 1000 members! LFG 🔥" }' ``` #### Response ```json { "accountCount": 1, "ok": true, "platforms": [ "twitter" ], "postId": "postId" } ```