Skip to content
UpVoiced Docs

API guides

Errors

Every failure returns the same JSON shape. Branch on error.code, a stable machine-readable string; message is for people and may change.

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed.",
    "details": [{ "path": "title", "code": "too_small" }]
  }
}

details is present on validation errors: up to 20 entries, each with the field path (dotted, for example tag_ids.3) and a code such as too_small, invalid_format or unrecognized_keys.

Status codes

Statuses and common error codes
StatusMeaningCommon codes
400The request is malformed or fails validation.invalid_request, invalid_json, invalid_cursor
401No valid credentials.unauthenticated
403Authenticated, but not allowed.forbidden, insufficient_scope, workspace_not_allowed, session_required, plan_required, owner_required
404The resource does not exist in this workspace, or you cannot see it.not_found
409The request conflicts with the current state.conflict, concurrent_update, idempotency_conflict, slug_taken, plan_limit
413The body is too large.body_too_large
415The body is not JSON.unsupported_media_type
422Well-formed, but the change cannot be applied.invalid_state, unknown_board, invalid_webhook_url, constraint_violation
429Too many requests: wait for Retry-After seconds.rate_limited
500An unexpected error on our side.internal_error
503A dependency is unavailable: retry after Retry-After seconds when present.unavailable, not_ready

Operations add their own codes where it helps (for example hostname_taken for custom domains); the list above is not exhaustive, so handle unknown codes by status.

What to retry

With the SDK

@upvoiced/sdk throws an UpVoicedError carrying the same fields, and already retries 429, 503 and network errors where that is safe:

import { UpVoiced, UpVoicedError } 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 });

try {
  await upvoiced.post('/v1/posts', {
    body: { board_id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d', title: '' },
  });
} catch (error) {
  if (!(error instanceof UpVoicedError)) throw error;
  console.log(error.status); // 400
  console.log(error.code); // 'invalid_request'
  console.log(error.details); // [{ path: 'title', code: 'too_small' }]
  console.log(error.retryAfter); // seconds, on 429 and 503
}