Boards, threads & posts
The forum is a four-level hierarchy: board → thread → post → reply. Articles sit alongside it as a separate content type (see Articles & paywalls).
Boards
A board is a topic category with a name, title, description, color, icon, and two point multipliers (fudPointsMultiplier, votePointsMultiplier).
| Endpoint | Method | Auth | Notes |
|---|---|---|---|
/api/boards | GET | — | Active boards, pinned first. Supports ?search=. |
/api/boards/name/:name | GET | — | Lookup by exact name (case-insensitive) or slug. |
/api/boards | POST | Admin | Creates a board. |
Board creation validates that name is 2–50 chars of letters, numbers, spaces, hyphens, and underscores, and rejects case-insensitive duplicates. Multipliers are clamped to 0.1–5.0 (default 1.0). Base64 images are uploaded to Cloudinary when configured, with a base64 fallback.
POST /api/boards uses verifyAdmin, which — beyond the x-wallet-address header — requires a valid x-signature and x-message (see API reference).
Threads
A thread is a discussion inside a board.
GET /api/threads # list, approved only
GET /api/threads/board/:boardId # threads for a board
GET /api/threads/:threadId # single thread
POST /api/threads # create
DELETE /api/threads/:threadId # owner or adminListing parameters (GET /api/threads): page (default 1), limit (default 1000), sort (hot | new | top), search. Only status = 'approved' threads are public. Responses include a pagination object (page, limit, total, pages, hasMore).
Create body: { title, content, userId, boardId, image? }. userId may be a uuid, a legacy ObjectId, or a wallet address and is resolved via the identity helper.
Moderation: pending → approved
Threads created by regular users are stored with status = 'pending' and are hidden from every public listing and from search until an admin approves them. Admin-created threads are auto-approved.
Other create-time guards:
- Duplicate detection — the same
(title, userId, boardId)returns409. - Timeouts — if
user.isTimedOutandtimeoutRestrictions.canCreateThreadsis false, returns403with the reason and expiry. Expired timeouts are auto-cleared on the next attempt. - Length — thread content is sanitized; board name characters are validated.
Posts
A post is a message inside a thread. It carries the FUD scoring fields (fudScore, fudPoints, pointsStatus, …).
GET /api/posts # global feed
GET /api/posts/board/:boardId # board feed
GET /api/posts/thread/:threadId # thread feed
GET /api/posts/top # trending
GET /api/posts/:postId # single post
POST /api/posts # create post or replyFeed parameters: page, limit (default 50), boardId, userId (injects the viewer’s userVote), cursor (created-at cursor; disables page offset), sort (random supported on the global feed). Responses include pagination.nextCursor for keyset pagination.
GET /api/posts/top accepts period (day | week | month | all) and sort (fud | votes | hot | new | random).
POST /api/posts is polymorphic. The body decides what gets created:
| Body | Creates |
|---|---|
{ content, userId, threadId } | A top-level post in the thread. |
{ content, userId, threadId, parentPostId } | A reply to parentPostId. |
{ content, userId, articleId } | A comment on an article. |
Posts are capped at 5000 characters. Exact-duplicate content by the same user in the same thread/post returns 409. Counters (thread.postCount, board.postCount, post.replyCount, thread.replyCount) are updated atomically; the thread update cascades to the board exactly once to avoid double counting.
Replies
GET /api/replies?threadId=...|postId=...|articleId=...
GET /api/replies/post/:postId
DELETE /api/replies/:replyIdGET /api/replies requires at least one filter (threadId, postId, or articleId) unless countsOnly=true. Pass x-wallet-address to get each reply’s userVote. countsOnly=true returns a { targetId: count } map.
Deletion & moderation
FudFi uses soft deletes: deleting a post, reply, or thread sets isDeleted = true (posts/replies) rather than removing rows, and vote rows are cleaned up as needed. DELETE handlers are guarded by verifyOwnershipOrAdmin — the author or an admin only.
Admins can additionally pin boards and posts globally:
POST /api/admin/pin-board POST /api/admin/unpin-board
POST /api/admin/pin-post POST /api/admin/unpin-post