Skip to content
UpVoiced Docs

API reference

Imports

Imports of posts, comments and votes from other tools.

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.

POST/v1/imports/uploads

Presign a CSV upload (≤ 10 MB) into the private exports bucket (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
presignImportUpload
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
bytesintegervalue 1–10485760Yes
Response 201: 8 fields
Response 201 (application/json)
NameTypeRequired
asset_idstring (uuid)Yes
method"PUT"Yes
upload_urlstring (uri)Yes
expires_atstring (date-time)Yes
headersobjectYes
headers.content-type"text/csv"Yes
headers.content-lengthstringYes
headers.if-none-match"*"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/imports/uploads' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "bytes": 1
}'
TypeScript SDK
const data = await upvoiced.post('/v1/imports/uploads', { body: { bytes: 1 } });
MCP

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

GET/v1/imports

Recent imports with progress (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
listImports
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 39 fields
Response 200 (application/json)
NameTypeRequired
itemsarray of objectYes
items[].idstring (uuid)Yes
items[].source"canny" | "featurebase" | "hearloop" | "generic"Yes
items[].entity"posts" | "votes" | "comments"Yes
items[].status"pending" | "running" | "completed" | "failed" | "canceled"Yes
items[].dry_runbooleanYes
items[].board_idstring (uuid) | nullYes
items[].progressobjectYes
items[].progress.rows_totalinteger | nullvalue ≥ 0Yes
items[].progress.rows_processedintegervalue ≥ 0Yes
items[].progress.rows_failedintegervalue ≥ 0Yes
items[].progress.rows_warnedintegervalue ≥ 0Yes
items[].countsobjectYes
items[].counts.posts_createdintegervalue ≥ 0Yes
items[].counts.posts_updatedintegervalue ≥ 0Yes
items[].counts.posts_unchangedintegervalue ≥ 0Yes
items[].counts.votes_createdintegervalue ≥ 0Yes
items[].counts.votes_existingintegervalue ≥ 0Yes
items[].counts.comments_createdintegervalue ≥ 0Yes
items[].counts.comments_updatedintegervalue ≥ 0Yes
items[].counts.comments_unchangedintegervalue ≥ 0Yes
items[].counts.end_users_createdintegervalue ≥ 0Yes
items[].counts.statuses_createdintegervalue ≥ 0Yes
items[].counts.tags_createdintegervalue ≥ 0Yes
items[].errorsarray of objectitems ≤ 200Yes
items[].errors[].rowintegervalue ≥ 1Yes
items[].errors[].columnstring | nulllength ≤ 200Yes
items[].errors[].code"required" | "too_long" | "invalid_email" | "invalid_date" | "invalid_number" | "invalid_eta" | "unknown_board" | "board_archived" | "board_private_votes" | "post_not_found" | "parent_not_found" | "reply_depth" | "end_user_deleted" | "plan_limit" | "changed_since_import" | "duplicate_in_file" | "too_many_values" | "row_failed"Yes
items[].errors[].severity"error" | "warning"Yes
items[].errors[].messagestringlength ≤ 300Yes
items[].errors_truncatedbooleanYes
items[].errorobject | nullYes
items[].error.code"upload_missing" | "file_too_large" | "invalid_encoding" | "empty_file" | "too_many_columns" | "too_many_rows" | "field_too_long" | "record_too_long" | "unterminated_quote" | "missing_columns" | "delimiter_mismatch" | "duplicate_headers" | "board_unavailable" | "post_not_found" | "storage_unavailable" | "stalled" | "internal_error"Yes
items[].error.messagestringYes
items[].cancel_requestedbooleanYes
items[].created_atstring (date-time)Yes
items[].started_atstring (date-time) | nullYes
items[].finished_atstring (date-time) | nullYes
next_cursornullYes

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

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

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

POST/v1/imports

Queue a CSV import or dry run (Canny/Featurebase/hearloop/generic mapping; owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
createImport
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
asset_idstring (uuid)Yes
source"canny" | "featurebase" | "hearloop" | "generic"Yes
entity"posts" | "votes" | "comments"default "posts"No
mappingobjectdefault {"delimiter":",","columns":{},"status_map":{},"board_map":{},"body_format":"auto","follow":false}No
mapping.delimiter"," | ";" | "\t" | "|"default ","No
mapping.columnsobjectdefault {}No
mapping.columns.external_idstringlength 1–200No
mapping.columns.titlestringlength 1–200No
mapping.columns.bodystringlength 1–200No
mapping.columns.statusstringlength 1–200No
mapping.columns.boardstringlength 1–200No
mapping.columns.tagsstringlength 1–200No
mapping.columns.categorystringlength 1–200No
mapping.columns.authorstringlength 1–200No
mapping.columns.author_emailstringlength 1–200No
mapping.columns.author_namestringlength 1–200No
mapping.columns.created_atstringlength 1–200No
mapping.columns.urlstringlength 1–200No
mapping.columns.vote_countstringlength 1–200No
mapping.columns.voter_emailsstringlength 1–200No
mapping.columns.etastringlength 1–200No
mapping.columns.post_refstringlength 1–200No
mapping.columns.emailstringlength 1–200No
mapping.columns.namestringlength 1–200No
mapping.columns.parent_refstringlength 1–200No
mapping.status_mapobjectdefault {}No
mapping.board_mapobjectdefault {}No
mapping.post_idstring (uuid)No
mapping.body_format"auto" | "markdown" | "html" | "text"default "auto"No
mapping.followbooleandefault falseNo
board_idstring (uuid)No
dry_runbooleandefault trueNo
Response 202: 37 fields
Response 202 (application/json)
NameTypeRequired
idstring (uuid)Yes
source"canny" | "featurebase" | "hearloop" | "generic"Yes
entity"posts" | "votes" | "comments"Yes
status"pending" | "running" | "completed" | "failed" | "canceled"Yes
dry_runbooleanYes
board_idstring (uuid) | nullYes
progressobjectYes
progress.rows_totalinteger | nullvalue ≥ 0Yes
progress.rows_processedintegervalue ≥ 0Yes
progress.rows_failedintegervalue ≥ 0Yes
progress.rows_warnedintegervalue ≥ 0Yes
countsobjectYes
counts.posts_createdintegervalue ≥ 0Yes
counts.posts_updatedintegervalue ≥ 0Yes
counts.posts_unchangedintegervalue ≥ 0Yes
counts.votes_createdintegervalue ≥ 0Yes
counts.votes_existingintegervalue ≥ 0Yes
counts.comments_createdintegervalue ≥ 0Yes
counts.comments_updatedintegervalue ≥ 0Yes
counts.comments_unchangedintegervalue ≥ 0Yes
counts.end_users_createdintegervalue ≥ 0Yes
counts.statuses_createdintegervalue ≥ 0Yes
counts.tags_createdintegervalue ≥ 0Yes
errorsarray of objectitems ≤ 200Yes
errors[].rowintegervalue ≥ 1Yes
errors[].columnstring | nulllength ≤ 200Yes
errors[].code"required" | "too_long" | "invalid_email" | "invalid_date" | "invalid_number" | "invalid_eta" | "unknown_board" | "board_archived" | "board_private_votes" | "post_not_found" | "parent_not_found" | "reply_depth" | "end_user_deleted" | "plan_limit" | "changed_since_import" | "duplicate_in_file" | "too_many_values" | "row_failed"Yes
errors[].severity"error" | "warning"Yes
errors[].messagestringlength ≤ 300Yes
errors_truncatedbooleanYes
errorobject | nullYes
error.code"upload_missing" | "file_too_large" | "invalid_encoding" | "empty_file" | "too_many_columns" | "too_many_rows" | "field_too_long" | "record_too_long" | "unterminated_quote" | "missing_columns" | "delimiter_mismatch" | "duplicate_headers" | "board_unavailable" | "post_not_found" | "storage_unavailable" | "stalled" | "internal_error"Yes
error.messagestringYes
cancel_requestedbooleanYes
created_atstring (date-time)Yes
started_atstring (date-time) | nullYes
finished_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/imports' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "asset_id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d",
  "source": "canny"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/imports', {
  body: {
    asset_id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d',
    source: 'canny',
  },
});
MCP

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

GET/v1/imports/{id}

Import progress, counts and row errors (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
getImport
Path parameters
NameTypeRequired
idstring (uuid)Yes
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 37 fields
Response 200 (application/json)
NameTypeRequired
idstring (uuid)Yes
source"canny" | "featurebase" | "hearloop" | "generic"Yes
entity"posts" | "votes" | "comments"Yes
status"pending" | "running" | "completed" | "failed" | "canceled"Yes
dry_runbooleanYes
board_idstring (uuid) | nullYes
progressobjectYes
progress.rows_totalinteger | nullvalue ≥ 0Yes
progress.rows_processedintegervalue ≥ 0Yes
progress.rows_failedintegervalue ≥ 0Yes
progress.rows_warnedintegervalue ≥ 0Yes
countsobjectYes
counts.posts_createdintegervalue ≥ 0Yes
counts.posts_updatedintegervalue ≥ 0Yes
counts.posts_unchangedintegervalue ≥ 0Yes
counts.votes_createdintegervalue ≥ 0Yes
counts.votes_existingintegervalue ≥ 0Yes
counts.comments_createdintegervalue ≥ 0Yes
counts.comments_updatedintegervalue ≥ 0Yes
counts.comments_unchangedintegervalue ≥ 0Yes
counts.end_users_createdintegervalue ≥ 0Yes
counts.statuses_createdintegervalue ≥ 0Yes
counts.tags_createdintegervalue ≥ 0Yes
errorsarray of objectitems ≤ 200Yes
errors[].rowintegervalue ≥ 1Yes
errors[].columnstring | nulllength ≤ 200Yes
errors[].code"required" | "too_long" | "invalid_email" | "invalid_date" | "invalid_number" | "invalid_eta" | "unknown_board" | "board_archived" | "board_private_votes" | "post_not_found" | "parent_not_found" | "reply_depth" | "end_user_deleted" | "plan_limit" | "changed_since_import" | "duplicate_in_file" | "too_many_values" | "row_failed"Yes
errors[].severity"error" | "warning"Yes
errors[].messagestringlength ≤ 300Yes
errors_truncatedbooleanYes
errorobject | nullYes
error.code"upload_missing" | "file_too_large" | "invalid_encoding" | "empty_file" | "too_many_columns" | "too_many_rows" | "field_too_long" | "record_too_long" | "unterminated_quote" | "missing_columns" | "delimiter_mismatch" | "duplicate_headers" | "board_unavailable" | "post_not_found" | "storage_unavailable" | "stalled" | "internal_error"Yes
error.messagestringYes
cancel_requestedbooleanYes
created_atstring (date-time)Yes
started_atstring (date-time) | nullYes
finished_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/imports/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/imports/{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/imports/{id}/cancel

Cancel a queued import, or stop a running one after its current batch (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
cancelImport
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
source"canny" | "featurebase" | "hearloop" | "generic"Yes
entity"posts" | "votes" | "comments"Yes
status"pending" | "running" | "completed" | "failed" | "canceled"Yes
dry_runbooleanYes
board_idstring (uuid) | nullYes
progressobjectYes
progress.rows_totalinteger | nullvalue ≥ 0Yes
progress.rows_processedintegervalue ≥ 0Yes
progress.rows_failedintegervalue ≥ 0Yes
progress.rows_warnedintegervalue ≥ 0Yes
countsobjectYes
counts.posts_createdintegervalue ≥ 0Yes
counts.posts_updatedintegervalue ≥ 0Yes
counts.posts_unchangedintegervalue ≥ 0Yes
counts.votes_createdintegervalue ≥ 0Yes
counts.votes_existingintegervalue ≥ 0Yes
counts.comments_createdintegervalue ≥ 0Yes
counts.comments_updatedintegervalue ≥ 0Yes
counts.comments_unchangedintegervalue ≥ 0Yes
counts.end_users_createdintegervalue ≥ 0Yes
counts.statuses_createdintegervalue ≥ 0Yes
counts.tags_createdintegervalue ≥ 0Yes
errorsarray of objectitems ≤ 200Yes
errors[].rowintegervalue ≥ 1Yes
errors[].columnstring | nulllength ≤ 200Yes
errors[].code"required" | "too_long" | "invalid_email" | "invalid_date" | "invalid_number" | "invalid_eta" | "unknown_board" | "board_archived" | "board_private_votes" | "post_not_found" | "parent_not_found" | "reply_depth" | "end_user_deleted" | "plan_limit" | "changed_since_import" | "duplicate_in_file" | "too_many_values" | "row_failed"Yes
errors[].severity"error" | "warning"Yes
errors[].messagestringlength ≤ 300Yes
errors_truncatedbooleanYes
errorobject | nullYes
error.code"upload_missing" | "file_too_large" | "invalid_encoding" | "empty_file" | "too_many_columns" | "too_many_rows" | "field_too_long" | "record_too_long" | "unterminated_quote" | "missing_columns" | "delimiter_mismatch" | "duplicate_headers" | "board_unavailable" | "post_not_found" | "storage_unavailable" | "stalled" | "internal_error"Yes
error.messagestringYes
cancel_requestedbooleanYes
created_atstring (date-time)Yes
started_atstring (date-time) | nullYes
finished_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/imports/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d/cancel' \
  -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/imports/{id}/cancel', {
  path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' },
  body: {},
});
MCP

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