Skip to content
UpVoiced Docs

API reference

Changelog

Changelog entries: drafts, scheduling, publishing and preview links.

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/changelog/draft

What an AI changelog draft would cost and use now: credit cost, credits available, credential source, blocker, shipped posts since the last entry (any member; spends nothing)

Authentication
API key or Dashboard session; API key scope read
Operation id
getChangelogDraftInfo
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 7 fields
Response 200 (application/json)
NameTypeRequired
enabledbooleanYes
source"platform" | "own_anthropic" | "openrouter"Yes
credits_costintegervalue ≥ 0Yes
credits_availableintegervalue ≥ 0Yes
blocker"ai_disabled" | "ai_unavailable" | "ai_credits_exhausted" | "ai_credential_invalid" | nullYes
last_entry_published_atstring (date-time) | nullYes
shipped_since_last_entryintegervalue ≥ 0Yes

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

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

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

POST/v1/changelog/draft

AI draft from shipped posts (post_ids, or since the last entry / an ISO time): 5 credits on UpVoiced credits, saved as a draft linked to those posts, never published

Authentication
API key or Dashboard session; API key scope write
Operation id
draftChangelogEntry
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
post_idsarray of string (uuid)items 1–50No
since"last_entry" | string (date-time)No
tone"friendly" | "neutral" | "technical"default "friendly"No
Response 201: 38 fields
Response 201 (application/json)
NameTypeRequired
entryobjectYes
entry.idstring (uuid)Yes
entry.slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
entry.titlestringlength 1–140Yes
entry.body_mdstringlength ≤ 20000Yes
entry.body_htmlstringYes
entry.coverobject | nullYes
entry.cover.idstring (uuid)Yes
entry.cover.urlstring (uri)Yes
entry.versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
entry.categoriesarray of stringitems ≤ 5Yes
entry.state"draft" | "scheduled" | "published"Yes
entry.scheduled_forstring (date-time) | nullYes
entry.published_atstring (date-time) | nullYes
entry.author_operator_idstring (uuid)Yes
entry.linked_postsarray of objectitems ≤ 50Yes
entry.linked_posts[].idstring (uuid)Yes
entry.linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
entry.linked_posts[].titlestringlength 1–140Yes
entry.linked_posts[].board_idstring (uuid)Yes
entry.linked_posts[].statusobjectYes
entry.reaction_countsobjectYes
entry.reaction_counts.👍integervalue ≥ 0Yes
entry.reaction_counts.❤️integervalue ≥ 0Yes
entry.reaction_counts.🎉integervalue ≥ 0Yes
entry.created_atstring (date-time)Yes
entry.updated_atstring (date-time)Yes
credits_usedintegervalue ≥ 0Yes
ai_callobjectYes
ai_call.idstring (uuid)Yes
ai_call.source"platform" | "own_anthropic" | "openrouter"Yes
ai_call.modelstringYes
ai_call.prompt_versionstringYes
selectionobjectYes
selection.mode"post_ids" | "since"Yes
selection.sincestring (date-time) | nullYes
selection.post_countintegervalue 1–50Yes
selection.omittedintegervalue ≥ 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/changelog/draft' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "post_ids": [
    "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
  ]
}'
TypeScript SDK
const data = await upvoiced.post('/v1/changelog/draft', {
  body: { post_ids: ['0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d'] },
});
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "draft_changelog",
    "arguments": {
      "post_ids": [
        "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
      ]
    }
  }
}

Tool draft_changelog.

GET/v1/changelog

Changelog entries, newest first, optional state filter, cursor (any member)

Authentication
API key or Dashboard session; API key scope read
Operation id
listChangelog
Query parameters
NameTypeRequired
state"draft" | "scheduled" | "published"No
cursorstringlength 1–512No
limitintegervalue 1–50default 25No
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 28 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectitems ≤ 50Yes
items[].idstring (uuid)Yes
items[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
items[].titlestringlength 1–140Yes
items[].body_mdstringlength ≤ 20000Yes
items[].body_htmlstringYes
items[].coverobject | nullYes
items[].cover.idstring (uuid)Yes
items[].cover.urlstring (uri)Yes
items[].versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
items[].categoriesarray of stringitems ≤ 5Yes
items[].state"draft" | "scheduled" | "published"Yes
items[].scheduled_forstring (date-time) | nullYes
items[].published_atstring (date-time) | nullYes
items[].author_operator_idstring (uuid)Yes
items[].linked_postsarray of objectitems ≤ 50Yes
items[].linked_posts[].idstring (uuid)Yes
items[].linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
items[].linked_posts[].titlestringlength 1–140Yes
items[].linked_posts[].board_idstring (uuid)Yes
items[].linked_posts[].statusobjectYes
items[].reaction_countsobjectYes
items[].reaction_counts.👍integervalue ≥ 0Yes
items[].reaction_counts.❤️integervalue ≥ 0Yes
items[].reaction_counts.🎉integervalue ≥ 0Yes
items[].created_atstring (date-time)Yes
items[].updated_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/changelog' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/changelog');
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_changelog",
    "arguments": {
      "state": "draft"
    }
  }
}

Tool list_changelog.

POST/v1/changelog

Create a draft entry: title, markdown body with media-host images, cover, version, categories, linked posts

Authentication
API key or Dashboard session; API key scope write
Operation id
createChangelogEntry
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 ≤ 20000default ""No
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$No
categoriesarray of stringitems ≤ 5default []No
cover_asset_idstring (uuid) | nullNo
post_idsarray of string (uuid)items ≤ 50default []No
Response 201: 30 fields
Response 201 (application/json)
NameTypeRequired
idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 20000Yes
body_htmlstringYes
coverobject | nullYes
cover.idstring (uuid)Yes
cover.urlstring (uri)Yes
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
categoriesarray of stringitems ≤ 5Yes
state"draft" | "scheduled" | "published"Yes
scheduled_forstring (date-time) | nullYes
published_atstring (date-time) | nullYes
author_operator_idstring (uuid)Yes
linked_postsarray of objectitems ≤ 50Yes
linked_posts[].idstring (uuid)Yes
linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
linked_posts[].titlestringlength 1–140Yes
linked_posts[].board_idstring (uuid)Yes
linked_posts[].statusobjectYes
linked_posts[].status.idstring (uuid)Yes
linked_posts[].status.namestringlength 1–100Yes
linked_posts[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
linked_posts[].status.category"open" | "active" | "done" | "closed"Yes
reaction_countsobjectYes
reaction_counts.👍integervalue ≥ 0Yes
reaction_counts.❤️integervalue ≥ 0Yes
reaction_counts.🎉integervalue ≥ 0Yes
created_atstring (date-time)Yes
updated_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/changelog' \
  -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"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/changelog', { body: { title: 'Dark mode' } });
MCP

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

GET/v1/changelog/{id}

One entry with linked posts and operator-only reaction counts

Authentication
API key or Dashboard session; API key scope read
Operation id
getChangelogEntry
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 30 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 20000Yes
body_htmlstringYes
coverobject | nullYes
cover.idstring (uuid)Yes
cover.urlstring (uri)Yes
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
categoriesarray of stringitems ≤ 5Yes
state"draft" | "scheduled" | "published"Yes
scheduled_forstring (date-time) | nullYes
published_atstring (date-time) | nullYes
author_operator_idstring (uuid)Yes
linked_postsarray of objectitems ≤ 50Yes
linked_posts[].idstring (uuid)Yes
linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
linked_posts[].titlestringlength 1–140Yes
linked_posts[].board_idstring (uuid)Yes
linked_posts[].statusobjectYes
linked_posts[].status.idstring (uuid)Yes
linked_posts[].status.namestringlength 1–100Yes
linked_posts[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
linked_posts[].status.category"open" | "active" | "done" | "closed"Yes
reaction_countsobjectYes
reaction_counts.👍integervalue ≥ 0Yes
reaction_counts.❤️integervalue ≥ 0Yes
reaction_counts.🎉integervalue ≥ 0Yes
created_atstring (date-time)Yes
updated_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/changelog/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/changelog/{id}', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP

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

PATCH/v1/changelog/{id}

Edit an entry in any state; editing a published entry purges public caches

Authentication
API key or Dashboard session; API key scope write
Operation id
updateChangelogEntry
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Request body (JSON)
NameTypeRequired
titlestringlength 1–140No
body_mdstringlength ≤ 20000No
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$No
categoriesarray of stringitems ≤ 5No
cover_asset_idstring (uuid) | nullNo
post_idsarray of string (uuid)items ≤ 50No
Response 200: 30 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 20000Yes
body_htmlstringYes
coverobject | nullYes
cover.idstring (uuid)Yes
cover.urlstring (uri)Yes
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
categoriesarray of stringitems ≤ 5Yes
state"draft" | "scheduled" | "published"Yes
scheduled_forstring (date-time) | nullYes
published_atstring (date-time) | nullYes
author_operator_idstring (uuid)Yes
linked_postsarray of objectitems ≤ 50Yes
linked_posts[].idstring (uuid)Yes
linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
linked_posts[].titlestringlength 1–140Yes
linked_posts[].board_idstring (uuid)Yes
linked_posts[].statusobjectYes
linked_posts[].status.idstring (uuid)Yes
linked_posts[].status.namestringlength 1–100Yes
linked_posts[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
linked_posts[].status.category"open" | "active" | "done" | "closed"Yes
reaction_countsobjectYes
reaction_counts.👍integervalue ≥ 0Yes
reaction_counts.❤️integervalue ≥ 0Yes
reaction_counts.🎉integervalue ≥ 0Yes
created_atstring (date-time)Yes
updated_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/changelog/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/changelog/{id}', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { title: 'Dark mode' },
});
MCP

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

DELETE/v1/changelog/{id}

Delete an entry (a published one is purged from public caches)

Authentication
API key or Dashboard session; API key scope write
Operation id
deleteChangelogEntry
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/changelog/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/changelog/{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/changelog/{id}/publish

Publish now: linked posts move to the done-target status through the status-change path, changelog.published + cache.purge in the same transaction

Authentication
API key or Dashboard session; API key scope write
Operation id
publishChangelogEntry
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
notifybooleandefault trueNo
Response 200: 30 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 20000Yes
body_htmlstringYes
coverobject | nullYes
cover.idstring (uuid)Yes
cover.urlstring (uri)Yes
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
categoriesarray of stringitems ≤ 5Yes
state"draft" | "scheduled" | "published"Yes
scheduled_forstring (date-time) | nullYes
published_atstring (date-time) | nullYes
author_operator_idstring (uuid)Yes
linked_postsarray of objectitems ≤ 50Yes
linked_posts[].idstring (uuid)Yes
linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
linked_posts[].titlestringlength 1–140Yes
linked_posts[].board_idstring (uuid)Yes
linked_posts[].statusobjectYes
linked_posts[].status.idstring (uuid)Yes
linked_posts[].status.namestringlength 1–100Yes
linked_posts[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
linked_posts[].status.category"open" | "active" | "done" | "closed"Yes
reaction_countsobjectYes
reaction_counts.👍integervalue ≥ 0Yes
reaction_counts.❤️integervalue ≥ 0Yes
reaction_counts.🎉integervalue ≥ 0Yes
created_atstring (date-time)Yes
updated_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/changelog/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/publish' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "notify": true
}'
TypeScript SDK
const data = await upvoiced.post('/v1/changelog/{id}/publish', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { notify: true },
});
MCP
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "publish_changelog",
    "arguments": {
      "id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
    }
  }
}

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

POST/v1/changelog/{id}/schedule

Schedule publishing between one minute and one year ahead; the worker publishes it exactly once

Authentication
API key or Dashboard session; API key scope write
Operation id
scheduleChangelogEntry
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
atstring (date-time)Yes
notifybooleandefault trueNo
Response 200: 30 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 20000Yes
body_htmlstringYes
coverobject | nullYes
cover.idstring (uuid)Yes
cover.urlstring (uri)Yes
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
categoriesarray of stringitems ≤ 5Yes
state"draft" | "scheduled" | "published"Yes
scheduled_forstring (date-time) | nullYes
published_atstring (date-time) | nullYes
author_operator_idstring (uuid)Yes
linked_postsarray of objectitems ≤ 50Yes
linked_posts[].idstring (uuid)Yes
linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
linked_posts[].titlestringlength 1–140Yes
linked_posts[].board_idstring (uuid)Yes
linked_posts[].statusobjectYes
linked_posts[].status.idstring (uuid)Yes
linked_posts[].status.namestringlength 1–100Yes
linked_posts[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
linked_posts[].status.category"open" | "active" | "done" | "closed"Yes
reaction_countsobjectYes
reaction_counts.👍integervalue ≥ 0Yes
reaction_counts.❤️integervalue ≥ 0Yes
reaction_counts.🎉integervalue ≥ 0Yes
created_atstring (date-time)Yes
updated_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/changelog/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/schedule' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "at": "2026-10-22T12:00:00.000Z"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/changelog/{id}/schedule', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { at: '2026-10-22T12:00:00.000Z' },
});
MCP

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

POST/v1/changelog/{id}/unpublish

Return a published or scheduled entry to draft (published: purges caches)

Authentication
API key or Dashboard session; API key scope write
Operation id
unpublishChangelogEntry
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: 30 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
titlestringlength 1–140Yes
body_mdstringlength ≤ 20000Yes
body_htmlstringYes
coverobject | nullYes
cover.idstring (uuid)Yes
cover.urlstring (uri)Yes
versionstring | nullpattern ^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$Yes
categoriesarray of stringitems ≤ 5Yes
state"draft" | "scheduled" | "published"Yes
scheduled_forstring (date-time) | nullYes
published_atstring (date-time) | nullYes
author_operator_idstring (uuid)Yes
linked_postsarray of objectitems ≤ 50Yes
linked_posts[].idstring (uuid)Yes
linked_posts[].slugstringlength 1–200pattern ^[a-z0-9]+(?:-[a-z0-9]+)*$Yes
linked_posts[].titlestringlength 1–140Yes
linked_posts[].board_idstring (uuid)Yes
linked_posts[].statusobjectYes
linked_posts[].status.idstring (uuid)Yes
linked_posts[].status.namestringlength 1–100Yes
linked_posts[].status.colorstringpattern ^#[0-9a-fA-F]{6}$Yes
linked_posts[].status.category"open" | "active" | "done" | "closed"Yes
reaction_countsobjectYes
reaction_counts.👍integervalue ≥ 0Yes
reaction_counts.❤️integervalue ≥ 0Yes
reaction_counts.🎉integervalue ≥ 0Yes
created_atstring (date-time)Yes
updated_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/changelog/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/unpublish' \
  -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/changelog/{id}/unpublish', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

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

Signed, expiring (7 days), noindex preview URL of a draft or scheduled entry; the token is stored hashed

Authentication
API key or Dashboard session; API key scope read
Operation id
getChangelogPreviewLink
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 2 fields
Response 200 (application/json)
NameTypeRequired
urlstring (uri)Yes
expires_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/changelog/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/preview-link' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/changelog/{id}/preview-link', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP

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