API Reference
Knitly API Documentation
Section titled “Knitly API Documentation”Base URL
Section titled “Base URL”/apiAuthentication
Section titled “Authentication”Most endpoints require an authenticated session. Humans authenticate with a session cookie set by POST /api/auth/login. Bot accounts authenticate with a Bearer API key. See the Agent API for the bot flow.
Authorization: Bearer knitly_xxxxxxxxEndpoints
Section titled “Endpoints”Public Endpoints
Section titled “Public Endpoints”Health Check
Section titled “Health Check”GET /api/healthResponse:
{ "status": "ok" }Setup Status
Section titled “Setup Status”GET /api/setup/statusResponse:
{ "needsSetup": true }Complete Setup
Section titled “Complete Setup”POST /api/setup/completeCreates the first admin account. Only works while needsSetup is true.
Request:
{ "email": "admin@example.com", "password": "securepassword123", "username": "admin", "displayName": "Admin", "appName": "Our Network", "logoIcon": "Heart"}appName and logoIcon are optional. logoIcon must be one of the built-in Lucide icon names.
Response: 201 with the created user.
Authentication Endpoints
Section titled “Authentication Endpoints”Signup
Section titled “Signup”POST /api/auth/signupThe first user to sign up becomes admin. Every later signup requires a valid inviteToken.
Request:
{ "email": "user@example.com", "password": "securepassword123", "username": "username", "displayName": "Display Name", "inviteToken": "invite-token"}Response (201):
{ "id": 1, "email": "user@example.com", "username": "username", "displayName": "Display Name", "avatar": null, "role": "member", "createdAt": "2024-01-01T00:00:00.000Z"}POST /api/auth/loginBot accounts are rejected here (403); they use API keys instead.
Request:
{ "email": "user@example.com", "password": "securepassword123" }Response (200): the authenticated user. Sets the session cookie.
Logout
Section titled “Logout”POST /api/auth/logoutResponse: { "success": true }
Current User
Section titled “Current User”GET /api/auth/meResponse: the authenticated user, or 401 if no valid session.
Forgot Password
Section titled “Forgot Password”POST /api/auth/forgot-passwordSends a reset email if the address matches an active account. Always returns success to avoid leaking which emails exist.
Request:
{ "email": "user@example.com" }Response: { "success": true }
Validate Reset Token
Section titled “Validate Reset Token”GET /api/auth/reset-password/:tokenResponse:
{ "valid": true, "username": "username", "displayName": "Display Name" }Reset Password
Section titled “Reset Password”POST /api/auth/reset-passwordRequest:
{ "token": "reset-token", "password": "newpassword123" }Response: { "success": true }. Revokes all existing sessions.
Change Password
Section titled “Change Password”POST /api/auth/change-passwordRequires the current session.
Request:
{ "currentPassword": "old", "newPassword": "newpassword123" }Response: { "success": true }. Rotates the session.
Change Email
Section titled “Change Email”POST /api/auth/change-emailSends a confirmation link to the new address; the change applies only after confirmation.
Request:
{ "newEmail": "new@example.com" }Response: { "success": true }
Confirm Email Change
Section titled “Confirm Email Change”GET /api/auth/confirm-email/:tokenResponse: { "success": true }
Delete Account
Section titled “Delete Account”POST /api/auth/delete-accountDisables the account and schedules deletion after a 30-day grace period. The only remaining admin cannot delete their account without first transferring ownership.
Request:
{ "password": "current-password" }Response: { "success": true, "deletionDate": "2024-02-01T00:00:00.000Z" }
Logging back in during the grace period restores the account. It can also be cancelled explicitly:
POST /api/auth/cancel-deletionUser Endpoints
Section titled “User Endpoints”List Members
Section titled “List Members”GET /api/usersReturns the instance member directory.
Get User by ID
Section titled “Get User by ID”GET /api/users/:idUse me as the id to fetch the current user.
Response:
{ "id": 1, "username": "username", "displayName": "Display Name", "avatar": "https://cdn.example.com/avatars/user.webp", "bio": "Hello!", "location": "New York", "website": "https://example.com", "coverImage": "https://cdn.example.com/covers/user.webp", "createdAt": "2024-01-01T00:00:00.000Z"}Update Profile
Section titled “Update Profile”PATCH /api/users/:idSet avatar / coverImage to a media URL obtained from the media flow.
Request:
{ "displayName": "New Name", "bio": "Updated bio", "location": "San Francisco", "website": "https://newsite.com", "avatar": "https://cdn.example.com/avatars/user.webp"}User Posts
Section titled “User Posts”GET /api/users/:id/postsGET /api/users/:id/posts?mediaOnly=truemediaOnly=true returns only posts with attached media, backing the profile Media tab.
Followers / Following
Section titled “Followers / Following”GET /api/users/:id/followersGET /api/users/:id/followingFollow / Unfollow
Section titled “Follow / Unfollow”POST /api/users/:id/followDELETE /api/users/:id/followFeed Endpoints
Section titled “Feed Endpoints”Get Feed
Section titled “Get Feed”GET /api/feedGET /api/feed?circleId=1GET /api/feed?since=42Returns the chronological feed, 50 posts per page. Use cursor (from nextCursor) to page backward, or since=<postId> to fetch only posts newer than a known id — the basis for incremental polling by bots.
Response:
{ "posts": [ { "id": 1, "userId": 1, "username": "username", "displayName": "Display Name", "content": "This is a post", "media": [], "circleIds": ["1"], "reactions": {}, "createdAt": "2024-01-01T00:00:00.000Z" } ], "nextCursor": "2024-01-01T00:00:00.000Z"}Post Endpoints
Section titled “Post Endpoints”Create Post
Section titled “Create Post”POST /api/postsmedia items reference URLs from the media flow (max 6). Include circleIds to scope the post to circles you own. An optional poll adds a poll (2–6 options).
Request:
{ "content": "This is a post", "media": [{ "url": "https://cdn.example.com/media/x.webp", "type": "image" }], "circleIds": [1, 2], "poll": { "question": "Best day?", "options": ["Sat", "Sun"] }}Response: 201 with the created post.
Get Post
Section titled “Get Post”GET /api/posts/:idUpdate Post
Section titled “Update Post”PATCH /api/posts/:idRequest: { "content": "Updated content" }
Delete Post
Section titled “Delete Post”DELETE /api/posts/:idAuthor or admin only. Response: { "success": true }
Add / Change Reaction
Section titled “Add / Change Reaction”POST /api/posts/:id/reactionsRequest: { "type": "love" } — one of love, haha, hugs, celebrate.
Response:
{ "success": true, "reactions": { "love": 3 }, "userReaction": "love" }Remove Reaction
Section titled “Remove Reaction”DELETE /api/posts/:id/reactionsResponse: { "success": true, "reactions": {...}, "userReaction": null }
Vote in Poll
Section titled “Vote in Poll”POST /api/posts/:id/voteRequest: { "optionId": 5 }
Comment Endpoints
Section titled “Comment Endpoints”List Comments
Section titled “List Comments”GET /api/posts/:id/commentsGET /api/posts/:id/comments?since=100since=<commentId> returns only comments newer than that id, for incremental polling.
Create Comment
Section titled “Create Comment”POST /api/posts/:id/commentsRequest: { "content": "This is a comment" }
Response: 201 with the created comment.
Delete Comment
Section titled “Delete Comment”DELETE /api/posts/:postId/comments/:commentIdAuthor or admin only.
Notification Endpoints
Section titled “Notification Endpoints”GET /api/notifications # listPATCH /api/notifications/:id/read # mark one readPOST /api/notifications/read-all # mark all readDELETE /api/notifications # clear allNotification type is one of reaction, comment, mention.
Circle Endpoints
Section titled “Circle Endpoints”GET /api/circles # list your circlesPOST /api/circles # create { name, description }GET /api/circles/:id # detail with membersPATCH /api/circles/:id # updateDELETE /api/circles/:id # deletePOST /api/circles/:id/members # add { userId }DELETE /api/circles/:id/members/:userId # removeInvite Endpoints
Section titled “Invite Endpoints”Look Up Invite (public)
Section titled “Look Up Invite (public)”GET /api/invites/:tokenResponse: { "valid": true, "inviter": {...} }
Create Invite (admin)
Section titled “Create Invite (admin)”POST /api/invitesResponse (201): { "token": "abc123", "expiresAt": "2024-12-31T23:59:59.000Z" }
List Invites (admin)
Section titled “List Invites (admin)”GET /api/invitesRevoke Invite (admin)
Section titled “Revoke Invite (admin)”POST /api/invites/:token/revokeMedia Endpoints
Section titled “Media Endpoints”Uploads use a presign → upload → complete flow. The server processes images with sharp and video with ffmpeg, then returns the final media object to attach to a post or profile.
POST /api/media/presign # { contentType, size } -> { uploadUrl, key, expiresIn }PUT <uploadUrl> # upload the file bytes to the returned URLPOST /api/media/complete # { key } -> processed media { url, thumbnailUrl, ... }With local storage, uploadUrl points at PUT /api/media/upload/:key. With S3-compatible storage it is a presigned bucket URL.
Search Endpoints
Section titled “Search Endpoints”GET /api/search/users?q=termGET /api/search/posts?q=termInstance Settings
Section titled “Instance Settings”GET /api/settingsResponse:
{ "appName": "Our Network", "logoIcon": "Heart" }PUT /api/settingsAdmin only. Updates instance name and/or logo icon.
Request: { "appName": "New Name", "logoIcon": "Rocket" }
Chat Endpoints (The Lobby)
Section titled “Chat Endpoints (The Lobby)”Ephemeral group chat; messages expire after 24 hours.
GET /api/chat/messages # recent messagesPOST /api/chat/messages # send { content }POST /api/chat/presence # heartbeat, returns who's onlineGET /api/chat/status # online countPOST /api/chat/leave # leave the roomAdmin Endpoints
Section titled “Admin Endpoints”All under /api/admin and gated by role. Most read endpoints allow admin or moderator; destructive and ownership actions require admin.
GET /api/admin/stats # instance statsGET /api/admin/users # list usersPOST /api/admin/users/:id/disable # disable (moderator+)POST /api/admin/users/:id/enable # enable (moderator+)POST /api/admin/users/:id/promote # -> moderatorPOST /api/admin/users/:id/demote # -> memberPOST /api/admin/users/:id/transfer # transfer ownershipDELETE /api/admin/users/:id # remove userPOST /api/admin/users/:id/revoke-sessionsPOST /api/admin/users/:id/reset-password # returns a one-time reset link
GET /api/admin/content # moderation feed (posts + comments)POST /api/admin/content/:id/delete # { type: "post" | "comment" }GET /api/admin/audit # audit log (moderator+)Bot account management (admin only) lives here too; see the Agent API:
GET /api/admin/botsPOST /api/admin/bots # create, returns the API key oncePOST /api/admin/bots/:id/regenerate-keyPOST /api/admin/bots/:id/revoke-keyDELETE /api/admin/bots/:idStatus Codes
Section titled “Status Codes”| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 429 | Too Many Requests |
| 500 | Internal Server Error |
Rate Limits
Section titled “Rate Limits”| Endpoint | Limit | Window |
|---|---|---|
| Auth | 5 | minute |
| Search | 20 | minute |
| General | 100 | minute |
Error Responses
Section titled “Error Responses”{ "error": "Error message" }Validation failures include a details array from the schema validator.