Skip to content
UpVoiced Docs

API reference

Posts

Feedback posts: list, search, create, update, approve, merge and bulk changes.

Set up the SDK client used in the examples

API key or Dashboard session:

import { UpVoiced } from '@upvoiced/sdk';

const apiKey = process.env['UPVOICED_API_KEY']; // uv_live_… (Settings → API keys)
const workspace = process.env['UPVOICED_WORKSPACE_ID']; // sent as X-Workspace
if (!apiKey || !workspace) throw new Error('Set UPVOICED_API_KEY and UPVOICED_WORKSPACE_ID.');
const upvoiced = new UpVoiced({ apiKey, workspace });

curl examples read $UPVOICED_API_KEY and $UPVOICED_WORKSPACE_IDfrom your shell. MCP examples are the tools/call request an MCP client sends to the MCP server with the same API key.

GET/v1/posts

Inbox: filter by board/status/tag/q (full-text + trigram)/author_type/has_reply/approval/since; sort new/top/trending/updated/relevance (any member)

Authentication
API key or Dashboard session; API key scope read
Operation id
listPosts
Query parameters
NameTypeRequired
boardstring (uuid)No
statusstring (uuid)No
tagstring (uuid)No
qstringlength 1–200No
author_type"end_user" | "operator"No
has_replyboolean | "true" | "false"No
approval"approved" | "pending"No
sincestring (date-time)No
sort"new" | "top" | "trending" | "updated" | "relevance"No
cursorstringlength 1–512No
limitintegervalue 1–100default 25No
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 39 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].board_idstring (uuid)Yes
items[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
items[].titlestringlength 1–140Yes
items[].body_mdstringlength ≤ 10000Yes
items[].statusobjectYes
items[].status.idstring (uuid)Yes
items[].status.namestringlength 1–100Yes
items[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
items[].status.category"open" | "active" | "done" | "closed"Yes
items[].tagsarray of objectitems ≤ 50Yes
items[].tags[].idstring (uuid)Yes
items[].tags[].namestringlength 1–100Yes
items[].tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
items[].imagesarray of objectitems ≤ 4Yes
items[].images[].idstring (uuid)Yes
items[].images[].urlstring (uri)Yes
items[].images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
items[].images[].bytesintegervalue ≤ 5242880value > 0Yes
items[].authorobjectYes
items[].author.kind"operator" | "end_user" | "deleted"Yes
items[].author.namestring | nulllength 1–100Yes
items[].vote_countintegervalue ≥ 0Yes
items[].comment_countintegervalue ≥ 0Yes
items[].merged_into_post_idstring (uuid) | nullYes
items[].created_atstring (date-time)Yes
items[].updated_atstring (date-time)Yes
items[].workspace_idstring (uuid)Yes
items[].approved_atstring (date-time) | nullYes
items[].eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
items[].pinned_comment_idstring (uuid) | nullYes
items[].trending_scorenumbervalue ≥ 0Yes
items[].follower_countintegervalue ≥ 0Yes
items[].author_end_user_idstring (uuid) | nullYes
items[].author_operator_idstring (uuid) | nullYes
items[].on_behalf_of_end_user_idstring (uuid) | nullYes
items[].last_activity_atstring (date-time)Yes
next_cursorstring | nullYes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl 'https://api.upvoiced.com/v1/posts' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/posts');
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_posts",
    "arguments": {
      "board": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
    }
  }
}

Tool list_posts.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": {
      "query": "dark mode"
    }
  }
}

Tool search.

POST/v1/posts

Create a post, optionally on behalf of an end-user by email; posts.active_max (any member)

Authentication
API key or Dashboard session; API key scope write
Operation id
createPost
Idempotency
Send an Idempotency-Key to make retries safe.
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000default ""No
image_asset_idsarray of string (uuid)items ≤ 4default []No
board_idstring (uuid)Yes
status_idstring (uuid)No
tag_idsarray of string (uuid)items ≤ 50default []No
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$No
on_behalf_of_emailstring (email)length ≤ 254No
Response 201: 37 fields
Response 201 (application/json)
NameTypeRequired
idstring (uuid)Yes
board_idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000Yes
statusobjectYes
status.idstring (uuid)Yes
status.namestringlength 1–100Yes
status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
status.category"open" | "active" | "done" | "closed"Yes
tagsarray of objectitems ≤ 50Yes
tags[].idstring (uuid)Yes
tags[].namestringlength 1–100Yes
tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
imagesarray of objectitems ≤ 4Yes
images[].idstring (uuid)Yes
images[].urlstring (uri)Yes
images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
images[].bytesintegervalue ≤ 5242880value > 0Yes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength 1–100Yes
vote_countintegervalue ≥ 0Yes
comment_countintegervalue ≥ 0Yes
merged_into_post_idstring (uuid) | nullYes
created_atstring (date-time)Yes
updated_atstring (date-time)Yes
workspace_idstring (uuid)Yes
approved_atstring (date-time) | nullYes
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
pinned_comment_idstring (uuid) | nullYes
trending_scorenumbervalue ≥ 0Yes
follower_countintegervalue ≥ 0Yes
author_end_user_idstring (uuid) | nullYes
author_operator_idstring (uuid) | nullYes
on_behalf_of_end_user_idstring (uuid) | nullYes
last_activity_atstring (date-time)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Dark mode",
  "board_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts', {
  body: {
    title: 'Dark mode',
    board_id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d',
  },
});
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_post",
    "arguments": {
      "title": "Dark mode",
      "board_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
    }
  }
}

Tool create_post.

GET/v1/posts/similar

Up to 5 existing posts similar to a title being typed, optionally on one board (any member)

Authentication
API key or Dashboard session; API key scope read
Operation id
listSimilarPosts
Query parameters
NameTypeRequired
qstringlength ≤ 200Yes
boardstring (uuid)No
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 12 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 5Yes
items[].idstring (uuid)Yes
items[].board_idstring (uuid)Yes
items[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
items[].titlestringlength 1–140Yes
items[].statusobjectYes
items[].status.idstring (uuid)Yes
items[].status.namestringlength 1–100Yes
items[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
items[].status.category"open" | "active" | "done" | "closed"Yes
items[].vote_countintegervalue ≥ 0Yes
items[].scorenumbervalue 0–1Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl 'https://api.upvoiced.com/v1/posts/similar?q=dark+mode' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/posts/similar', { query: { q: 'dark mode' } });
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

GET/v1/posts/{id}/similar

Up to 5 other posts similar to this post's title (any member)

Authentication
API key or Dashboard session; API key scope read
Operation id
getPostSimilar
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 12 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 5Yes
items[].idstring (uuid)Yes
items[].board_idstring (uuid)Yes
items[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
items[].titlestringlength 1–140Yes
items[].statusobjectYes
items[].status.idstring (uuid)Yes
items[].status.namestringlength 1–100Yes
items[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
items[].status.category"open" | "active" | "done" | "closed"Yes
items[].vote_countintegervalue ≥ 0Yes
items[].scorenumbervalue 0–1Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/similar' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/posts/{id}/similar', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

POST/v1/posts/bulk

All-or-nothing bulk status/tag/untag/merge/delete for up to 100 posts (any member)

Authentication
API key or Dashboard session; API key scope write
Operation id
bulkPosts
Idempotency
Send an Idempotency-Key to make retries safe.
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 3 fields
Response 200 (application/json)
NameTypeRequired
action"status" | "tag" | "untag" | "merge" | "delete"Yes
countintegervalue ≥ 0Yes
idsarray of string (uuid)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts/bulk' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "status",
  "ids": [
    "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
  ],
  "status_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts/bulk', {
  body: {
    action: 'status',
    ids: ['0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d'],
    status_id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d',
  },
});
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

GET/v1/posts/{id}

Get a post, including unapproved and merged ones (any member)

Authentication
API key or Dashboard session; API key scope read
Operation id
getPost
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 37 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
board_idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000Yes
statusobjectYes
status.idstring (uuid)Yes
status.namestringlength 1–100Yes
status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
status.category"open" | "active" | "done" | "closed"Yes
tagsarray of objectitems ≤ 50Yes
tags[].idstring (uuid)Yes
tags[].namestringlength 1–100Yes
tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
imagesarray of objectitems ≤ 4Yes
images[].idstring (uuid)Yes
images[].urlstring (uri)Yes
images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
images[].bytesintegervalue ≤ 5242880value > 0Yes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength 1–100Yes
vote_countintegervalue ≥ 0Yes
comment_countintegervalue ≥ 0Yes
merged_into_post_idstring (uuid) | nullYes
created_atstring (date-time)Yes
updated_atstring (date-time)Yes
workspace_idstring (uuid)Yes
approved_atstring (date-time) | nullYes
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
pinned_comment_idstring (uuid) | nullYes
trending_scorenumbervalue ≥ 0Yes
follower_countintegervalue ≥ 0Yes
author_end_user_idstring (uuid) | nullYes
author_operator_idstring (uuid) | nullYes
on_behalf_of_end_user_idstring (uuid) | nullYes
last_activity_atstring (date-time)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/posts/{id}', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_post",
    "arguments": {
      "id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
    }
  }
}

Tool get_post.

PATCH/v1/posts/{id}

Edit title/body/board/status/tags/images/eta; status changes emit post.status_changed

Authentication
API key or Dashboard session; API key scope write
Operation id
updatePost
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Request body (JSON)
NameTypeRequired
titlestringlength 1–140No
body_mdstringlength ≤ 10000No
image_asset_idsarray of string (uuid)items ≤ 4No
board_idstring (uuid)No
status_idstring (uuid)No
tag_idsarray of string (uuid)items ≤ 50No
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$No
Response 200: 37 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
board_idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000Yes
statusobjectYes
status.idstring (uuid)Yes
status.namestringlength 1–100Yes
status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
status.category"open" | "active" | "done" | "closed"Yes
tagsarray of objectitems ≤ 50Yes
tags[].idstring (uuid)Yes
tags[].namestringlength 1–100Yes
tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
imagesarray of objectitems ≤ 4Yes
images[].idstring (uuid)Yes
images[].urlstring (uri)Yes
images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
images[].bytesintegervalue ≤ 5242880value > 0Yes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength 1–100Yes
vote_countintegervalue ≥ 0Yes
comment_countintegervalue ≥ 0Yes
merged_into_post_idstring (uuid) | nullYes
created_atstring (date-time)Yes
updated_atstring (date-time)Yes
workspace_idstring (uuid)Yes
approved_atstring (date-time) | nullYes
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
pinned_comment_idstring (uuid) | nullYes
trending_scorenumbervalue ≥ 0Yes
follower_countintegervalue ≥ 0Yes
author_end_user_idstring (uuid) | nullYes
author_operator_idstring (uuid) | nullYes
on_behalf_of_end_user_idstring (uuid) | nullYes
last_activity_atstring (date-time)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X PATCH 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Dark mode"
}'
TypeScript SDK
const data = await upvoiced.patch('/v1/posts/{id}', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { title: 'Dark mode' },
});
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "update_post",
    "arguments": {
      "id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
    }
  }
}

Tool update_post: without "confirm": true some calls only return a preview.

DELETE/v1/posts/{id}

Soft-delete a post (any member; audited)

Authentication
API key or Dashboard session; API key scope write
Operation id
deletePost
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 1 fields
Response 200 (application/json)
NameTypeRequired
oktrueYes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X DELETE 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.delete('/v1/posts/{id}', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

POST/v1/posts/{id}/approve

Approve a post from the approval queue; idempotent

Authentication
API key or Dashboard session; API key scope write
Operation id
approvePost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 37 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
board_idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000Yes
statusobjectYes
status.idstring (uuid)Yes
status.namestringlength 1–100Yes
status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
status.category"open" | "active" | "done" | "closed"Yes
tagsarray of objectitems ≤ 50Yes
tags[].idstring (uuid)Yes
tags[].namestringlength 1–100Yes
tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
imagesarray of objectitems ≤ 4Yes
images[].idstring (uuid)Yes
images[].urlstring (uri)Yes
images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
images[].bytesintegervalue ≤ 5242880value > 0Yes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength 1–100Yes
vote_countintegervalue ≥ 0Yes
comment_countintegervalue ≥ 0Yes
merged_into_post_idstring (uuid) | nullYes
created_atstring (date-time)Yes
updated_atstring (date-time)Yes
workspace_idstring (uuid)Yes
approved_atstring (date-time) | nullYes
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
pinned_comment_idstring (uuid) | nullYes
trending_scorenumbervalue ≥ 0Yes
follower_countintegervalue ≥ 0Yes
author_end_user_idstring (uuid) | nullYes
author_operator_idstring (uuid) | nullYes
on_behalf_of_end_user_idstring (uuid) | nullYes
last_activity_atstring (date-time)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/approve' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts/{id}/approve', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

POST/v1/posts/{id}/merge

Merge this post into `into`: votes/followers union, comments moved, undo for 30 days

Authentication
API key or Dashboard session; API key scope write
Operation id
mergePost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
intostring (uuid)Yes
Response 200: 10 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
source_post_idstring (uuid)Yes
target_post_idstring (uuid)Yes
created_atstring (date-time)Yes
undo_untilstring (date-time)Yes
undone_atstring (date-time) | nullYes
movedobjectYes
moved.votesintegervalue ≥ 0Yes
moved.commentsintegervalue ≥ 0Yes
moved.followersintegervalue ≥ 0Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/merge' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "into": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts/{id}/merge', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { into: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
});
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "merge_posts",
    "arguments": {
      "source_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d",
      "target_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
    }
  }
}

Tool merge_posts: without "confirm": true some calls only return a preview.

POST/v1/posts/{id}/unmerge

Undo the latest merge of this post within 30 days, restoring the snapshot exactly

Authentication
API key or Dashboard session; API key scope write
Operation id
unmergePost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 37 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
board_idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000Yes
statusobjectYes
status.idstring (uuid)Yes
status.namestringlength 1–100Yes
status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
status.category"open" | "active" | "done" | "closed"Yes
tagsarray of objectitems ≤ 50Yes
tags[].idstring (uuid)Yes
tags[].namestringlength 1–100Yes
tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
imagesarray of objectitems ≤ 4Yes
images[].idstring (uuid)Yes
images[].urlstring (uri)Yes
images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
images[].bytesintegervalue ≤ 5242880value > 0Yes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength 1–100Yes
vote_countintegervalue ≥ 0Yes
comment_countintegervalue ≥ 0Yes
merged_into_post_idstring (uuid) | nullYes
created_atstring (date-time)Yes
updated_atstring (date-time)Yes
workspace_idstring (uuid)Yes
approved_atstring (date-time) | nullYes
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
pinned_comment_idstring (uuid) | nullYes
trending_scorenumbervalue ≥ 0Yes
follower_countintegervalue ≥ 0Yes
author_end_user_idstring (uuid) | nullYes
author_operator_idstring (uuid) | nullYes
on_behalf_of_end_user_idstring (uuid) | nullYes
last_activity_atstring (date-time)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/unmerge' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts/{id}/unmerge', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

POST/v1/posts/{id}/unapprove

Hide a post: back into the approval queue, out of every public read until a member approves it again; idempotent

Authentication
API key or Dashboard session; API key scope write
Operation id
unapprovePost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 37 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
board_idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000Yes
statusobjectYes
status.idstring (uuid)Yes
status.namestringlength 1–100Yes
status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
status.category"open" | "active" | "done" | "closed"Yes
tagsarray of objectitems ≤ 50Yes
tags[].idstring (uuid)Yes
tags[].namestringlength 1–100Yes
tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
imagesarray of objectitems ≤ 4Yes
images[].idstring (uuid)Yes
images[].urlstring (uri)Yes
images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
images[].bytesintegervalue ≤ 5242880value > 0Yes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength 1–100Yes
vote_countintegervalue ≥ 0Yes
comment_countintegervalue ≥ 0Yes
merged_into_post_idstring (uuid) | nullYes
created_atstring (date-time)Yes
updated_atstring (date-time)Yes
workspace_idstring (uuid)Yes
approved_atstring (date-time) | nullYes
eta_quarterstring | nullpattern ^20[0-9]{2}-Q[1-4]$Yes
pinned_comment_idstring (uuid) | nullYes
trending_scorenumbervalue ≥ 0Yes
follower_countintegervalue ≥ 0Yes
author_end_user_idstring (uuid) | nullYes
author_operator_idstring (uuid) | nullYes
on_behalf_of_end_user_idstring (uuid) | nullYes
last_activity_atstring (date-time)Yes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/unapprove' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts/{id}/unapprove', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.

POST/v1/posts/{id}/ai-triage

Run AI triage for an approved post now (1 credit on UpVoiced credits; 60 per workspace and hour)

Authentication
API key or Dashboard session; API key scope write
Operation id
runAiTriage
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 16 fields
Response 200 (application/json)
NameTypeRequired
post_idstring (uuid)Yes
status"pending" | "ready" | "paused" | "failed"Yes
reasonstring | nullYes
summarystring | nulllength ≤ 160Yes
sentiment"positive" | "neutral" | "negative" | "mixed" | nullYes
ai_call_idstring (uuid) | nullYes
updated_atstring (date-time)Yes
suggestionsarray of objectitems ≤ 20Yes
suggestions[].idstring (uuid)Yes
suggestions[].kind"board" | "tag" | "duplicate"Yes
suggestions[].state"open" | "applied" | "dismissed"Yes
suggestions[].confidencenumber | nullvalue 0–1Yes
suggestions[].targetobjectYes
suggestions[].target.idstring (uuid)Yes
suggestions[].target.labelstringlength 1–300Yes
suggestions[].decided_atstring (date-time) | nullYes

Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.

curl
curl -X POST 'https://api.upvoiced.com/v1/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/ai-triage' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/posts/{id}/ai-triage', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

No MCP tool for this operation. The MCP server covers the everyday reads and writes.