Custom domains
Custom portal hostnames and their verification.
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/domains
The workspace custom domain with live status, DNS records and the CNAME target (owner/admin)
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
Response 200: 21 fields
| Name | Type | Required |
|---|---|---|
items | array of objectitems ≤ 2 | Yes |
items[].id | string (uuid) | Yes |
items[].hostname | stringlength 1–253 | Yes |
items[].display_hostname | stringlength 1–1012 | Yes |
items[].status | "pending" | "active" | "failed" | "removing" | Yes |
items[].failure_reason | "verification_timeout" | "dns_not_pointed" | "certificate_failed" | "blocked" | "hostname_deleted" | null | Yes |
items[].hostname_status | string | nullpattern ^[a-z_]{1,40}$ | Yes |
items[].certificate_status | string | nullpattern ^[a-z_]{1,40}$ | Yes |
items[].verification_errors | array of stringitems ≤ 5 | Yes |
items[].records | array of objectitems ≤ 6 | Yes |
items[].records[].type | "CNAME" | "TXT" | Yes |
items[].records[].name | stringlength 1–300 | Yes |
items[].records[].value | stringlength 1–300 | Yes |
items[].records[].purpose | "routing" | "ownership" | "certificate" | Yes |
items[].records[].required | boolean | Yes |
items[].created_at | string (date-time) | Yes |
items[].activated_at | string (date-time) | null | Yes |
items[].last_checked_at | string (date-time) | null | Yes |
items[].next_check_at | string (date-time) | null | Yes |
cname_target | stringlength 1–253 | Yes |
max_domains | 1 | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl 'https://api.upvoiced.com/v1/workspace/domains' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID"const data = await upvoiced.get('/v1/workspace/domains');No MCP tool for this operation. The MCP server covers the everyday reads and writes.
POST/v1/workspace/domains
Connect a custom domain (custom_domain, Starter and above; one per workspace): returns the CNAME target and TXT pre-validation records
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
idempotency-key | stringpattern ^[A-Za-z0-9_.:-]{8,128}$ | No |
| Name | Type | Required |
|---|---|---|
hostname | stringlength 1–1012 | Yes |
Response 201: 18 fields
| Name | Type | Required |
|---|---|---|
id | string (uuid) | Yes |
hostname | stringlength 1–253 | Yes |
display_hostname | stringlength 1–1012 | Yes |
status | "pending" | "active" | "failed" | "removing" | Yes |
failure_reason | "verification_timeout" | "dns_not_pointed" | "certificate_failed" | "blocked" | "hostname_deleted" | null | Yes |
hostname_status | string | nullpattern ^[a-z_]{1,40}$ | Yes |
certificate_status | string | nullpattern ^[a-z_]{1,40}$ | Yes |
verification_errors | array of stringitems ≤ 5 | Yes |
records | array of objectitems ≤ 6 | Yes |
records[].type | "CNAME" | "TXT" | Yes |
records[].name | stringlength 1–300 | Yes |
records[].value | stringlength 1–300 | Yes |
records[].purpose | "routing" | "ownership" | "certificate" | Yes |
records[].required | boolean | Yes |
created_at | string (date-time) | Yes |
activated_at | string (date-time) | null | Yes |
last_checked_at | string (date-time) | null | Yes |
next_check_at | string (date-time) | null | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X POST 'https://api.upvoiced.com/v1/workspace/domains' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"hostname": "Example hostname"
}'const data = await upvoiced.post('/v1/workspace/domains', { body: { hostname: 'Example hostname' } });No MCP tool for this operation. The MCP server covers the everyday reads and writes.
DELETE/v1/workspace/domains/{id}
Remove the custom domain: the portal returns to its UpVoiced subdomain; the hostname is released
| Name | Type | Required |
|---|---|---|
id | string (uuid) | Yes |
| Name | Type | Required |
|---|---|---|
x-workspace | string (uuid) | Yes |
Response 200: 18 fields
| Name | Type | Required |
|---|---|---|
id | string (uuid) | Yes |
hostname | stringlength 1–253 | Yes |
display_hostname | stringlength 1–1012 | Yes |
status | "pending" | "active" | "failed" | "removing" | Yes |
failure_reason | "verification_timeout" | "dns_not_pointed" | "certificate_failed" | "blocked" | "hostname_deleted" | null | Yes |
hostname_status | string | nullpattern ^[a-z_]{1,40}$ | Yes |
certificate_status | string | nullpattern ^[a-z_]{1,40}$ | Yes |
verification_errors | array of stringitems ≤ 5 | Yes |
records | array of objectitems ≤ 6 | Yes |
records[].type | "CNAME" | "TXT" | Yes |
records[].name | stringlength 1–300 | Yes |
records[].value | stringlength 1–300 | Yes |
records[].purpose | "routing" | "ownership" | "certificate" | Yes |
records[].required | boolean | Yes |
created_at | string (date-time) | Yes |
activated_at | string (date-time) | null | Yes |
last_checked_at | string (date-time) | null | Yes |
next_check_at | string (date-time) | null | Yes |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, 503, all in the standard error shape.
curl -X DELETE 'https://api.upvoiced.com/v1/workspace/domains/0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID"const data = await upvoiced.delete('/v1/workspace/domains/{id}', { path: { id: '0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d' } });No MCP tool for this operation. The MCP server covers the everyday reads and writes.