Skip to content
UpVoiced Docs

API reference

Branding

Portal and widget branding, custom CSS and import from your site.

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/workspace/branding

Get branding

Authentication
API key or Dashboard session; API key scope read
Operation id
getBranding
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 32 fields
Response 200 (application/json)
NameTypeRequired
preset"ink" | "ocean" | "forest" | "citrus" | "plum" | "mono"Yes
accentstringpattern ^#[0-9a-fA-F]{6}$Yes
scheme"light" | "dark" | "auto"Yes
font"system" | "source-sans" | "inter" | "geist" | "manrope" | "source-serif" | "fraunces" | "ibm-plex" | "jetbrains-mono"Yes
radius"none" | "sm" | "md" | "lg" | "full"Yes
density"comfortable" | "compact"Yes
surface"flat" | "elevated"Yes
show_powered_bybooleanYes
layoutobjectYes
layout.portal_navarray of "board" | "roadmap" | "changelog" | "wall"items ≤ 4Yes
layout.portal_header"logo-left" | "centered" | "minimal"Yes
layout.post_card"compact" | "comfortable"Yes
layout.roadmap_card"title-only" | "with-excerpt"Yes
layout.changelog"timeline" | "cards"Yes
layout.wall_default"grid" | "masonry" | "carousel" | "list" | "spotlight"Yes
layout.widget_launcher"icon" | "pill" | "tab"Yes
layout.widget_position"bottom-right" | "bottom-left" | "right-middle" | "left-middle"Yes
logoobject | nullYes
logo.idstring (uuid)Yes
logo.urlstring (uri)Yes
logo.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
logo.bytesintegervalue ≤ 2097152value > 0Yes
faviconobject | nullYes
favicon.idstring (uuid)Yes
favicon.urlstring (uri)Yes
favicon.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
favicon.bytesintegervalue ≤ 2097152value > 0Yes
og_imageobject | nullYes
og_image.idstring (uuid)Yes
og_image.urlstring (uri)Yes
og_image.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
og_image.bytesintegervalue ≤ 2097152value > 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/workspace/branding' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID"
TypeScript SDK
const data = await upvoiced.get('/v1/workspace/branding');
MCP

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

PUT/v1/workspace/branding

Update branding fields; plan-gated (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
updateBranding
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Request body (JSON)
NameTypeRequired
preset"ink" | "ocean" | "forest" | "citrus" | "plum" | "mono"No
accentstringpattern ^#[0-9a-fA-F]{6}$No
scheme"light" | "dark" | "auto"No
font"system" | "source-sans" | "inter" | "geist" | "manrope" | "source-serif" | "fraunces" | "ibm-plex" | "jetbrains-mono"No
radius"none" | "sm" | "md" | "lg" | "full"No
density"comfortable" | "compact"No
surface"flat" | "elevated"No
show_powered_bybooleanNo
layoutobjectNo
layout.portal_navarray of "board" | "roadmap" | "changelog" | "wall"items ≤ 4Yes
layout.portal_header"logo-left" | "centered" | "minimal"Yes
layout.post_card"compact" | "comfortable"Yes
layout.roadmap_card"title-only" | "with-excerpt"Yes
layout.changelog"timeline" | "cards"Yes
layout.wall_default"grid" | "masonry" | "carousel" | "list" | "spotlight"Yes
layout.widget_launcher"icon" | "pill" | "tab"Yes
layout.widget_position"bottom-right" | "bottom-left" | "right-middle" | "left-middle"Yes
logo_asset_idstring (uuid) | nullNo
favicon_asset_idstring (uuid) | nullNo
og_image_asset_idstring (uuid) | nullNo
custom_cssstringlength ≤ 20480No
Response 200: 32 fields
Response 200 (application/json)
NameTypeRequired
preset"ink" | "ocean" | "forest" | "citrus" | "plum" | "mono"Yes
accentstringpattern ^#[0-9a-fA-F]{6}$Yes
scheme"light" | "dark" | "auto"Yes
font"system" | "source-sans" | "inter" | "geist" | "manrope" | "source-serif" | "fraunces" | "ibm-plex" | "jetbrains-mono"Yes
radius"none" | "sm" | "md" | "lg" | "full"Yes
density"comfortable" | "compact"Yes
surface"flat" | "elevated"Yes
show_powered_bybooleanYes
layoutobjectYes
layout.portal_navarray of "board" | "roadmap" | "changelog" | "wall"items ≤ 4Yes
layout.portal_header"logo-left" | "centered" | "minimal"Yes
layout.post_card"compact" | "comfortable"Yes
layout.roadmap_card"title-only" | "with-excerpt"Yes
layout.changelog"timeline" | "cards"Yes
layout.wall_default"grid" | "masonry" | "carousel" | "list" | "spotlight"Yes
layout.widget_launcher"icon" | "pill" | "tab"Yes
layout.widget_position"bottom-right" | "bottom-left" | "right-middle" | "left-middle"Yes
logoobject | nullYes
logo.idstring (uuid)Yes
logo.urlstring (uri)Yes
logo.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
logo.bytesintegervalue ≤ 2097152value > 0Yes
faviconobject | nullYes
favicon.idstring (uuid)Yes
favicon.urlstring (uri)Yes
favicon.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
favicon.bytesintegervalue ≤ 2097152value > 0Yes
og_imageobject | nullYes
og_image.idstring (uuid)Yes
og_image.urlstring (uri)Yes
og_image.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
og_image.bytesintegervalue ≤ 2097152value > 0Yes

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

curl
curl -X PUT 'https://api.upvoiced.com/v1/workspace/branding' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "preset": "ink"
}'
TypeScript SDK
const data = await upvoiced.put('/v1/workspace/branding', { body: { preset: 'ink' } });
MCP

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

GET/v1/workspace/branding/custom-css

Custom CSS draft, stored sanitized output and whether the plan applies it (owner/admin; Growth+)

Authentication
API key or Dashboard session; API key scope admin
Operation id
getCustomCss
Headers
NameTypeRequired
x-workspacestring (uuid)Yes
Response 200: 4 fields
Response 200 (application/json)
NameTypeRequired
draftstringlength ≤ 20480Yes
cssstringlength ≤ 65536Yes
entitledbooleanYes
appliedbooleanYes

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

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

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

POST/v1/workspace/branding/custom-css/lint

Lint a custom CSS draft with the parser-based sanitizer without saving it (owner/admin; Growth+)

Authentication
API key or Dashboard session; API key scope admin
Operation id
lintCustomCss
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
cssstringlength ≤ 20480Yes
Response 200: 10 fields
Response 200 (application/json)
NameTypeRequired
okbooleanYes
bytesintegervalue ≥ 0Yes
issuesarray of objectitems ≤ 100Yes
issues[].severity"error" | "warning"Yes
issues[].code"too_large" | "output_too_large" | "parse_error" | "import_not_allowed" | "at_rule_not_allowed" | "nesting_not_allowed" | "selector_not_allowed" | "selector_outside_root" | "attribute_selector_not_allowed" | "too_complex" | "property_not_allowed" | "value_not_allowed" | "function_not_allowed" | "expression_not_allowed" | "url_not_allowed" | "position_fixed_outside_root" | "focus_outline_removed" | "important_removed"Yes
issues[].messagestringlength 1–300Yes
issues[].lineintegervalue ≥ 1Yes
issues[].columnintegervalue ≥ 1Yes
cssstringlength ≤ 65536Yes
preview_cssstringlength ≤ 65536Yes

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/workspace/branding/custom-css/lint' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "css": "Example css"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/workspace/branding/custom-css/lint', { body: { css: 'Example css' } });
MCP

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

POST/v1/workspace/branding/reset

Reset branding to the Ocean defaults (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
resetBranding
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 200: 32 fields
Response 200 (application/json)
NameTypeRequired
preset"ink" | "ocean" | "forest" | "citrus" | "plum" | "mono"Yes
accentstringpattern ^#[0-9a-fA-F]{6}$Yes
scheme"light" | "dark" | "auto"Yes
font"system" | "source-sans" | "inter" | "geist" | "manrope" | "source-serif" | "fraunces" | "ibm-plex" | "jetbrains-mono"Yes
radius"none" | "sm" | "md" | "lg" | "full"Yes
density"comfortable" | "compact"Yes
surface"flat" | "elevated"Yes
show_powered_bybooleanYes
layoutobjectYes
layout.portal_navarray of "board" | "roadmap" | "changelog" | "wall"items ≤ 4Yes
layout.portal_header"logo-left" | "centered" | "minimal"Yes
layout.post_card"compact" | "comfortable"Yes
layout.roadmap_card"title-only" | "with-excerpt"Yes
layout.changelog"timeline" | "cards"Yes
layout.wall_default"grid" | "masonry" | "carousel" | "list" | "spotlight"Yes
layout.widget_launcher"icon" | "pill" | "tab"Yes
layout.widget_position"bottom-right" | "bottom-left" | "right-middle" | "left-middle"Yes
logoobject | nullYes
logo.idstring (uuid)Yes
logo.urlstring (uri)Yes
logo.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
logo.bytesintegervalue ≤ 2097152value > 0Yes
faviconobject | nullYes
favicon.idstring (uuid)Yes
favicon.urlstring (uri)Yes
favicon.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
favicon.bytesintegervalue ≤ 2097152value > 0Yes
og_imageobject | nullYes
og_image.idstring (uuid)Yes
og_image.urlstring (uri)Yes
og_image.mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
og_image.bytesintegervalue ≤ 2097152value > 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/workspace/branding/reset' \
  -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/workspace/branding/reset', { body: {} });
MCP

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

POST/v1/workspace/branding/import

Suggest colours, font, logo and favicon from a site via the SSRF-safe fetcher; writes nothing (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
importBranding
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
urlstringlength 3–2048Yes
Response 200: 23 fields
Response 200 (application/json)
NameTypeRequired
urlstring (uri)length ≤ 2048Yes
namestring | nulllength ≤ 80Yes
accentstring | nullpattern ^#[0-9a-fA-F]{6}$Yes
colorsarray of objectitems ≤ 8Yes
colors[].hexstringpattern ^#[0-9a-fA-F]{6}$Yes
colors[].sourcesarray of "theme-color" | "manifest-theme" | "manifest-background" | "mask-icon" | "tile-color" | "css-variable" | "css-button" | "css" | "icon" | "logo"items 1–10Yes
colors[].neutralbooleanYes
fontobject | nullYes
font.font"system" | "source-sans" | "inter" | "geist" | "manrope" | "source-serif" | "fraunces" | "ibm-plex" | "jetbrains-mono"Yes
font.familystringlength ≤ 64Yes
font.source"css-body" | "css-variable" | "css-heading" | "font-face" | "css"Yes
detected_fontsarray of stringitems ≤ 8Yes
assetsarray of objectitems ≤ 8Yes
assets[].urlstring (uri)length ≤ 2048Yes
assets[].kind"logo-img" | "apple-touch-icon" | "manifest-icon" | "mask-icon" | "icon" | "og-image"Yes
assets[].rolesarray of "logo" | "favicon"items 1–2Yes
assets[].mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
assets[].bytesintegervalue ≤ 2097152value > 0Yes
assets[].widthinteger | nullvalue > 0Yes
assets[].heightinteger | nullvalue > 0Yes
assets[].sha256stringpattern ^[0-9a-f]{64}$Yes
assets[].previewstring | nulllength ≤ 800000pattern ^data:image\/(png|jpeg|webp|svg\+xml);base64,[A-Za-z0-9+/=]+$Yes
warningsarray of "manifest_unavailable" | "stylesheet_unavailable" | "stylesheets_truncated" | "asset_unavailable" | "svg_rejected" | "unsupported_image" | "deadline_reached"items ≤ 10Yes

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/workspace/branding/import' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/upvoiced"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/workspace/branding/import', { body: { url: 'https://example.com/upvoiced' } });
MCP

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

POST/v1/workspace/branding/import/asset

Re-fetch a chosen logo/favicon, validate or sanitize it and store it as a ready branding asset (owner/admin)

Authentication
API key or Dashboard session; API key scope admin
Operation id
importBrandingAsset
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
urlstringlength 8–2048Yes
role"logo" | "favicon"Yes
sha256stringpattern ^[0-9a-f]{64}$No
Response 201: 4 fields
Response 201 (application/json)
NameTypeRequired
idstring (uuid)Yes
urlstring (uri)Yes
mime"image/png" | "image/svg+xml" | "image/jpeg" | "image/webp"Yes
bytesintegervalue ≤ 2097152value > 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/workspace/branding/import/asset' \
  -H "Authorization: Bearer $UPVOICED_API_KEY" \
  -H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/upvoiced",
  "role": "logo"
}'
TypeScript SDK
const data = await upvoiced.post('/v1/workspace/branding/import/asset', {
  body: { url: 'https://example.com/upvoiced', role: 'logo' },
});
MCP

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