Skip to content
UpVoiced Docs

API reference

Widget API

What the feedback widget calls with a signed-in end user’s session: posting, voting, following, comments and the user’s own data.

Set up the SDK client used in the examples

End-user session (widget):

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

// End-user operations: the session token the widget received when the user signed in.
const upvoiced = new UpVoiced({
  headers: { authorization: `Bearer ${endUserToken}` },
  workspace: 'acme', // your workspace slug
});

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/widget/me

The signed-in end-user, the session expiry and the unread state: changelog dot, status changes since the last visit

Authentication
End-user session (widget)
Operation id
getMe
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 18 fields
Response 200 (application/json)
NameTypeRequired
end_userobjectYes
end_user.idstring (uuid)Yes
end_user.emailstring | nulllength ≤ 254Yes
end_user.namestring | nulllength 1–100Yes
end_user.avatar_urlstring | nulllength ≤ 2048Yes
end_user.locale"en" | "pt-BR" | "es" | "de" | "fr"Yes
end_user.created_atstring (date-time)Yes
sessionobjectYes
session.expires_atstring (date-time)Yes
unreadobjectYes
unread.changelogobjectYes
unread.changelog.unreadbooleanYes
unread.changelog.unread_countintegervalue 0–99Yes
unread.changelog.last_seen_atstring (date-time) | nullYes
unread.changelog.latest_published_atstring (date-time) | nullYes
unread.status_changesobjectYes
unread.status_changes.countintegervalue 0–99Yes
unread.status_changes.last_seen_atstring (date-time) | 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/widget/me' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/me');
MCP

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

POST/v1/widget/auth/logout

Revoke the presented session (idempotent)

Authentication
End-user session (widget)
Operation id
logout
Idempotency
Send an Idempotency-Key to make retries safe.
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
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 POST 'https://api.upvoiced.com/v1/widget/auth/logout' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/auth/logout', { body: {} });
MCP

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

POST/v1/widget/changelog/seen

The end-user opened the changelog now: clears the unread dot

Authentication
End-user session (widget)
Operation id
markChangelogSeen
Idempotency
Send an Idempotency-Key to make retries safe.
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 8 fields
Response 200 (application/json)
NameTypeRequired
changelogobjectYes
changelog.unreadbooleanYes
changelog.unread_countintegervalue 0–99Yes
changelog.last_seen_atstring (date-time) | nullYes
changelog.latest_published_atstring (date-time) | nullYes
status_changesobjectYes
status_changes.countintegervalue 0–99Yes
status_changes.last_seen_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/widget/changelog/seen' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/changelog/seen', { body: {} });
MCP

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

POST/v1/widget/updates/seen

The end-user saw the status changes of followed/voted posts now: resets the count

Authentication
End-user session (widget)
Operation id
markUpdatesSeen
Idempotency
Send an Idempotency-Key to make retries safe.
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 8 fields
Response 200 (application/json)
NameTypeRequired
changelogobjectYes
changelog.unreadbooleanYes
changelog.unread_countintegervalue 0–99Yes
changelog.last_seen_atstring (date-time) | nullYes
changelog.latest_published_atstring (date-time) | nullYes
status_changesobjectYes
status_changes.countintegervalue 0–99Yes
status_changes.last_seen_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/widget/updates/seen' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/updates/seen', { body: {} });
MCP

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

POST/v1/widget/me/delete

Delete my data: anonymized within 24 h, 30 days at most (end-user session)

Authentication
End-user session (widget)
Operation id
deleteMyData
Idempotency
Send an Idempotency-Key to make retries safe.
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 202: 3 fields
Response 202 (application/json)
NameTypeRequired
status"pending" | "processing" | "completed"Yes
due_atstring (date-time)Yes
confirmation_emailbooleanYes

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/widget/me/delete' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/me/delete', { body: {} });
MCP

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

GET/v1/widget/me/votes

Posts I voted for that I can still read, newest vote first

Authentication
End-user session (widget)
Operation id
listMyVotes
Query parameters
NameTypeRequired
cursorstringlength 1–512No
limitintegervalue 1–50default 20No
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 34 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 50Yes
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[].approvedbooleanYes
items[].viewerobjectYes
items[].viewer.votedbooleanYes
items[].viewer.followingbooleanYes
items[].viewer.is_authorbooleanYes
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/widget/me/votes' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/me/votes');
MCP

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

GET/v1/widget/me/follows

Posts I follow (not muted) that I can still read, newest follow first

Authentication
End-user session (widget)
Operation id
listMyFollows
Query parameters
NameTypeRequired
cursorstringlength 1–512No
limitintegervalue 1–50default 20No
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 34 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 50Yes
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[].approvedbooleanYes
items[].viewerobjectYes
items[].viewer.votedbooleanYes
items[].viewer.followingbooleanYes
items[].viewer.is_authorbooleanYes
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/widget/me/follows' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/me/follows');
MCP

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

GET/v1/widget/me/preferences

My email preferences in this workspace: the P1-007 opt-outs shared with unsubscribe links

Authentication
End-user session (widget)
Operation id
getMyPreferences
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 6 fields
Response 200 (application/json)
NameTypeRequired
emailobjectYes
email.followedbooleanYes
email.changelogbooleanYes
email.surveysbooleanYes
email.testimonialsbooleanYes
workspace_emails_enabledbooleanYes

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

curl
curl 'https://api.upvoiced.com/v1/widget/me/preferences' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/me/preferences');
MCP

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

PATCH/v1/widget/me/preferences

Turn email categories on or off: followed posts, changelog, surveys, testimonial requests

Authentication
End-user session (widget)
Operation id
updateMyPreferences
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Request body (JSON)
NameTypeRequired
emailobjectYes
email.followedbooleanNo
email.changelogbooleanNo
email.surveysbooleanNo
email.testimonialsbooleanNo
Response 200: 6 fields
Response 200 (application/json)
NameTypeRequired
emailobjectYes
email.followedbooleanYes
email.changelogbooleanYes
email.surveysbooleanYes
email.testimonialsbooleanYes
workspace_emails_enabledbooleanYes

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/widget/me/preferences' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Content-Type: application/json" \
  -d '{
  "email": {
    "followed": true
  }
}'
TypeScript SDK
const data = await upvoiced.patch('/v1/widget/me/preferences', { body: { email: { followed: true } } });
MCP

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

POST/v1/widget/me/export

My own records in this workspace as JSON: profile, preferences, posts, comments, votes, follows; 5 per hour

Authentication
End-user session (widget)
Operation id
exportMyData
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 47 fields
Response 200 (application/json)
NameTypeRequired
format"upvoiced.end_user_export.v1"Yes
exported_atstring (date-time)Yes
workspaceobjectYes
workspace.namestringYes
workspace.slugstringYes
profileobjectYes
profile.idstring (uuid)Yes
profile.emailstring | nullYes
profile.namestring | nullYes
profile.avatar_urlstring | nullYes
profile.locale"en" | "pt-BR" | "es" | "de" | "fr"Yes
profile.created_atstring (date-time)Yes
profile.identity_verified_atstring (date-time) | nullYes
profile.last_seen_atstring (date-time) | nullYes
email_preferencesobjectYes
email_preferences.followedbooleanYes
email_preferences.changelogbooleanYes
email_preferences.surveysbooleanYes
email_preferences.testimonialsbooleanYes
postsarray of objectYes
posts[].idstring (uuid)Yes
posts[].titlestringYes
posts[].body_mdstringYes
posts[].boardstring | nullYes
posts[].statusstringYes
posts[].approvedbooleanYes
posts[].on_my_behalfbooleanYes
posts[].created_atstring (date-time)Yes
posts[].deletedbooleanYes
commentsarray of objectYes
comments[].idstring (uuid)Yes
comments[].post_idstring (uuid)Yes
comments[].post_titlestring | nullYes
comments[].body_mdstringYes
comments[].created_atstring (date-time)Yes
comments[].edited_atstring (date-time) | nullYes
comments[].deleted_atstring (date-time) | nullYes
votesarray of objectYes
votes[].post_idstring (uuid)Yes
votes[].post_titlestring | nullYes
votes[].created_atstring (date-time)Yes
followsarray of objectYes
follows[].post_idstring (uuid)Yes
follows[].post_titlestring | nullYes
follows[].mutedbooleanYes
follows[].created_atstring (date-time)Yes
truncatedbooleanYes

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/widget/me/export' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/me/export', { body: {} });
MCP

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

GET/v1/widget/me/posts

My posts, newest first, including ones awaiting approval

Authentication
End-user session (widget)
Operation id
listMyPosts
Query parameters
NameTypeRequired
cursorstringlength 1–512No
limitintegervalue 1–50default 20No
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 34 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 50Yes
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[].approvedbooleanYes
items[].viewerobjectYes
items[].viewer.votedbooleanYes
items[].viewer.followingbooleanYes
items[].viewer.is_authorbooleanYes
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/widget/me/posts' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/me/posts');
MCP

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

GET/v1/widget/boards

Public boards the end-user can browse and post to

Authentication
End-user session (widget)
Operation id
listWidgetBoards
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 7 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].namestringlength 1–100Yes
items[].slugstringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
items[].descriptionstringlength ≤ 2000Yes
items[].visibility"public"Yes
items[].require_approvalbooleanYes

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

curl
curl 'https://api.upvoiced.com/v1/widget/boards' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/boards');
MCP

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

GET/v1/widget/posts

Posts of one board with my vote/follow state; own unapproved posts included

Authentication
End-user session (widget)
Operation id
listWidgetPosts
Query parameters
NameTypeRequired
boardstringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
sort"trending" | "top" | "new" | "relevance"No
statusstring (uuid)No
tagstring (uuid)No
qstringlength 1–200No
cursorstringlength 1–512No
limitintegervalue 1–50default 20No
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 34 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 50Yes
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[].approvedbooleanYes
items[].viewerobjectYes
items[].viewer.votedbooleanYes
items[].viewer.followingbooleanYes
items[].viewer.is_authorbooleanYes
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/widget/posts' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/posts');
MCP

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

POST/v1/widget/posts

Submit a post; approval-required boards keep it visible to its author only

Authentication
End-user session (widget)
Operation id
createWidgetPost
Idempotency
Send an Idempotency-Key to make retries safe.
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
board_idstring (uuid)Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 10000default ""No
websitestringlength ≤ 2048No
Response 201: 32 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
approvedbooleanYes
viewerobjectYes
viewer.votedbooleanYes
viewer.followingbooleanYes
viewer.is_authorbooleanYes

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/widget/posts' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "board_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d",
  "title": "Dark mode"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/posts', {
  body: {
    board_id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d',
    title: 'Dark mode',
  },
});
MCP

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

GET/v1/widget/posts/similar

Duplicate hints while typing a title, up to 5

Authentication
End-user session (widget)
Operation id
listWidgetSimilarPosts
Query parameters
NameTypeRequired
qstringlength ≤ 200Yes
boardstringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$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/widget/posts/similar?q=dark+mode' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/posts/similar', { query: { q: 'dark mode' } });
MCP

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

GET/v1/widget/posts/{id}

Post detail with my state, the official reply and the first comments

Authentication
End-user session (widget)
Operation id
getWidgetPost
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 63 fields
Response 200 (application/json)
NameTypeRequired
postobjectYes
post.idstring (uuid)Yes
post.board_idstring (uuid)Yes
post.slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
post.titlestringlength 1–140Yes
post.body_mdstringlength ≤ 10000Yes
post.statusobjectYes
post.status.idstring (uuid)Yes
post.status.namestringlength 1–100Yes
post.status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
post.status.category"open" | "active" | "done" | "closed"Yes
post.tagsarray of objectitems ≤ 50Yes
post.tags[].idstring (uuid)Yes
post.tags[].namestringlength 1–100Yes
post.tags[].colorstringpattern ^#[0-9a-fA-F]{6}$Yes
post.imagesarray of objectitems ≤ 4Yes
post.images[].idstring (uuid)Yes
post.images[].urlstring (uri)Yes
post.images[].mime"image/png" | "image/jpeg" | "image/webp"Yes
post.images[].bytesintegervalue ≤ 5242880value > 0Yes
post.authorobjectYes
post.author.kind"operator" | "end_user" | "deleted"Yes
post.author.namestring | nulllength 1–100Yes
post.vote_countintegervalue ≥ 0Yes
post.comment_countintegervalue ≥ 0Yes
post.merged_into_post_idstring (uuid) | nullYes
post.created_atstring (date-time)Yes
post.updated_atstring (date-time)Yes
post.approvedbooleanYes
post.viewerobjectYes
post.viewer.votedbooleanYes
post.viewer.followingbooleanYes
post.viewer.is_authorbooleanYes
official_replyobject | nullYes
official_reply.idstring (uuid)Yes
official_reply.post_idstring (uuid)Yes
official_reply.parent_idstring (uuid) | nullYes
official_reply.authorobjectYes
official_reply.author.kind"operator" | "end_user" | "deleted"Yes
official_reply.author.namestring | nulllength ≤ 200Yes
official_reply.body_mdstringYes
official_reply.is_officialbooleanYes
official_reply.pinnedbooleanYes
official_reply.edited_atstring (date-time) | nullYes
official_reply.deleted_atstring (date-time) | nullYes
official_reply.created_atstring (date-time)Yes
official_reply.is_minebooleanYes
official_reply.heldtrueNo
commentsobjectYes
comments.itemsarray of objectYes
comments.items[].idstring (uuid)Yes
comments.items[].post_idstring (uuid)Yes
comments.items[].parent_idstring (uuid) | nullYes
comments.items[].authorobjectYes
comments.items[].body_mdstringYes
comments.items[].is_officialbooleanYes
comments.items[].pinnedbooleanYes
comments.items[].edited_atstring (date-time) | nullYes
comments.items[].deleted_atstring (date-time) | nullYes
comments.items[].created_atstring (date-time)Yes
comments.items[].is_minebooleanYes
comments.items[].heldtrueNo
comments.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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/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.

GET/v1/widget/posts/{id}/comments

Comments of a readable post, oldest first

Authentication
End-user session (widget)
Operation id
listWidgetComments
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
cursorstringlength 1–512No
limitintegervalue 1–50default 20No
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 16 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].post_idstring (uuid)Yes
items[].parent_idstring (uuid) | nullYes
items[].authorobjectYes
items[].author.kind"operator" | "end_user" | "deleted"Yes
items[].author.namestring | nulllength ≤ 200Yes
items[].body_mdstringYes
items[].is_officialbooleanYes
items[].pinnedbooleanYes
items[].edited_atstring (date-time) | nullYes
items[].deleted_atstring (date-time) | nullYes
items[].created_atstring (date-time)Yes
items[].is_minebooleanYes
items[].heldtrueNo
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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/comments' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/posts/{id}/comments', { 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/widget/posts/{id}/comments

Comment or reply one level; markdown subset, sanitized on render

Authentication
End-user session (widget)
Operation id
commentWidgetPost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
body_mdstringlength ≤ 10000Yes
parent_idstring (uuid)No
websitestringlength ≤ 2048No
Response 201: 14 fields
Response 201 (application/json)
NameTypeRequired
idstring (uuid)Yes
post_idstring (uuid)Yes
parent_idstring (uuid) | nullYes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.namestring | nulllength ≤ 200Yes
body_mdstringYes
is_officialbooleanYes
pinnedbooleanYes
edited_atstring (date-time) | nullYes
deleted_atstring (date-time) | nullYes
created_atstring (date-time)Yes
is_minebooleanYes
heldtrueNo

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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/comments' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "body_md": "It would help our night shift."
}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/posts/{id}/comments', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { body_md: 'It would help our night shift.' },
});
MCP

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

POST/v1/widget/posts/{id}/vote

Vote once (repeat is a no-op); follows the post

Authentication
End-user session (widget)
Operation id
voteWidgetPost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 3 fields
Response 200 (application/json)
NameTypeRequired
post_idstring (uuid)Yes
votedbooleanYes
vote_countintegervalue ≥ 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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/vote' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/posts/{id}/vote', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

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

DELETE/v1/widget/posts/{id}/vote

Remove my vote (idempotent; the follow stays)

Authentication
End-user session (widget)
Operation id
unvoteWidgetPost
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 3 fields
Response 200 (application/json)
NameTypeRequired
post_idstring (uuid)Yes
votedbooleanYes
vote_countintegervalue ≥ 0Yes

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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/vote' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.delete('/v1/widget/posts/{id}/vote', { 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/widget/posts/{id}/follow

Follow a post for status/comment emails

Authentication
End-user session (widget)
Operation id
followWidgetPost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Response 200: 2 fields
Response 200 (application/json)
NameTypeRequired
post_idstring (uuid)Yes
followingbooleanYes

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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/follow' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/posts/{id}/follow', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

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

DELETE/v1/widget/posts/{id}/follow

Stop following a post (idempotent)

Authentication
End-user session (widget)
Operation id
unfollowWidgetPost
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 2 fields
Response 200 (application/json)
NameTypeRequired
post_idstring (uuid)Yes
followingbooleanYes

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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/follow' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.delete('/v1/widget/posts/{id}/follow', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP

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

GET/v1/widget/changelog/subscription

Whether I get changelog emails (subscribed and the changelog category on)

Authentication
End-user session (widget)
Operation id
getChangelogSubscription
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
Response 200: 1 fields
Response 200 (application/json)
NameTypeRequired
subscribedbooleanYes

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

curl
curl 'https://api.upvoiced.com/v1/widget/changelog/subscription' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme"
TypeScript SDK
const data = await upvoiced.get('/v1/widget/changelog/subscription');
MCP

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

POST/v1/widget/changelog/subscription

Subscribe or unsubscribe my account to changelog emails (idempotent; needs an email address)

Authentication
End-user session (widget)
Operation id
setChangelogSubscription
Idempotency
Send an Idempotency-Key to make retries safe.
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
subscribedbooleanYes
Response 200: 1 fields
Response 200 (application/json)
NameTypeRequired
subscribedbooleanYes

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/widget/changelog/subscription' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "subscribed": true
}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/changelog/subscription', { body: { subscribed: true } });
MCP

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

POST/v1/widget/changelog/{id}/react

Set or clear my 👍 ❤️ 🎉 reaction on a published entry; one per end-user and emoji, counts operator-only

Authentication
End-user session (widget)
Operation id
reactWidgetChangelog
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
emoji"👍" | "❤️" | "🎉"Yes
reactedbooleandefault trueNo
Response 200: 2 fields
Response 200 (application/json)
NameTypeRequired
entry_idstring (uuid)Yes
reactionsarray of "👍" | "❤️" | "🎉"items ≤ 3Yes

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/widget/changelog/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/react' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "emoji": "👍"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/changelog/{id}/react', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { emoji: '👍' },
});
MCP

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

POST/v1/widget/posts/{id}/report

Report a post to the moderators (spam, abuse, off topic, other); one report per end-user and post, always the same answer

Authentication
End-user session (widget)
Operation id
reportWidgetPost
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
reason"spam" | "abuse" | "off_topic" | "other"Yes
notestringlength ≤ 500No
Response 202: 1 fields
Response 202 (application/json)
NameTypeRequired
reportedtrueYes

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/widget/posts/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/report' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "spam"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/posts/{id}/report', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { reason: 'spam' },
});
MCP

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

POST/v1/widget/comments/{id}/report

Report a comment to the moderators; one report per end-user and comment, always the same answer

Authentication
End-user session (widget)
Operation id
reportWidgetComment
Idempotency
Send an Idempotency-Key to make retries safe.
Path parameters
NameTypeRequired
idstring (uuid)Yes
Query parameters
NameTypeRequired
workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$No
Headers
NameTypeRequired
x-workspacestringlength 3–32pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$Yes
idempotency-keystringpattern ^[A-Za-z0-9_.:-]{8,128}$No
Request body (JSON)
NameTypeRequired
reason"spam" | "abuse" | "off_topic" | "other"Yes
notestringlength ≤ 500No
Response 202: 1 fields
Response 202 (application/json)
NameTypeRequired
reportedtrueYes

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/widget/comments/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/report' \
  -H "Authorization: Bearer $UPVOICED_END_USER_TOKEN" \
  -H "X-Workspace: acme" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "spam"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/widget/comments/{id}/report', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { reason: 'spam' },
});
MCP

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