# V1 ## Global XP leaderboard `client.v1.retrieveGlobalLeaderboard(V1RetrieveGlobalLeaderboardParamsquery?, RequestOptionsoptions?): V1RetrieveGlobalLeaderboardResponse` **get** `/api/v1/leaderboard` Returns the top users platform-wide, ranked by XP descending. ### Parameters - `query: V1RetrieveGlobalLeaderboardParams` - `limit?: number` Max results (1–100, default 25) ### Returns - `V1RetrieveGlobalLeaderboardResponse` - `entries?: Array` - `image?: string | null` - `name?: string | null` - `rank?: number` - `streakDays?: number` - `username?: string | null` - `xp?: number` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.retrieveGlobalLeaderboard(); console.log(response.entries); ``` #### Response ```json { "entries": [ { "image": "image", "name": "Alice", "rank": 1, "streakDays": 12, "username": "alice", "xp": 9800 } ] } ``` ## Domain Types ### Leaderboard Entry - `LeaderboardEntry` - `image?: string | null` - `name?: string | null` - `rank?: number` - `streakDays?: number` - `username?: string | null` - `xp?: number` # Me ## Current user profile `client.v1.me.retrieve(RequestOptionsoptions?): MeRetrieveResponse` **get** `/api/v1/me` Returns the authenticated user's profile, stats (cents earned/tipped), XP, level, and default AI model. ### Returns - `MeRetrieveResponse` - `id?: string` - `bio?: string | null` - `createdAt?: string` - `defaultAiModel?: string | null` - `email?: string | null` - `image?: string | null` - `lastPostAt?: string | null` - `level?: number` - `name?: string | null` - `postCount?: number` - `streakDays?: number` - `totalEarned?: number` Lifetime earnings in cents - `totalTipped?: number` Lifetime tips given in cents - `username?: string | null` - `xp?: number` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const me = await client.v1.me.retrieve(); console.log(me.id); ``` #### 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 `client.v1.me.listBadges(RequestOptionsoptions?): MeListBadgesResponse` **get** `/api/v1/me/badges` Earned badges for the token owner ### Returns - `MeListBadgesResponse` - `badges?: Array` - `description?: string | null` - `earnedAt?: string` - `emoji?: string | null` - `name?: string` - `slug?: string` - `xpThreshold?: number | null` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.me.listBadges(); console.log(response.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 `client.v1.me.listCircles(RequestOptionsoptions?): MeListCirclesResponse` **get** `/api/v1/me/circles` Returns all circles the authenticated user belongs to, with role and timestamps. ### Returns - `MeListCirclesResponse` - `circles?: Array` - `id?: string` - `createdAt?: string` - `emoji?: string | null` - `isOwner?: boolean` - `isPrivate?: boolean` - `joinedAt?: string` - `name?: string` - `role?: "OWNER" | "ADMIN" | "MEMBER"` - `"OWNER"` - `"ADMIN"` - `"MEMBER"` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.me.listCircles(); console.log(response.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 `client.v1.circles.retrieve(stringid, RequestOptionsoptions?): CircleRetrieveResponse` **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. ### Parameters - `id: string` ### Returns - `CircleRetrieveResponse` - `id?: string` - `createdAt?: string` - `description?: string | null` - `discordUrl?: string | null` - `emoji?: string | null` - `isPrivate?: boolean` - `memberCount?: number` - `name?: string` - `ownerId?: string` - `postCount?: number` - `questCount?: number` - `xUrl?: string | null` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const circle = await client.v1.circles.retrieve('clxxxxxxxxxxxxxxxxxxxxxxxx'); console.log(circle.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 `client.v1.circles.listMembers(stringid, CircleListMembersParamsquery?, RequestOptionsoptions?): CircleListMembersResponse` **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. ### Parameters - `id: string` - `query: CircleListMembersParams` - `limit?: number` Max results (1–100, default 50) - `offset?: number` Pagination offset (default 0) ### Returns - `CircleListMembersResponse extends Pagination` - `members?: Array` - `id?: string` - `image?: string | null` - `joinedAt?: string` - `level?: number` - `name?: string | null` - `role?: "OWNER" | "ADMIN" | "MEMBER"` - `"OWNER"` - `"ADMIN"` - `"MEMBER"` - `streakDays?: number` - `username?: string | null` - `xp?: number` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.circles.listMembers('id'); console.log(response); ``` #### 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 `client.v1.circles.retrieveLeaderboard(stringid, CircleRetrieveLeaderboardParamsquery?, RequestOptionsoptions?): CircleRetrieveLeaderboardResponse` **get** `/api/v1/circles/{id}/leaderboard` Returns circle members ranked by XP descending. ### Parameters - `id: string` - `query: CircleRetrieveLeaderboardParams` - `limit?: number` Max results (1–100, default 25) ### Returns - `CircleRetrieveLeaderboardResponse` - `entries?: Array` - `id?: string` - `joinedAt?: string` - `level?: number` - `role?: "OWNER" | "ADMIN" | "MEMBER"` - `"OWNER"` - `"ADMIN"` - `"MEMBER"` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.circles.retrieveLeaderboard('id'); console.log(response.entries); ``` #### 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 `client.v1.circles.quests.list(stringid, QuestListParamsquery?, RequestOptionsoptions?): QuestListResponse` **get** `/api/v1/circles/{id}/quests` Returns quests belonging to the circle, ordered by creation date descending. Supports status filtering and offset pagination. ### Parameters - `id: string` - `query: QuestListParams` - `limit?: number` Max results (1–100, default 20) - `offset?: number` Pagination offset (default 0) - `status?: "ACTIVE" | "ENDED" | "CANCELLED"` Filter by quest status - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` ### Returns - `QuestListResponse extends Pagination` - `quests?: Array` - `id?: string` - `createdAt?: string` - `deadline?: string | null` - `description?: string | null` - `rewardPoolCents?: number` Total reward pool in cents - `status?: "ACTIVE" | "ENDED" | "CANCELLED"` - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` - `submissionCount?: number` - `targetUrl?: string | null` - `title?: string` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const quests = await client.v1.circles.quests.list('id'); console.log(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 `client.v1.circles.quests.create(stringid, QuestCreateParamsbody, RequestOptionsoptions?): Quest` **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 | ### Parameters - `id: string` - `body: QuestCreateParams` - `title: string` Quest title shown to members - `deadline?: string | null` Optional deadline after which the quest closes - `description?: string | null` Optional longer description - `questType?: "QUOTE_TWEET" | "RETWEET" | "LIKE" | 2 more` Type of on-chain action required - `"QUOTE_TWEET"` - `"RETWEET"` - `"LIKE"` - `"FOLLOW"` - `"TELEGRAM_REACTION"` - `rewardPool?: number` Total reward pool in cents (default 0) - `targetHandle?: string` Required for FOLLOW — X/Twitter @handle (with or without @) - `targetUrl?: string` Required for QUOTE_TWEET, RETWEET, LIKE, and TELEGRAM_REACTION ### Returns - `Quest` - `id?: string` - `createdAt?: string` - `deadline?: string | null` - `description?: string | null` - `rewardPoolCents?: number` Total reward pool in cents - `status?: "ACTIVE" | "ENDED" | "CANCELLED"` - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` - `submissionCount?: number` - `targetUrl?: string | null` - `title?: string` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const quest = await client.v1.circles.quests.create('id', { title: 'Quote-tweet our launch post' }); console.log(quest.id); ``` #### 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` - `limit: number` Page size used for this response - `offset: number` Offset used for this response - `total: number` Total number of matching records ### Quest - `Quest` - `id?: string` - `createdAt?: string` - `deadline?: string | null` - `description?: string | null` - `rewardPoolCents?: number` Total reward pool in cents - `status?: "ACTIVE" | "ENDED" | "CANCELLED"` - `"ACTIVE"` - `"ENDED"` - `"CANCELLED"` - `submissionCount?: number` - `targetUrl?: string | null` - `title?: string` # Posts ## Recent posts in a circle `client.v1.circles.posts.list(stringid, PostListParamsquery?, RequestOptionsoptions?): PostListResponse` **get** `/api/v1/circles/{id}/posts` Returns posts in the circle feed, newest first. Supports offset pagination. ### Parameters - `id: string` - `query: PostListParams` - `limit?: number` Max results (1–100, default 20) - `offset?: number` Pagination offset (default 0) ### Returns - `PostListResponse extends Pagination` - `posts?: Array` - `id?: string` - `author?: Author | null` - `id?: string` - `image?: string | null` - `name?: string | null` - `username?: string | null` - `content?: string` - `createdAt?: string` - `mediaType?: "TEXT" | "IMAGE" | "VIDEO"` - `"TEXT"` - `"IMAGE"` - `"VIDEO"` - `mediaUrl?: string | null` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const posts = await client.v1.circles.posts.list('id'); console.log(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 `client.v1.circles.posts.create(stringid, PostCreateParamsbody, RequestOptionsoptions?): PostCreateResponse` **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). ### Parameters - `id: string` - `body: PostCreateParams` - `content: string` Post text content (max 2000 chars) - `crossPost?: boolean` Also publish to connected social accounts - `mediaUrl?: string` Media URL to include in cross-posts - `socialAccounts?: Array` Specific Zernio account IDs to cross-post to (default all connected) ### Returns - `PostCreateResponse extends Post` - `social?: Social | null` Cross-post result (only present when crossPost is true) - `error?: string` - `ok?: boolean` - `postId?: string` ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const post = await client.v1.circles.posts.create('id', { content: 'GM frens! Big news dropping today.', }); console.log(post); ``` #### 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` - `id?: string` - `author?: Author | null` - `id?: string` - `image?: string | null` - `name?: string | null` - `username?: string | null` - `content?: string` - `createdAt?: string` - `mediaType?: "TEXT" | "IMAGE" | "VIDEO"` - `"TEXT"` - `"IMAGE"` - `"VIDEO"` - `mediaUrl?: string | null` # Social ## Connected social accounts for a circle `client.v1.circles.social.listAccounts(stringid, RequestOptionsoptions?): SocialListAccountsResponse` **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. ### Parameters - `id: string` ### Returns - `SocialListAccountsResponse` - `accounts?: Array` - `id?: string` - `avatarUrl?: string | null` - `connectedAt?: string` - `displayName?: string | null` - `platform?: string` - `zernioAccountId?: string` Use this ID with the publish endpoint ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.circles.social.listAccounts('id'); console.log(response.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 `client.v1.circles.social.publish(stringid, SocialPublishParamsbody, RequestOptionsoptions?): SocialPublishResponse` **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. ### Parameters - `id: string` - `body: SocialPublishParams` - `content: string` Text to publish (max 2000 chars) - `accounts?: Array` Zernio account IDs to post to (default all connected) - `mediaUrl?: string` Media URL to attach to the post ### Returns - `SocialPublishResponse` - `accountCount?: number` - `ok?: boolean` - `platforms?: Array` - `postId?: string` Zernio post ID ### Example ```typescript import Racks from 'racks.cash'; const client = new Racks(); const response = await client.v1.circles.social.publish('id', { content: 'We just hit 1000 members! LFG 🔥', }); console.log(response.accountCount); ``` #### Response ```json { "accountCount": 1, "ok": true, "platforms": [ "twitter" ], "postId": "postId" } ```