Client API
The Client API powers the social side of Kumbaya: user accounts, sessions, comments, fuel/tipping, launches, and the token claim flow that links on-chain creators to Kumbaya profiles.
Base URL
https://clients.kumbaya.xyz
Base path
/v1
OpenAPI / Swagger
Auth
Mostly JWT (Privy-issued) via Authorization: Bearer or cookies. Public for some reads. Signed-message for claim.
Building an LLM agent? These endpoints are also available as MCP tools - 76 of them under the
app_prefix. See the MCP Server, part of the Kumbaya Agent Kit.
Endpoint groups
Sessions (/v1/session/*)
POST /v1/session/create
Privy idToken
Create a session from a Privy login
GET /v1/session/current
JWT
Fetch current session
POST /v1/session/refresh
JWT
Rotate token
POST /v1/session/logout
JWT
Revoke session
POST /v1/session/wallet-state
Optional JWT
Update wallet state metadata
GET /v1/session/wallet/nonce
None
SIWE: get a one-time nonce for a wallet
POST /v1/session/wallet/verify
None
SIWE: verify signed message, return JWT
Sign-In With Ethereum (SIWE) - for agents and wallet-only users
The Client API supports EIP-4361 (Sign-In With Ethereum) as a first-class auth path alongside Privy. This is the right path for AI agents, bots, and any integration that has its own private key and doesn't want to go through a social login flow.
1. Request a nonce
Response: { "nonce": "abc123…" }. The nonce is valid for 5 minutes and is single-use.
2. Build a SIWE message (EIP-4361). The parser is minimal - it requires the address and Nonce: … fields:
Sign it with personal_sign (most wallets/SDKs do this by default for raw strings).
3. Verify
Response:
The same JWT is also set as an httpOnly cookie. Use either path on subsequent requests.
Wallet-only user creation. If the wallet has never logged in before (no Privy user exists with that address), the backend creates a new user record with a synthetic privyDid: "wallet:0x...". This means agents can self-onboard - no admin, no Privy account, no email needed. From there the wallet has the same access as any Privy-backed account except for features that need Privy-specific data (which are rare).
Users (/v1/users/*)
GET /v1/users/me
JWT
Current user's profile
GET /v1/users/profile/address/{wallet}
Public
Public profile by wallet
GET /v1/users/username/check?username=
Public
Username availability
PATCH /v1/users/profile
JWT
Update name/bio/image
POST /v1/users/profile/image
JWT
Upload avatar
GET /v1/users/stats / activity / yaps / fuels / trades
Optional JWT
Profile widgets
PATCH /v1/users/admin/{userId} and similar
Admin JWT
Moderation
Tokens (/v1/tokens/*)
The token endpoints back the launchpad detail page and the claim flow.
GET /v1/tokens/{mintAddress}
Public
Token detail (creator, holders, metadata)
GET /v1/tokens/{mintAddress}/buyers
Public
Holder leaderboard
GET /v1/tokens/{mintAddress}/buyers/chart
Public
Buyer distribution by time
GET /v1/tokens/{mintAddress}/fuels
Public
Fuel tip history
GET /v1/tokens/{mintAddress}/position
JWT
Caller's position
POST /v1/tokens/batch/images
Public
Batch fetch icons
POST /v1/tokens/{mintAddress}/report
JWT
Report a token
POST /v1/tokens/{mintAddress}/claim
JWT + EIP-712 signature
Claim an unclaimed token (see below)
POST /v1/tokens/{mintAddress}/claim/image
JWT
Upload claim image (separate from the metadata claim)
Token claim - EIP-712 signature
The user must be authenticated (JWT) and present an EIP-712 signature that recovers to the on-chain creator of the token. The signature is verified server-side; only on success does the backend create the TokenMetadata record linking the token to the authenticated user.
Request body (ClaimTokenInputSchema):
name, symbol, and the image are not in this body. Name and symbol are read from the on-chain token; the image is uploaded via the separate POST /v1/tokens/{mintAddress}/claim/image endpoint after the metadata claim succeeds.
EIP-712 typed data the user signs:
The signature must be produced within the last hour - signedAt older than 3600 seconds rejects with SIGNATURE_EXPIRED.
Error codes (from ClaimErrorCodes):
UNAUTHORIZED
No valid session
TOKEN_NOT_FOUND
No on-chain token at this address
ALREADY_CLAIMED
Listing already has a creatorId
TOKEN_DELETED
Token was removed by an admin
INVALID_SIGNATURE
Signature doesn't validate against the EIP-712 typed data
NOT_CREATOR
Recovered signer ≠ on-chain creator
SIGNATURE_EXPIRED
signedAt older than 1h
IMAGE_REQUIRED
(image endpoint) no image provided
For the user-facing version of this flow see client docs › Unclaimed tokens.
Launches (/v1/launch/*)
Used by the frontend to track launch state across drafts → on-chain deployment. The actual FireLaunch.ignite() transaction is signed and sent from the user's wallet; the Client API tracks the metadata flow around it.
POST /v1/launch
JWT
Create a draft launch (body: name, symbol, description?, category, chainId)
GET /v1/launch/pending
JWT
Caller's launches not yet COMPLETED or FAILED
GET /v1/launch/{id}
JWT
Launch detail
POST /v1/launch/{id}/image
JWT
Upload launch image (transitions DRAFT → IMAGE_UPLOADED)
POST /v1/launch/{id}/submit
JWT
Submit on-chain tokenAddress for verification (transitions IMAGE_UPLOADED → COMPLETED)
POST /v1/launch/{id}/fail
JWT
Mark a launch FAILED
DELETE /v1/launch/{id}
JWT
Delete a draft
Status state machine
TokenLaunchStatus = 'DRAFT' | 'IMAGE_UPLOADED' | 'COMPLETED' | 'FAILED'.
Create launch body (CreateLaunchInputSchema)
A user can have at most one in-flight launch per (chainId, symbol) pair - duplicates return 400 { code: 'DUPLICATE_LAUNCH' }.
Submit launch body (SubmitLaunchInputSchema)
The backend verifies that the authenticated user matches the on-chain creator for the supplied address before creating a TokenMetadata record. The launch must be in IMAGE_UPLOADED status, and the corresponding token must not already have a TokenMetadata record.
Comments (/v1/comments/*)
Standard CRUD for token comment threads (Yaps).
GET /v1/comments/tokens/{mintAddress}
Public
Comments on a token (paginated)
GET /v1/comments/{id}
Public
Single comment + replies
GET /v1/comments/tokens/{mintAddress}/post/{postNumber}
Public
Comment by 4chan-style post number
POST /v1/comments
JWT
Create comment
PUT /v1/comments/{id}
JWT
Edit own comment
DELETE /v1/comments/{id}
JWT
Delete own comment
POST /v1/comments/{id}/report
JWT
Report comment
Engagement (/v1/likes, /v1/dislike, /v1/favorites)
POST toggles for likes/dislikes/favorites on posts and comments.
Fuel (/v1/fuel/*)
GET /v1/fuel/credits
JWT
Caller's fuel balance
GET /v1/fuel/received
JWT
Inbound transactions
GET /v1/fuel/given
JWT
Outbound transactions
Gifts (/v1/gifts/*)
GET /v1/gifts/status
JWT
Caller's gift cycle status
GET /v1/gifts/prepare
JWT
Prepare gift claim
POST /v1/gifts
JWT
Claim gift
POST /v1/gifts/reset-cycle
Admin
Reset gift cycle
Notifications & push (/v1/notifications/*, /v1/push/*)
Standard endpoints for notification list, unread count, mark-read, and Web Push subscription registration. GET /v1/push/vapid-key returns the public VAPID key for browser registration.
Feed (/v1/feed/*)
GET /v1/feed
Optional JWT
Social feed (type=ALL|LAUNCHES|YAPS|FUELS), personalized when authenticated
GET /v1/feed/content
None
Content feed (yaps and shills)
GET /v1/feed/dares/viral
None
Trending dare tokens
GET /v1/feed/sidebar
None
Sidebar widgets
Content & discovery (/v1/content/*, /v1/competition, /v1/badges, /v1/shares)
GET /v1/content/yaps / shills / tips / landing-ticker
None
Public content streams
GET /v1/competition/stats
None
Competition leaderboards
GET /v1/badges / GET /v1/badges/{badgeId}
None
Badge catalog
POST /v1/shares
JWT
Create a share link for a token
Misc
GET /healthz- livenessGET /v1/ip- return caller IPPOST /v1/x-auth/store-tokens- store X OAuth tokens
Auth model
JWT is issued by
POST /v1/session/create(validating a Privy idToken or wallet signature) and stored as an httpOnly cookie. Subsequent requests use the cookie orAuthorization: Bearer <jwt>.Signed-message auth for
POST /v1/tokens/{mintAddress}/claimis independent of the session - the request must include a wallet-signed payload that recovers to the on-chain creator address.Admin endpoints require
isAdmin: trueon the authenticated user and otherwise behave like any other JWT-protected route.
For complete request/response shapes consult the OpenAPI Swagger UI at clients.kumbaya.xyz/docs.
Last updated