Create Post
Create a new feedback post.
const res = await client.post.create.$post({
title: "Add dark mode support",
content: "It would be great to have a dark mode option for the app.",
workspaceSlug: "acme",
boardSlug: "features",
tags: ["tag-id-1", "tag-id-2"],
roadmapStatus: "pending",
fingerprint: "browser-fingerprint" // For anonymous users
})
const { post } = await res.json()
Type: Public Procedure
Post title (1-256 characters)
Board slug where post will be created
Array of tag IDs to attach
Initial status (default: “pending”)
Browser fingerprint for anonymous users
Authentication:
Authenticated users: Creates post with their user ID
Anonymous users: Requires fingerprint if board allows anonymous posting
Private boards: Requires workspace membership
Automatic Actions:
Post is automatically upvoted by creator
Generates URL-friendly slug
Triggers webhook notifications
Logs activity
Update Post
Update an existing post.
const res = await client.post.update.$post({
postId: "post-123",
title: "Updated title",
content: "Updated content",
tags: ["new-tag-id"],
roadmapStatus: "planned"
})
const { post } = await res.json()
Type: Private Procedure
New cover image (null to remove)
New tags (replaces existing)
Permissions:
Post author can edit their own post
Workspace owner can edit any post
Admins with moderation permission can edit
Delete Post
Permanently delete a post.
const res = await client.post.delete.$post({
postId: "post-123"
})
const { success } = await res.json()
Type: Private Procedure
Permissions:
Post author can delete their own post
Workspace owner can delete any post
Admins with moderation permission can delete
Deleting a post also deletes all associated comments, votes, and activity logs.
Vote on Post
Upvote or remove upvote from a post.
// Authenticated user
const res = await client.post.vote.$post({
postId: "post-123"
})
// Anonymous user
const res = await client.post.vote.$post({
postId: "post-123",
fingerprint: "browser-fingerprint"
})
const { upvotes, hasVoted } = await res.json()
Type: Public Procedure
Required for anonymous users
Whether user has voted after this action
Behavior:
First call: Adds upvote
Second call: Removes upvote (toggle)
One vote per user/fingerprint
Get Vote Status
Check if user has voted on a post.
const res = await client.post.getVoteStatus.$get({
postId: "post-123",
fingerprint: "browser-fingerprint" // For anonymous
})
const { hasVoted } = await res.json()
Type: Public Procedure
Report Post
Report a post for moderation.
const res = await client.post.report.$post({
postId: "post-123",
reason: "spam",
description: "This is a spam post advertising products"
})
Type: Private Procedure
Reason for report (spam, offensive, duplicate, other)
Actions:
Creates report record with “pending” status
Sends email notification to workspace owner
Logs activity with report count
Get Similar Posts
Find similar posts based on title matching.
const res = await client.post.getSimilar.$get({
title: "Add dark mode",
boardSlug: "features",
workspaceSlug: "acme"
})
const { posts } = await res.json()
Type: Public Procedure
Post title to match against
Up to 3 similar posts sorted by relevance
Use Case:
Show duplicate suggestions when users create new posts.
Merge Posts
Merge duplicate posts together.
const res = await client.post.merge.$post({
postId: "post-123",
targetPostId: "post-456",
mergeType: "merge_into",
reason: "Duplicate feature request"
})
const { success, merge } = await res.json()
Type: Private Procedure (requires moderation permission)
Source post ID (will be archived)
Target post ID (receives merged data)
Merge type (“merge_into” or “merge_here”)
Merge Actions:
Consolidates upvotes into target post
Transfers all comments to target
Transfers unique tags
Archives source post
Sets duplicateOfId reference
Logs merge activity
Merge Multiple Posts Here
Merge multiple posts into current post.
const res = await client.post.mergeHere.$post({
postId: "post-123",
sourcePostIds: ["post-456", "post-789"],
reason: "Consolidating duplicate requests"
})
const { success } = await res.json()
Type: Private Procedure (requires moderation permission)
Target post ID (receives all merged data)
Array of source post IDs to merge in
Search Merge Candidates
Search for potential posts to merge with.
const res = await client.post.searchMergeCandidates.$get({
postId: "post-123",
query: "dark mode",
excludeSelf: true
})
const { candidates } = await res.json()
Type: Public Procedure
Search query (searches in same workspace)
Whether to exclude current post from results
Show candidate properties
Auto-Suggestions:
If no query is provided, suggests posts with similar titles.
Example: Complete Post Creation Flow
// 1. Check for similar posts before creating
const similarRes = await client.post.getSimilar.$get({
title: "Add dark mode support",
boardSlug: "features",
workspaceSlug: "acme"
})
const { posts: similar } = await similarRes.json()
if (similar.length > 0) {
// Show duplicates to user
console.log("Similar posts found:", similar)
}
// 2. Get available tags
const tagsRes = await client.board.tagsByWorkspaceSlug.$get({
slug: "acme"
})
const { tags } = await tagsRes.json()
// 3. Create the post
const createRes = await client.post.create.$post({
title: "Add dark mode support",
content: "Users want a dark mode for better readability at night.",
workspaceSlug: "acme",
boardSlug: "features",
tags: [tags[0].id], // UI tag
image: "https://example.com/mockup.png"
})
const { post } = await createRes.json()
// 4. Post is automatically upvoted by creator
console.log(post.upvotes) // 1