Skip to content
UpVoiced Docs

API reference

Moderation

Reports, held comments and blocked end users.

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/reports

Moderation queue: end-user reports of posts and comments by status (default open), newest first, with the target excerpt, its author (keyed IP hash, blocked flag) and open report count

Authentication
API key or Dashboard session; API key scope read
Operation id
listReports
Query parameters
NameTypeRequired
status"open" | "resolved" | "dismissed"default "open"No
cursorstringlength 1–512No
limitintegervalue 1–100default 25No
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 17 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].targetobjectYes
items[].target.kind"post" | "comment"Yes
items[].target.post_idstring (uuid)Yes
items[].target.comment_idstring (uuid) | nullYes
items[].target.excerptstring | nulllength ≤ 280Yes
items[].target.deletedbooleanYes
items[].target.authorobjectYes
items[].target.open_reportsintegervalue ≥ 0Yes
items[].reason"spam" | "abuse" | "off_topic" | "other"Yes
items[].notestring | nulllength ≤ 500Yes
items[].reporter_end_user_idstring (uuid)Yes
items[].status"open" | "resolved" | "dismissed"Yes
items[].created_atstring (date-time)Yes
items[].resolved_atstring (date-time) | nullYes
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/reports' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/reports');
MCP

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

POST/v1/reports/{id}/resolve

Resolve or dismiss a report: closes every open report of the same post or comment (remove content or block the author with their own routes)

Authentication
API key or Dashboard session; API key scope write
Operation id
resolveReport
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
status"resolved" | "dismissed"Yes
Response 200: 2 fields
Response 200 (application/json)
NameTypeRequired
closedintegervalue ≥ 0Yes
status"resolved" | "dismissed"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/reports/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/resolve' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "resolved"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/reports/{id}/resolve', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: { status: 'resolved' },
});
MCP

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

GET/v1/held-comments

End-user comments held for approval (over the link threshold), newest first; not visible anywhere until approved

Authentication
API key or Dashboard session; API key scope read
Operation id
listHeldComments
Query parameters
NameTypeRequired
cursorstringlength 1–512No
limitintegervalue 1–100default 25No
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 15 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].post_idstring (uuid)Yes
items[].parent_idstring (uuid) | nullYes
items[].body_mdstringYes
items[].reason"links"Yes
items[].link_countintegervalue ≥ 0Yes
items[].authorobjectYes
items[].author.end_user_idstring (uuid) | nullYes
items[].author.namestring | nulllength 1–100Yes
items[].author.emailstring | nulllength ≤ 254Yes
items[].author.ip_hashstring | nullpattern ^[0-9a-f]{32}$Yes
items[].author.blockedbooleanYes
items[].created_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/held-comments' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/held-comments');
MCP

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

POST/v1/held-comments/{id}/approve

Publish a held comment as its author (normal checks, follower notifications from now on)

Authentication
API key or Dashboard session; API key scope write
Operation id
approveHeldComment
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: 14 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
post_idstring (uuid)Yes
parent_idstring (uuid) | nullYes
authorobjectYes
author.kind"operator" | "end_user" | "deleted"Yes
author.idstring (uuid) | nullYes
author.namestring | nulllength ≤ 200Yes
body_mdstringYes
is_officialbooleanYes
pinnedbooleanYes
edited_atstring (date-time) | nullYes
deleted_atstring (date-time) | nullYes
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/held-comments/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/held-comments/{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.

DELETE/v1/held-comments/{id}

Reject a held comment: it is deleted and never published

Authentication
API key or Dashboard session; API key scope write
Operation id
rejectHeldComment
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/held-comments/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/held-comments/{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/blocks

Block list: end-users, email addresses, email domains and keyed IP hashes refused on every end-user write (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
listBlocks
Query parameters
NameTypeRequired
cursorstringlength 1–512No
limitintegervalue 1–100default 25No
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 10 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].kind"end_user" | "email" | "email_domain" | "ip_hash"Yes
items[].valuestringlength ≤ 254Yes
items[].end_user_idstring (uuid) | nullYes
items[].reasonstring | nulllength ≤ 500Yes
items[].expires_atstring (date-time) | nullYes
items[].created_by_operator_idstring (uuid)Yes
items[].created_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/blocks' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/blocks');
MCP

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

POST/v1/blocks

Block an end-user, an email address, an email domain (subdomains included) or a keyed IP hash, optionally until a time; idempotent per subject (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
createBlock
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 201: 8 fields
Response 201 (application/json)
NameTypeRequired
idstring (uuid)Yes
kind"end_user" | "email" | "email_domain" | "ip_hash"Yes
valuestringlength ≤ 254Yes
end_user_idstring (uuid) | nullYes
reasonstring | nulllength ≤ 500Yes
expires_atstring (date-time) | nullYes
created_by_operator_idstring (uuid)Yes
created_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/blocks' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "kind": "end_user",
  "end_user_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/blocks', {
  body: {
    kind: 'end_user',
    end_user_id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d',
  },
});
MCP

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

DELETE/v1/blocks/{id}

Remove a block (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
deleteBlock
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/blocks/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/blocks/{id}', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });
MCP

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