API Docs

REST API

Note: The URL used in this document (vas-poc.vurbo.ai) is the planned deployment URL. A separate notice will be provided once the service goes live.


Table of Contents


API Overview

ItemValue
Base Pathhttps://vas-poc.vurbo.ai/api/v1
ProtocolHTTPS
Data FormatJSON

Authentication

APIs that require authentication pass the API Key via an HTTP header:

X-API-Key: vas_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API Categories

CategoryPath PrefixAuthenticationPurpose
Tasks API/api/v1/tasksHeader X-API-KeyTask management, audio/transcript export
Import API/api/v1/importsHeader X-API-KeyAudio import
Audio API/api/v1/sse/audioHeader X-API-KeyAudio file playback
TTS API/api/v1/ttsHeader X-API-KeyTTS voice service
Broadcasts API/api/v1/broadcastsHeader X-API-KeyBroadcast management
Viewer API/api/v1/viewer/broadcastsNoneViewer-side public info
Recording Speaker API/api/v1/tasks/{taskId}/speakersHeader X-API-KeyTranscript speaker editing (since V1.4.1 the recordings path is a deprecated alias, removed in V1.6.0)
Summary Template API/api/v1/summary-templatesHeader X-API-KeySummary template lookup
Broadcast REST API/broadcastToken (path parameter)Broadcast real-time status
Version API/api/v1/versionNoneDeployed version lookup (for pre-release version gates)
My Plan API/api/v1/me/planHeader X-API-KeyLook up the current billing mode, plan contents, and usage (v1.9.0)
Key Self-Service API/api/v1/me/credit-lots, /api/v1/me/usage, /api/v1/me/keyHeader X-API-KeyLook up this API Key's credit lots, usage history, and settings (V1.21.0)
Glossary Validation API/api/v1/glossary/validateHeader X-API-KeyCheck a glossary for conflicts before saving (V1.14.0, served by the realtime service domain)

GET /api/v1/version (Look Up the Deployed Version)

Description

Reports the version currently deployed, so integrators can run a version gate before going live — for example, "this fix requires ≥ vX.Y.Z".

No authentication required, consistent with health-check endpoints. A version gate that fails on authentication would be indistinguishable from a version mismatch, defeating its purpose.

Note: The realtime service and the REST service are versioned independently and may report different versions. If the fix you need to verify belongs to live recording or broadcasting (WebSocket), query the realtime service's /version instead (see below).

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/version"

Success Response (HTTP 200)

{
  "service": "vas-api",
  "version": "1.7.7",
  "build": "a1b2c3d4e5f6"
}

Response Fields

FieldTypeDescription
servicestringService identifier: vas-api (REST) or vas-realtime (WebSocket)
versionstringPlatform version, matching this documentation's version (e.g. 1.7.7)
buildstringBuild identifier for tracing a specific build; one version may have several builds

Realtime (WebSocket) Service Version

The realtime service exposes the same endpoint at /version.

Use the same host you connect to over WebSocket, swapping the wss:// scheme for https://. (In some environments the realtime and REST services live on different hosts — use the connection settings you were issued.)

# If your WebSocket connection is wss://<realtime-host>/ws
curl -X GET "https://<realtime-host>/version"
{
  "service": "vas-realtime",
  "version": "1.7.7",
  "build": "a1b2c3d4e5f6"
}

This endpoint is available from V1.7.7 onward, which means:

  • The endpoint responds → the version is necessarily ≥ V1.7.7; compare version directly.
  • The endpoint returns 404 → the version predates V1.7.7 and cannot be determined here; please confirm with your service contact.

GET /api/v1/me/plan (Look Up My Plan)

Description

Look up the billing mode and plan contents this API Key currently operates under (added in v1.9.0). When blocked by a plan limit such as plan_feature_not_allowed (HTTP 403) or plan_daily_limit_reached (HTTP 402), use this endpoint to answer "what does my plan include, how far am I from a limit, and when does the restriction lift?"

Read-only endpoint: still available after credits run out.

The full request/response specification (complete field tables for the three response shapes) is in reference/rest/me-plan.md.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/me/plan" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response (HTTP 200)

The response shape depends on the billing mode:

Unlimited plan (mode: "unlimited", plan-bound):

{
  "data": {
    "mode": "unlimited",
    "plan": {
      "name": "專業方案",
      "expired_at": "2027-07-31T23:59:59+08:00"
    },
    "features": [
      { "slug": "stt", "name": "基礎語音轉錄", "included": true },
      { "slug": "diarization", "name": "語者分離", "included": true },
      { "slug": "broadcast", "name": "廣播", "included": false }
    ],
    "oneoff_features": [
      { "slug": "summary", "name": "AI 會議摘要", "included": true },
      { "slug": "import", "name": "檔案匯入", "included": false }
    ],
    "limits": {
      "daily_soft_limit_minutes": 480,
      "daily_hard_limit_minutes": 600,
      "max_concurrent_sessions": 2,
      "daily_used_minutes": 123,
      "max_transcription_languages": 4,
      "max_session_minutes": 240,
      "rolling_limit_minutes": 3000,
      "rolling_used_minutes": 850,
      "auth_total_limit_minutes": 60000,
      "auth_total_used_minutes": 12345,
      "restriction_recovery_at": null
    }
  }
}

Credit mode (mode: "credit"):

{
  "data": {
    "mode": "credit",
    "plan": null,
    "available_credit": 480.5
  }
}

Unlimited authorization with no plan restrictions (mode: "unlimited", rare):

{
  "data": {
    "mode": "unlimited",
    "plan": null,
    "features": { "all": true },
    "expired_at": "2027-01-31T23:59:59+08:00"
  }
}

Main fields: features[] lists per-minute billed features (included indicates whether the plan includes them; broadcasting is always false), oneoff_features[] lists one-off features (summary, full-text re-translation, audio import), and limits holds the plan's limits and current usage (null = unrestricted). The full field reference is in reference/rest/me-plan.md.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
auth_missing_api_key401API Key not providedMake sure the header includes the API Key
auth_invalid_api_key401Invalid API KeyVerify that the API Key is correct

GET /api/v1/me/credit-lots, /me/usage, /me/key (API Key Self-Service)

Description

Use an API Key to look up its own credit lots, usage history, and settings (added in V1.21.0). All three are read-only endpoints, queryable even with zero balance, and return only this API Key's own data.

EndpointPurpose
GET /api/v1/me/credit-lotsCredit lots drawn on when charging (the dedicated allotment and, when allowed, account credit); only lots with credit left that have not expired, soonest expiry first
GET /api/v1/me/usageCharge history, one row per recording / broadcast and per import / summary / retranslation, newest first; supports page and per_page (5 to 20, default 20)
GET /api/v1/me/keyThe API Key's name, expiry date, monthly credit limit and this month's spend, concurrency limit, webhook URL, and whether a source IP restriction is configured

The full request/response specification is in reference/rest/me-key.md.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/me/usage?page=1&per_page=20" \
  -H "X-API-Key: YOUR_API_KEY"

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
validation_failed422Invalid page or per_page on /me/usageUse page ≥ 1 and an integer per_page from 5 to 20
auth_missing_api_key401API Key not providedMake sure the header includes the API Key
auth_invalid_api_key401Invalid API KeyVerify that the API Key is correct

GET /api/v1/tasks (List Tasks)

Description

Retrieve the recording task list for the current user. You can use the status parameter to filter tasks by processing stage, or task_ids[] to query specific tasks only.

Use Cases

  • Display the task history list
  • View completed recordings
  • Query in-progress recording tasks
  • Check the current processing status of specific tasks

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters (Query)

ParameterTypeRequiredDefaultDescription
statusstringNocompletedFilter task status: completed, active, all
task_ids[]string[]No—Query these tasks only (each element is a UUID, 1–100 entries)
status ValueDescription
completedReturn only completed tasks (default, backward compatible)
activeReturn in-progress tasks (recording, importing, uploading, processing)
allReturn all tasks without filtering by status

task_ids Filter Details

  • Returns only the listed tasks that belong to the current account. IDs that do not exist or do not belong to the current account are skipped without an error.
  • status still applies: without status, only completed tasks are returned. To look up the listed tasks regardless of status, add status=all.
  • The response format is the same as without task_ids.
  • More than 100 entries, an entry that is not a UUID, or task_ids that is not an array (for example, task_ids=<UUID> without []) returns 422 validation_failed.

Request Example

# Default query (completed tasks)
curl -X GET "https://vas-poc.vurbo.ai/api/v1/tasks" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

# Query in-progress tasks
curl -X GET "https://vas-poc.vurbo.ai/api/v1/tasks?status=active" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

# Query specific tasks only (regardless of status, add status=all)
curl -G "https://vas-poc.vurbo.ai/api/v1/tasks" \
  --data-urlencode "task_ids[]=550e8400-e29b-41d4-a716-446655440000" \
  --data-urlencode "task_ids[]=6ba7b810-9dad-11d1-80b4-00c04fd430c8" \
  --data-urlencode "status=all" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

FieldTypeDescription
data.tasksarrayTask list
data.tasks[].task_idstringTask ID (UUID)
data.tasks[].titlestringTask title
data.tasks[].typestringRecording type
data.tasks[].type_sourcestringSource type (realtime / import / broadcast)
data.tasks[].duration_msnumberRecording duration (milliseconds)
data.tasks[].duration_formattedstringFormatted duration (min:sec)
data.tasks[].transcription_languagesarrayTranscription language list
data.tasks[].translation_languagesarrayTranslation language list
data.tasks[].created_atstringCreation time (ISO 8601)
data.tasks[].processing_statusstringProcessing status
data.tasks[].is_pinnedbooleanWhether pinned
data.tasks[].is_unreadbooleanWhether unread

processing_status Values

StatusDescriptionApplicable Scenario
recordingRecording in progressReal-time recording, broadcast
importingAudio import in progressAudio import
uploadingUploading to the cloudUpload phase after recording stops
processingPost-processingSummary, translation, etc.
completedProcessing completeAll scenarios
failedProcessing failedAll scenarios

Response Example

{
  "data": {
    "tasks": [
      {
        "task_id": "550e8400-e29b-41d4-a716-446655440000",
        "title": "Meeting Notes",
        "type": "transcribe",
        "type_source": "realtime",
        "duration_ms": 60000,
        "duration_formatted": "1:00",
        "transcription_languages": ["zh-TW"],
        "translation_languages": ["en-US"],
        "created_at": "2026-02-25T10:00:00Z",
        "processing_status": "completed",
        "is_pinned": false,
        "is_unread": true
      }
    ]
  }
}

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
auth_missing_api_key401API Key not providedMake sure the header includes the API Key
auth_invalid_api_key401Invalid API KeyVerify that the API Key is correct
validation_failed422Parameter validation failedVerify that task_ids is a UUID array of 1–100 entries

DELETE /api/v1/tasks/{taskId} (Delete Task)

Description

Delete the specified task. Deletion is permanent and cannot be undone: the task is removed together with its audio, transcript, summary, translations, and imported source file, and can no longer be queried, exported, or retranslated.

A task that is still being processed cannot be deleted (processing_status is recording, importing, uploading, pending, or processing, or the task's import is still being processed); the request returns 422 invalid_processing_status. Wait until it completes or fails before deleting it. If a task is stuck, you can first mark it as failed with POST /api/v1/tasks/{taskId}/force-fail. This does not help when the task's import is still being processed; wait until the import finishes, then delete the task.

Use Cases

  • Clear recording records you no longer need
  • Organize the task list

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask ID (UUID)

Request Example

curl -X DELETE "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "message": "Task deleted"
}

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct
invalid_processing_status422The task is still being processed and cannot be deletedWait until the task completes or fails; for a stuck recording, use force-fail first. If the import is still being processed, wait until it finishes

PUT /api/v1/tasks/batch/pin (Batch Update Pin Status)

Description

Batch update the pin status of multiple tasks. Up to 100 tasks can be operated on per request. Only tasks belonging to the current user are affected; IDs that do not belong to the user are ignored.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDescription
task_idsbodyarrayYesArray of task IDs (each element a UUID, up to 100)
is_pinnedbodybooleanYesPin status

Request Example

curl -X PUT "https://vas-poc.vurbo.ai/api/v1/tasks/batch/pin" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "task_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
    ],
    "is_pinned": true
  }'

Success Response

{
  "data": {
    "affected_count": 2
  }
}

Response Fields

FieldTypeDescription
data.affected_countnumberNumber of tasks actually updated

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
validation_failed422Parameter validation failedMake sure task_ids is an array of UUIDs with no more than 100 entries, and is_pinned is a boolean

DELETE /api/v1/tasks/batch (Batch Delete Tasks)

Description

Batch delete multiple tasks. Deletion is permanent and cannot be undone, with the same scope as single-task deletion. Up to 100 tasks can be operated on per request. Only tasks belonging to the current user are affected; IDs that do not belong to the user are ignored.

Tasks that are still being processed are skipped and not deleted, and are listed in skipped_task_ids in the response. The remaining tasks are deleted as usual; the batch as a whole does not fail because of them.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDescription
task_idsbodyarrayYesArray of task IDs (each element a UUID, up to 100)

Request Example

curl -X DELETE "https://vas-poc.vurbo.ai/api/v1/tasks/batch" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "task_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
    ]
  }'

Success Response

{
  "data": {
    "affected_count": 2,
    "skipped_task_ids": []
  }
}

Response Fields

FieldTypeDescription
data.affected_countnumberNumber of tasks actually deleted
data.skipped_task_idsstring[]IDs of tasks that were not deleted because they are still being processed. Empty array when every requested task was deleted. IDs that do not belong to the current user never appear here

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
validation_failed422Parameter validation failedMake sure task_ids is an array of UUIDs with no more than 100 entries

PUT /api/v1/tasks/{taskId}/pin (Update Pin Status)

Description

Update the pin status of a task. Pinned tasks are displayed first in the list.

Use Cases

  • Mark important recordings
  • Quickly access frequently used tasks

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask ID (path parameter)
is_pinnedbooleanYesPin status

Request Example

curl -X PUT "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/pin" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{"is_pinned": true}'

Success Response

{
  "data": {
    "is_pinned": true
  }
}

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct
validation_failed422Parameter validation failedMake sure is_pinned is a boolean

PUT /api/v1/tasks/{taskId}/read (Mark as Read)

Description

Mark a task as read.

Use Cases

  • Mark recordings you have viewed
  • Clear the unread indicator

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask ID (path parameter)

Request Example

curl -X PUT "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/read" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "data": {
    "is_unread": false
  }
}

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct

PATCH /api/v1/tasks/{taskId}/name (Update Task Name)

Description

Update the name of the specified task.

Use Cases

  • Customize the recording title
  • Correct an automatically generated name

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask ID (path parameter)
namestringYesTask name (max 60 characters)

Request Example

curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/name" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{"name": "Product Meeting Discussion"}'

Success Response

{
  "message": "Recording name updated",
  "data": {
    "task_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Product Meeting Discussion",
    "name_source": "user"
  }
}
FieldTypeDescription
name_sourcestringName source: default, llm, user

Name Source Explanation:

name_sourceDescriptionTrigger Condition
userA name explicitly set by the userset_name, this REST API (the system will not override it)
llmAutomatically generated by the system from the transcriptAt the end of a recording, if name_source is not user, the system generates one automatically
defaultDefault nameThe name passed to start (initial default, the system may still override it) or type + sequence number (e.g. Transcription #1)

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct
recording_unauthorized403Not authorized to operate on this recordingConfirm the task belongs to the user
validation_failed422Validation failedMake sure name is not empty and its length is valid

GET /api/v1/tasks/{taskId}/audio/export (Download Task Audio)

Description

Download the original audio file of the specified task. The response is a binary audio stream with a Content-Disposition: attachment header, so a browser or download tool saves the content directly as a file. The file name uses the recording name first (a sanitized file name); if the name is empty, it falls back to audio.

Difference from the audio streaming API (GET /api/v1/sse/audio/{taskId}):

  • This endpoint: for offline download; the response includes a Content-Disposition: attachment header; Range Requests are not supported.
  • Audio streaming: for playback; supports HTTP Range Requests for seeking/fast-forward; the response does not force a download.

Use Cases

  • Save recording files offline
  • Batch export the original audio of all tasks

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDescription
taskIdpathstringYesTask ID (UUID)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/audio/export" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -OJ

Tip: curl -OJ lets curl automatically name the saved file based on the server's Content-Disposition response.

Success Response

HTTP 200

HTTP/1.1 200 OK
Content-Type: audio/mp4
Content-Length: 1234567
Content-Disposition: attachment; filename="audio.m4a"; filename*=UTF-8''%E6%9C%83%E8%AD%B0%E8%A8%98%E9%8C%84.m4a
Cache-Control: no-cache

Note: All recording audio files are returned as an M4A container (AAC encoding). Content-Type is fixed to audio/mp4, and the file extension is .m4a.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not found, or the audio file does not exist in cloud storageVerify that taskId is correct and the recording has not been deleted
recording_audio_not_ready422The audio file has not finished uploading or is still processingRetry later; first confirm via GET /api/v1/tasks that processing_status is completed
storage_download_failed500Storage service download failedRetry later; if it keeps failing, contact support

GET /api/v1/tasks/{taskId}/transcript/export (Download Transcript)

Description

Download the transcript of the specified task, supporting five formats: plain text, SubRip subtitles, YouTube SBV subtitles, WebVTT subtitles, and CSV spreadsheet. The response includes the original text and all translation languages; the response includes a Content-Disposition: attachment header for direct download. The file name uses the recording name first (a sanitized file name); if the name is empty, it falls back to transcript, and a -transcript.{ext} suffix is always appended.

Difference from the transcript history SSE API (GET /api/v1/sse/history/transcribe/{taskId}):

  • This endpoint: for offline download; returns the complete file at once; can be opened directly in subtitle software or a spreadsheet.
  • SSE history API: for progressive loading; pushes raw structured data sentence by sentence as an event stream (JSON fragments) for progressive rendering in the frontend UI.

Use Cases

  • Download the transcript for subtitle software (SRT / SBV / VTT)
  • Export CSV to open in Excel or data analysis tools
  • Save the plain-text transcript offline

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDefaultDescription
taskIdpathstringYes—Task ID (UUID)
formatquerystringNotxtFormat: txt / srt / sbv / vtt / csv

format Explanation

FormatTime FormatContent StructureTypical Use
txt—One line per segment, [Speaker] original text; translations indented 4 spaces as [language code] translated textReading, record keeping
srtHH:MM:SS,mmmIncludes a sequence number; after the time axis of each segment, the original text and translation each occupy one lineSubRip subtitles (DaVinci Resolve, VLC, etc.)
sbvH:MM:SS.mmmNo sequence number; the time axis is separated by ,; the original text and translation are joined with | into a single line (line breaks are replaced with spaces)YouTube subtitle upload
vttHH:MM:SS.mmmUses WEBVTT as the header; after the time axis of each segment, the original text and translation each occupy one lineHTML5 <track> subtitles, web players
csvHH:MM:SS (no milliseconds)Begins with a UTF-8 BOM; columns index,start,end,speaker,text,<one column per translation language>Excel, data analysis

Request Example

# Default TXT format
curl -X GET "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/transcript/export" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -OJ

# Specify SRT format
curl -X GET "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/transcript/export?format=srt" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -OJ

# CSV (Excel can open it directly; the UTF-8 BOM ensures non-ASCII text is not garbled)
curl -X GET "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/transcript/export?format=csv" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -OJ

Success Response

HTTP 200

HTTP/1.1 200 OK
Content-Type: text/csv; charset=UTF-8
Content-Length: 2048
Content-Disposition: attachment; filename="transcript.csv"; filename*=UTF-8''%E6%9C%83%E8%AD%B0%E8%A8%98%E9%8C%84-transcript.csv
Cache-Control: no-cache

Note: Content-Type is determined dynamically based on the format parameter:

FormatContent-Type
txttext/plain; charset=UTF-8
srtapplication/x-subrip
sbvtext/plain; charset=UTF-8
vtttext/vtt; charset=UTF-8
csvtext/csv; charset=UTF-8

Output Example

Assume the transcript contains two segments of English audio (en-US) and two translations (zh-TW, ja-JP):

TXT

[Alice] Hello, good morning
    [zh-TW] 你好,早安
    [ja-JP] おはよう
[Bob] Thanks
    [zh-TW] 多謝
    [ja-JP] ありがとう

SRT

1
00:00:00,500 --> 00:00:03,000
Hello, good morning
你好,早安
おはよう

2
00:00:03,000 --> 00:00:04,200
Thanks
多謝
ありがとう

SBV

0:00:00.500,0:00:03.000
Hello, good morning | 你好,早安 | おはよう

0:00:03.000,0:00:04.200
Thanks | 多謝 | ありがとう

VTT

WEBVTT

00:00:00.500 --> 00:00:03.000
Hello, good morning
你好,早安
おはよう

00:00:03.000 --> 00:00:04.200
Thanks
多謝
ありがとう

CSV (the file begins with a UTF-8 BOM EF BB BF)

index,start,end,speaker,text,zh-TW,ja-JP
1,00:00:00,00:00:03,Alice,"Hello, good morning",你好,早安,おはよう
2,00:00:03,00:00:04,Bob,Thanks,多謝,ありがとう

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct and the recording has not been deleted
recording_transcript_not_ready422The transcript has not finished generating or is emptyFirst confirm via GET /api/v1/tasks that processing_status = completed, then call again
validation_failed422Parameter validation failedMake sure format is one of the allowed values (txt / srt / sbv / vtt / csv)
storage_download_failed500Storage service download failedRetry later; if it keeps failing, contact support

POST /api/v1/tasks/{taskId}/force-fail (Force Mark as Failed)

Description

Force a task that is stuck in a non-terminal state (recording / importing / uploading / pending / processing) to be marked as failed. After a successful operation, processing_status becomes failed, processing_error is set to the reason provided by the user, and a recording.failed webhook is triggered (payload.failure_source = user_forced). Tasks already in a terminal state (completed / failed) will receive a 422.

For the full specification and frontend example, see: Tasks API — POST force-fail.

Authentication

Header: X-API-Key.

Request Parameters

ParameterLocationTypeRequiredDescription
taskIdpathstringYesTask ID (UUID)
reasonbodystring | nullNoFailure reason, up to 500 characters

Request Example

curl -X POST "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/force-fail" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{"reason": "The recording client was disconnected too long; giving up waiting"}'

Success Response

HTTP 200

{
  "data": {
    "task_id": "550e8400-e29b-41d4-a716-446655440000",
    "processing_status": "failed",
    "processing_error": "User-forced failure: The recording client was disconnected too long; giving up waiting (previous status: recording)"
  }
}

Error Responses

Error CodeHTTPDescriptionRecommended Action
recording_not_found404Recording not found or not owned by youVerify that taskId is correct
invalid_processing_status422The task is already in a terminal stateIf completed, use DELETE; if failed, there is no need to force it again
validation_failed422reason exceeds 500 characters or taskId is malformedCheck the length of reason and the UUID format

POST /api/v1/tasks/{taskId}/retry (Reprocess Failed Task)

Description

Re-enqueue a task that is in the failed state for processing. After a successful operation, processing_status becomes processing, and processing_error is cleared. Re-queuing happens only after the status update has taken effect, so it never reads a stale status.

Preconditions: processing_status = failed and audio_status = success and transcript_status = success. If any one fails, a 422 is returned (the details include audio_status / transcript_status to help diagnose).

For the full specification, see: Tasks API — POST retry.

Authentication

Header: X-API-Key.

Request Parameters

ParameterLocationTypeRequiredDescription
taskIdpathstringYesTask ID (UUID)

Request Example

curl -X POST "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/retry" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

HTTP 200

{
  "data": {
    "task_id": "550e8400-e29b-41d4-a716-446655440000",
    "processing_status": "processing"
  }
}

Error Responses

Error CodeHTTPDescriptiondetails FieldRecommended Action
recording_not_found404Recording not found or not owned by you—Verify that taskId is correct
invalid_processing_status422The task is not in the failed statecurrent_statusOnly failed tasks can be retried
invalid_processing_status422The audio / transcript was not fully uploadedcurrent_status, audio_status, transcript_statusConfirm the source is complete; if corrupted, use force-fail instead
task_already_processing409Another processing run for the same task has not finished yettask_idSend the same request again later; the task status was not changed

Audio Import API

The audio import API lets you upload audio files for speech recognition and translation.


POST /api/v1/imports/check-quota (Check Credit)

Description

Check whether the user has enough credit to upload an audio file of the specified duration. We recommend calling this API for a pre-check before uploading.

Use Cases

  • Check whether credit is sufficient before uploading an audio file
  • Display the remaining available credit

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
duration_msintegerYesAudio duration (milliseconds; 1 second to 10 hours by default -- the actual bounds follow the deployment setting and match the duration check applied after upload)

Request Example

curl -X POST "https://vas-poc.vurbo.ai/api/v1/imports/check-quota" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{"duration_ms": 3600000}'

Success Response

{
  "data": {
    "allowed": true,
    "reason": null,
    "is_unlimited": false,
    "remain_quota": 480.0,
    "duration_minutes": 60,
    "estimated_points": 60.0
  }
}
FieldTypeDescription
allowedbooleanWhether the upload is allowed (true when credit is sufficient or the plan allows it)
reasonstring | nullWhy the upload is not allowed: null (allowed) / insufficient_credit (insufficient credit; topping up resolves it) / plan_not_allowed (the plan does not include audio import; a plan upgrade is required) / plan_daily_limit_reached (today's plan usage is exhausted and resets tomorrow; topping up does not help, added in v1.16.4)
is_unlimitedbooleanWhether the account is unlimited (no point limit)
remain_quotafloat | nullRemaining credit points; null when unlimited. v1.9.0 semantics change: API Keys with a dedicated credit allotment receive the credit actually available to that key (its dedicated allotment, not the account's total balance); accounts without dedicated allotments see no change
duration_minutesintegerEstimated audio duration (minutes, rounded up)
estimated_pointsfloatEstimated points charged (STT-based; actual also includes translation/diarization, finalized at upload)

POST /api/v1/imports (Upload Audio)

Description

Upload an audio file for speech recognition and translation. After a successful upload, processing happens in the background, and you can track progress via the status query API.

Use Cases

  • Upload a recording file for transcription
  • Batch process audio files

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters (multipart/form-data)

ParameterTypeRequiredDescription
filefileYesAudio file (mp3/wav/m4a, max 500MB). The format is determined from the actual content; when the extension does not match the content, the file is processed according to its content
transcription_languagesstringYesTranscription languages (JSON array, e.g. ["zh-TW"])
translation_languagesstringNoTranslation languages (JSON array, e.g. ["en-US"])
recognition_modestringYesRecognition mode: single / multi_speaker. multi_language or multi_channel returns 422 import_recognition_mode_unsupported
summary_templatestringNoSummary template identifier (max 50 characters)
summary_modestringNoSummary mode: builtin (default, uses summary_template) or custom (uses summary_prompt). Omitted = uses summary_template
summary_promptstringNoFull custom prompt for custom mode (max 3000 chars, fully replaces the built-in template). Required for custom, prohibited otherwise
summary_prompt_slugstringNoCustom identifier for custom mode (max 64 chars, pass-through, not validated). Required for custom, prohibited otherwise
terminologystringNoTerminology list (JSON object, format below)
fuzzy_correctionstringNoFuzzy correction rules (JSON object)
translation_dictstringNoTranslation dictionary (JSON object, format below)
callback_urlstringNoWebhook callback URL (max 2048 characters)

Webhook notification: After you set callback_url, an HTTP POST notification is sent automatically when audio processing completes or fails. You can also specify a webhook_url in the API Key settings as a default callback. See the Webhook Guide.

Text Processing Parameter Formats

Terminology list (terminology): improves recognition accuracy for specific terms

{
  "zh-TW": [
    { "term": "語者分離" },
    { "term": "即時轉錄" }
  ]
}
  • Use the language code as the key and a term array as the value
  • term: term text (required, max 100 characters)
  • Up to 500 terms per language, and no more than 500 across all languages combined
  • Up to 4000 fuzzy-correction rules per language, and no more than 4000 across all languages combined

The numbers above are defaults: the limit actually in force can be tuned per environment; always treat the 422 response message as authoritative.

Note: Both limits are enforced: exceeding 500 entries in a single language, or 500 across all languages combined, returns 422 with the actual count. Plan multi-language vocabularies against the combined total.

Fuzzy correction (fuzzy_correction): corrects misspellings that sound different from the term

Usually no manual configuration is needed — misspellings that sound the same are already covered by terminology. It is needed only when the misspelling and the correct term sound different.

{
  "zh-TW": [
    { "correct": "語者分離", "incorrect": ["語這分離", "語者分力"] }
  ]
}
  • Use the language code as the key and a correction rule array as the value
  • correct: the correct term (required, up to 200 characters)
  • incorrect: a list of incorrect variants (conditionally required, each up to 200 characters)

Supplying only the correct term: when correct is Chinese (contains Han characters), incorrect may be omitted entirely — the system matches by pronunciation, and spellings in the transcript that sound the same or nearly the same are corrected back to correct.

{ "fuzzy_correction": { "zh-TW": [{ "correct": "艾思通" }] } }

No misspellings need to be listed above: 愛思通, 愛時通, 愛司東 and 愛似通 are all corrected. Only spellings that sound quite different (愛自動, say) or have a different number of syllables (愛松) still need to be listed in incorrect.

Note: Both conditions must hold: the language must be Chinese (zh-TW, zh-CN, zh-HK and so on) and correct must contain Han characters. Otherwise incorrect remains required — omitting it in those cases would have no effect at all, and accepting it would leave you believing the setting took.

  • case_insensitive: whether this rule's variants match regardless of case (optional, defaults to false = exact-case matching)

When the same incorrect variant appears in more than one rule: collisions are resolved on incorrect (the variant), not on correct. The case flag resolves to strict wins (if any rule leaves case_insensitive off, that variant is matched with exact case). Splitting one correct term across several rules is therefore safe, as long as their incorrect variants do not overlap.

Translation dictionary (translation_dict): specifies how proper nouns are translated. Entries are grouped by language code, giving each language its own dictionary.

{
  "en-US": [
    { "source": "語者分離", "target": "Speaker Diarization" }
  ]
}
  • Top-level key: the target language code
  • source: the original term (required, up to 200 characters)
  • target: the required translation for this language (required, up to 200 characters)
  • case_sensitive: whether the entry applies only on an exact-case match (optional, defaults to false = case-insensitive)
  • Up to 3000 entries per language

The previous format is still supported: the earlier array-of-entries format ([{ "source": ..., "translations": { "language code": ... } }]) is still accepted, with identical content and behavior. Existing integrations need no changes.

Case-flag comparison: the case switches in fuzzy_correction and translation_dict have opposite field names, and their default value produces opposite behavior —

BlockFieldDefaultDefault behavior
fuzzy_correctioncase_insensitivefalseStrict (case-sensitive)
translation_dictcase_sensitivefalsePermissive (case-insensitive)

Both default to false, yet one means strict and the other means permissive. Do not share a single variable between them or mirror one onto the other — getting it wrong produces no error at all, only matching behavior opposite to what you intended.

Note: The translation dictionary guides the model through prompting rather than literal substitution, so it is best-effort and the case flag is likewise a hint. Use fuzzy_correction when you need deterministic replacement.

Credit check: Credit balance is checked automatically during upload. If credit is insufficient, an auth_insufficient_credit error (HTTP 402) is returned.

Recommendation: Before uploading, use the check-quota API to pre-check whether credit is sufficient, to avoid discovering insufficient credit only after uploading a large file.

Request Example

Basic request

curl -X POST "https://vas-poc.vurbo.ai/api/v1/imports" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -F "file=@meeting.mp3" \
  -F 'transcription_languages=["zh-TW"]' \
  -F 'translation_languages=["en-US"]' \
  -F "recognition_mode=multi_speaker"

Request with text processing settings

curl -X POST "https://vas-poc.vurbo.ai/api/v1/imports" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -F "file=@meeting.mp3" \
  -F 'transcription_languages=["zh-TW"]' \
  -F 'translation_languages=["en-US"]' \
  -F "recognition_mode=multi_speaker" \
  -F 'terminology={"zh-TW": [{"term": "語者分離"}]}' \
  -F 'fuzzy_correction={"zh-TW": [{"correct": "語者分離", "incorrect": ["語這分離"]}]}' \
  -F 'translation_dict={"en-US": [{"source": "語者分離", "target": "Speaker Diarization"}]}'

Success Response (HTTP 202)

{
  "data": {
    "import_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "pending",
    "stage": null,
    "progress": 0,
    "message": null,
    "original_filename": "meeting.mp3",
    "file_size": "15.2 MB",
    "task_id": null,
    "error_code": null,
    "error_message": null,
    "created_at": "2026-01-03T10:00:00.000Z",
    "updated_at": "2026-01-03T10:00:00.000Z",
    "downgraded_features": []
  }
}

downgraded_features (v1.9.0): for unlimited plans that include audio import but not some sub-features (such as speaker diarization speaker_diarization or translation translation), those sub-features are skipped and the import proceeds as usual; the skipped features are listed in this array. An empty array means nothing was downgraded.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
import_file_too_large413File size exceeds the limitCompress or split the file
import_invalid_format415Unsupported audio formatUse mp3/wav/m4a format
import_recognition_mode_unsupported422This recognition mode is not supported for file imports (multi_language, multi_channel); data.details carries field and supportedModesUse single or multi_speaker
auth_insufficient_credit402Insufficient creditTop up your credit balance
plan_feature_not_allowed403The unlimited plan does not include audio importUpgrade the plan; query GET /api/v1/me/plan for the plan contents
plan_daily_limit_reached402The plan's daily usage limit has been reachedUpload again after the plan's reset (the next day)

GET /api/v1/imports/{importId} (Query Import Status)

Description

Query the processing status and progress of the specified import task.

Once the task created by an import is deleted, the corresponding import record is removed as well, and this request returns 404 import_not_found.

Use Cases

  • Track the processing progress of an uploaded audio file
  • Retrieve the task ID once processing completes

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
importIdstringYesImport ID (UUID)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/imports/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "data": {
    "import_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "processing",
    "stage": "transcribing",
    "progress": 45,
    "message": "Recognizing speech...",
    "original_filename": "meeting.mp3",
    "file_size": "15.2 MB",
    "task_id": null,
    "error_code": null,
    "error_message": null,
    "created_at": "2026-01-03T10:00:00.000Z",
    "updated_at": "2026-01-03T10:05:00.000Z"
  }
}
FieldTypeDescription
statusstringStatus: pending / processing / completed / failed
stagestringProcessing stage: converting / transcribing / translating / summarizing
progressintegerProgress percentage (0-100)
task_idstringThe task ID after processing completes (usable with the Task API)
error_codestringThe error code on failure
error_messagestringThe error message on failure (a general description without internal details; provide the import_id for troubleshooting)

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
import_not_found404Import task not foundVerify that importId is correct; if the task created by the import has been deleted, the import record is removed as well

GET /api/v1/imports (List Imports)

Description

Retrieve the user's import task list (paginated). Import records whose tasks have been deleted do not appear in the list.

Use Cases

  • Display the import history
  • View the status of all import tasks

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
per_pageintegerNoItems per page (default 20)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/imports?per_page=20" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "data": [
    {
      "import_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "completed",
      "original_filename": "meeting.mp3",
      "file_size": "15.2 MB",
      "task_id": "660e8400-e29b-41d4-a716-446655440001",
      "created_at": "2026-01-03T10:00:00.000Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 20,
    "total": 100
  }
}

Audio API

Audio file streaming playback, with support for HTTP Range Requests.


GET /api/v1/sse/audio/{taskId} (Audio Streaming Playback)

Description

Stream the recording file of the specified task, with support for HTTP Range Requests to enable seek playback.

Note: Although the path contains /sse/, this endpoint returns an audio file (not an SSE stream).

Use Cases

  • Play recording audio
  • Support seeking the playback position

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesRecording ID (i.e. recordings.id, UUID)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/sse/audio/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Response Format

Full file (HTTP 200):

HTTP/1.1 200 OK
Content-Type: audio/mp4
Content-Length: 1234567
Accept-Ranges: bytes
Cache-Control: no-cache

Note: All recording audio files are returned as an M4A container (AAC encoding). Content-Type is fixed to audio/mp4.

Partial file (HTTP 206 - Range Request):

HTTP/1.1 206 Partial Content
Content-Type: audio/mp4
Content-Length: 1024
Content-Range: bytes 0-1023/1234567
Accept-Ranges: bytes

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404Recording not foundVerify that taskId is correct
recording_audio_not_ready422The audio file has not finished uploadingRetry later
storage_download_failed500Storage service download failedRetry later

Frontend Example

async function playAudio(taskId, apiKey) {
  const response = await fetch(
    `https://vas-poc.vurbo.ai/api/v1/sse/audio/${taskId}`,
    {
      headers: {
        'X-API-Key': apiKey
      }
    }
  );

  const blob = await response.blob();
  const audioUrl = URL.createObjectURL(blob);
  const audio = new Audio(audioUrl);
  audio.play();
}

TTS API

The TTS (Text-to-Speech) API provides lookup functions related to speech synthesis.


GET /api/v1/tts/voices (List TTS Voices)

Description

Retrieve the list of available TTS voices for the specified language. Each language has multiple voices to choose from, including different genders and styles.

Use Cases

  • Let users choose their preferred TTS voice
  • Display the available voice options

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
languagestringYesLanguage code (e.g. en-US)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/tts/voices?language=en-US" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "data": {
    "language": "en-US",
    "voices": [
      {
        "voice_name": "en-US-JennyNeural",
        "display_name": "Jenny",
        "gender": "Female",
        "is_default": true,
        "sample_url": "https://vas-poc.vurbo.ai/api/v1/tts/voices/en-US-JennyNeural/sample"
      },
      {
        "voice_name": "en-US-GuyNeural",
        "display_name": "Guy",
        "gender": "Male",
        "is_default": false,
        "sample_url": "https://vas-poc.vurbo.ai/api/v1/tts/voices/en-US-GuyNeural/sample"
      },
      {
        "voice_name": "en-US-AriaNeural",
        "display_name": "Aria",
        "gender": "Female",
        "is_default": false,
        "sample_url": "https://vas-poc.vurbo.ai/api/v1/tts/voices/en-US-AriaNeural/sample"
      },
      {
        "voice_name": "en-US-DavisNeural",
        "display_name": "Davis",
        "gender": "Male",
        "is_default": false,
        "sample_url": "https://vas-poc.vurbo.ai/api/v1/tts/voices/en-US-DavisNeural/sample"
      },
      {
        "voice_name": "en-US-SaraNeural",
        "display_name": "Sara",
        "gender": "Female",
        "is_default": false,
        "sample_url": "https://vas-poc.vurbo.ai/api/v1/tts/voices/en-US-SaraNeural/sample"
      },
      {
        "voice_name": "en-US-TonyNeural",
        "display_name": "Tony",
        "gender": "Male",
        "is_default": false,
        "sample_url": "https://vas-poc.vurbo.ai/api/v1/tts/voices/en-US-TonyNeural/sample"
      }
    ]
  }
}
FieldTypeDescription
voice_namestringVoice identifier (used by the API)
display_namestringVoice display name
genderstringGender: Female / Male
is_defaultbooleanWhether this is the default voice for the language
sample_urlstringVoice sample audio URL (playable directly for preview)

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
validation_failed400Missing language parameter or invalid parameter formatProvide a valid language parameter

When this endpoint receives an unsupported language code it returns HTTP 200 with an empty voices array instead of an error -- this includes locales that have voices available but cannot be used as a TTS target because they lack transcription support. For valid codes, see the supported language list.


GET /api/v1/tts/voices/{voiceName}/sample (Get Voice Sample Audio)

Description

Retrieve the sample audio file (MP3 format) for the specified voice. The first request synthesizes it in real time and caches it; subsequent requests are served directly from the cache.

This endpoint does not count toward TTS charges.

Use Cases

  • Let users preview a voice before choosing it
  • Provide voice browsing and comparison

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
voiceNamestringYesVoice name (e.g. en-US-JennyNeural)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/tts/voices/zh-TW-HsiaoChenNeural/sample" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  --output sample.mp3

Success Response

The response is binary MP3 audio data (not JSON).

HeaderValue
Content-Typeaudio/mpeg
Content-LengthAudio file size (bytes)
Cache-Controlpublic, max-age=86400

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
tts_voice_not_found404Voice not found, or the voice's language cannot be used as a TTS target (any voice not listed by GET /api/v1/tts/voices is treated as not found)Use a voice_name returned by GET /api/v1/tts/voices?language={code}
tts_sample_generation_failed500Voice sample generation failedRetry later
-429Request rate too highWait and retry (limit 30 per minute)

Rate Limiting

30 requests per minute per user. When the limit is exceeded, HTTP 429 is returned.



Broadcasts API

The broadcast API manages real-time subtitle streaming, including creating, querying, updating, and revoking broadcasts.


GET /api/v1/broadcasts (List Broadcasts)

Description

Query the broadcast list owned by the current API Key holder (excluding revoked channels), with pagination support.

Use Cases

  • View all created broadcasts
  • Manage multiple broadcast channels
  • Monitor broadcast status

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
per_pageintegerNoItems per page (default 20)
pageintegerNoPage number (default 1)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/broadcasts?per_page=10&page=1" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response (HTTP 200)

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "token": "a3f9",
      "name": "My Broadcast Channel",
      "share_url": "https://vas-poc.vurbo.ai/broadcast/a3f9",
      "transcription_language": "zh-TW",
      "translation_languages": ["en-US", "ja-JP"],
      "tts_config": null,
      "speaker_diarization": false,
      "summary_template": null,
      "summary_language": null,
      "max_viewers": 100,
      "access_type": "public",
      "pass_code": null,
      "status": "pending",
      "is_live": false,
      "session_id": null,
      "current_recording_id": null,
      "recordings_count": 0,
      "peak_viewers": 0,
      "total_viewers": 0,
      "duration_ms": 0,
      "duration_formatted": "0:00",
      "started_at": null,
      "ended_at": null,
      "revoked_at": null,
      "created_at": "2026-01-03T10:00:00.000Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 10,
    "total": 50
  }
}

For an explanation of the response fields, see the response fields of Create Broadcast.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
auth_missing_api_key401API Key not providedMake sure the header includes the API Key
auth_invalid_api_key401Invalid API KeyVerify that the API Key is correct

POST /api/v1/broadcasts (Create Broadcast)

Description

Create a new broadcast session for real-time subtitle streaming. After creation, a share link is generated, and viewers can receive real-time subtitles and translations through this link.

The full request/response spec (including the plural transcription_languages field, the 12-language translation limit, and the error codes for each violation) is in reference/rest/broadcasts.md. The singular transcription_language shown here is a backward-compatible field (equal to the first array element).

Use Cases

  • Create real-time subtitles for a lecture/talk
  • Create a real-time translation stream for a meeting
  • Create real-time subtitles for a livestream

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
transcription_languagestringYesTranscription language code (e.g. zh-TW)
translation_languagesstring[]NoArray of translation language codes
namestringNoChannel name (max 100 characters; cannot be changed after creation and is not used as the recording name)
access_typestringNoAccess type: public (default) or password
pass_codestringConditionalPassword (required when access_type is password, 4-12 characters; letters, digits and common punctuation only (no Chinese characters, no spaces))
max_viewersintegerNoMaximum number of viewers (1 to the account viewer limit; defaults to that limit when omitted)
speaker_diarizationbooleanNoSpeaker diarization (true or false, default false)
tts_configobjectNoTTS default settings (key is the language code)
tts_config.*.voicestringNoTTS voice name (uses the default voice if not specified)
summary_templatestringNoSummary template slug (max 50 characters, must be an enabled summary category template)
summary_languagestringNoSummary output language; must be a language code from the supported language list (defaults to transcription_language if not specified)
callback_urlstringNoWebhook callback URL (max 2048 characters)

Webhook notification: After you set callback_url, an HTTP POST notification is sent automatically when broadcast recording processing completes or fails. You can also specify a webhook_url in the API Key settings as a default callback. See the Webhook Guide.

Request Example

curl -X POST "https://vas-poc.vurbo.ai/api/v1/broadcasts" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "transcription_language": "zh-TW",
    "translation_languages": ["en-US", "ja-JP"],
    "name": "My Broadcast Channel",
    "access_type": "public",
    "max_viewers": 50,
    "tts_config": {
      "en-US": {"voice": "en-US-JennyNeural"},
      "ja-JP": {"voice": "ja-JP-NanamiNeural"}
    },
    "summary_template": "lecture",
    "summary_language": "zh-TW",
    "callback_url": "https://your-server.com/webhooks/vas"
  }'

Success Response (HTTP 201)

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "token": "a3f9",
    "name": "My Broadcast Channel",
    "share_url": "https://vas-poc.vurbo.ai/broadcast/a3f9",
    "transcription_language": "zh-TW",
    "translation_languages": ["en-US", "ja-JP"],
    "tts_config": {
      "en-US": {"voice": "en-US-JennyNeural"},
      "ja-JP": {"voice": "ja-JP-NanamiNeural"}
    },
    "speaker_diarization": false,
    "summary_template": "lecture",
    "summary_language": "zh-TW",
    "max_viewers": 100,
    "access_type": "public",
    "pass_code": null,
    "status": "pending",
    "is_live": false,
    "session_id": null,
    "current_recording_id": null,
    "recordings_count": 0,
    "peak_viewers": 0,
    "total_viewers": 0,
    "duration_ms": 0,
    "duration_formatted": "0:00",
    "started_at": null,
    "ended_at": null,
    "revoked_at": null,
    "created_at": "2026-01-03T10:00:00.000Z"
  }
}
FieldTypeDescription
idstringBroadcast ID (UUID)
tokenstringShare token (4-character short code, character set a-z0-9)
namestringBroadcast name
share_urlstringDefault share URL (not an openable viewer page; see the Broadcast Guide)
transcription_languagestringTranscription language
translation_languagesarrayTranslation language list
tts_configobjectTTS default settings (key is the language code)
speaker_diarizationbooleanSpeaker diarization toggle
summary_templatestringSummary template slug (null means not set)
summary_languagestringSummary output language (null defaults to transcription_language)
max_viewersintegerMaximum number of viewers
access_typestringAccess type: public or password
pass_codestringPlaintext password (set when access_type is password, otherwise null)
statusstringStatus (see below)
is_livebooleanWhether currently live (true when in the active or paused state)
session_idstringWebSocket Session ID
current_recording_idstringCurrent recording UUID: has a value only while live, and is the recording of this go-live (the new recording after a takeover); null during standby or when not live
recordings_countintegerNumber of historical recordings
peak_viewersintegerHistorical peak viewer count
total_viewersintegerCumulative viewer count
duration_msintegerBroadcast duration (milliseconds)
duration_formattedstringFormatted duration (min:sec)
started_atstringStart time (ISO 8601)
ended_atstringEnd time (ISO 8601)
revoked_atstringRevocation time (ISO 8601)
created_atstringCreation time (ISO 8601)

Broadcast Status

StatusDescription
pendingWaiting to start (created, not yet started)
activeBroadcasting
pausedPaused
endedEnded
revokedRevoked

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
auth_missing_api_key401API Key not providedMake sure the header includes the API Key
auth_invalid_api_key401Invalid API KeyVerify that the API Key is correct
validation_failed422Parameter validation failedVerify that the parameter format is correct
plan_feature_not_allowed403The unlimited plan does not include broadcasting (broadcasting is never included in plans)Broadcasts are billed in credits; use a credit-based API Key

GET /api/v1/broadcasts/{id} (Query Broadcast Status)

Description

Query detailed information and the current status of the specified broadcast.

Use Cases

  • Check whether the broadcast has started
  • Monitor the viewer count
  • Confirm the broadcast status

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
idstringYesBroadcast ID (UUID)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response (HTTP 200)

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "token": "a3f9",
    "name": "My Broadcast Channel",
    "share_url": "https://vas-poc.vurbo.ai/broadcast/a3f9",
    "transcription_language": "zh-TW",
    "translation_languages": ["en-US", "ja-JP"],
    "tts_config": {
      "en-US": {"voice": "en-US-JennyNeural"},
      "ja-JP": {"voice": "ja-JP-NanamiNeural"}
    },
    "speaker_diarization": true,
    "summary_template": "lecture",
    "summary_language": "zh-TW",
    "max_viewers": 100,
    "access_type": "public",
    "status": "active",
    "is_live": true,
    "session_id": "ws_session_xyz",
    "current_recording_id": "660e8400-e29b-41d4-a716-446655440001",
    "recordings_count": 1,
    "peak_viewers": 25,
    "total_viewers": 30,
    "duration_ms": 1800000,
    "duration_formatted": "30:00",
    "started_at": "2026-01-03T10:00:00.000Z",
    "ended_at": null,
    "revoked_at": null,
    "created_at": "2026-01-03T09:55:00.000Z"
  }
}

For an explanation of the response fields, see the response fields of Create Broadcast.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
broadcast_session_not_found404The specified broadcast was not foundVerify that the broadcast ID is correct

PATCH /api/v1/broadcasts/{id} (Update Broadcast Settings)

Description

Dynamically update broadcast settings, including access type, maximum viewer count, transcription language, and translation languages. This API can be called while a broadcast is in progress (active or paused state) to adjust settings in real time.

Use Cases

  • Change a public broadcast to password protected
  • Change a password-protected broadcast to public
  • Adjust the maximum viewer count
  • Change the transcription language (e.g. from Chinese to English)
  • Add or remove translation languages
  • Turn speaker diarization on or off
  • Dynamically adjust settings while live

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
idstringYesBroadcast ID (path parameter)
access_typestringNoAccess type: public or password
pass_codestringConditionalPassword (4-12 characters; letters, digits and common punctuation only (no Chinese characters, no spaces), required when access_type is password)
max_viewersintegerNoMaximum number of viewers (1 to the account viewer limit)
transcription_languagestringNoTranscription language (e.g. zh-TW, en-US, ja-JP)
translation_languagesarrayNoTranslation language list (e.g. ["en-US", "ja-JP"])
speaker_diarizationbooleanNoSpeaker diarization toggle (true or false)
tts_configobjectNoTTS default settings (overrides existing settings; null means clear)
summary_templatestringNoSummary template slug (max 50 characters, an empty string "" means clear)
summary_languagestringNoSummary output language; must be a language code from the supported language list (an empty string "" means clear)

Note: If no updatable field is provided, the request returns 200 and nothing changes. The channel name cannot be changed after creation; a name field is ignored. Passing null for tts_config clears the settings; omitting it means no change.

Request Example

# Change to password protected
curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "access_type": "password",
    "pass_code": "mySecret123"
  }'

# Adjust the maximum viewer count
curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "max_viewers": 200
  }'

# Change the transcription and translation languages
curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "transcription_language": "en-US",
    "translation_languages": ["zh-TW", "ja-JP", "ko-KR"]
  }'

# Turn on speaker diarization
curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "speaker_diarization": true
  }'

# Update the TTS default settings
curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "tts_config": {
      "zh-TW": {"voice": "zh-TW-HsiaoChenNeural"},
      "ja-JP": {"voice": "ja-JP-NanamiNeural"}
    }
  }'

Success Response (HTTP 200)

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "token": "a3f9",
    "name": "My Broadcast Channel",
    "share_url": "https://vas-poc.vurbo.ai/broadcast/a3f9",
    "transcription_language": "zh-TW",
    "translation_languages": ["en-US", "ja-JP"],
    "tts_config": {
      "en-US": {"voice": "en-US-JennyNeural"},
      "ja-JP": {"voice": "ja-JP-NanamiNeural"}
    },
    "speaker_diarization": true,
    "summary_template": "lecture",
    "summary_language": "zh-TW",
    "access_type": "password",
    "pass_code": "mySecret123",
    "max_viewers": 200,
    "status": "active",
    "is_live": true,
    "session_id": "ws_session_xyz",
    "current_recording_id": "660e8400-e29b-41d4-a716-446655440001",
    "recordings_count": 1,
    "peak_viewers": 25,
    "total_viewers": 30,
    "duration_ms": 1800000,
    "duration_formatted": "30:00",
    "started_at": "2026-01-03T10:00:00.000Z",
    "ended_at": null,
    "revoked_at": null,
    "created_at": "2026-01-03T09:55:00.000Z"
  }
}

For an explanation of the response fields, see the response fields of Create Broadcast.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
broadcast_session_not_found404The specified broadcast was not foundVerify that the broadcast ID is correct
validation_failed422Parameter validation failedVerify that the parameter format is correct

DELETE /api/v1/broadcasts/{id} (Revoke Broadcast)

Description

Revoke a broadcast that has not yet started. Only broadcasts in the pending state can be revoked.

Use Cases

  • Cancel a broadcast that has not yet started
  • Clean up broadcasts you no longer need

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
idstringYesBroadcast ID (UUID)

Request Example

curl -X DELETE "https://vas-poc.vurbo.ai/api/v1/broadcasts/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response (HTTP 200)

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "token": "a3f9",
    "name": "My Broadcast Channel",
    "share_url": "https://vas-poc.vurbo.ai/broadcast/a3f9",
    "transcription_language": "zh-TW",
    "translation_languages": ["en-US", "ja-JP"],
    "tts_config": null,
    "speaker_diarization": false,
    "summary_template": null,
    "summary_language": null,
    "max_viewers": 100,
    "access_type": "public",
    "status": "revoked",
    "is_live": false,
    "session_id": null,
    "current_recording_id": null,
    "recordings_count": 0,
    "peak_viewers": 0,
    "total_viewers": 0,
    "duration_ms": 0,
    "duration_formatted": "0:00",
    "started_at": null,
    "ended_at": null,
    "revoked_at": "2026-01-03T10:05:00.000Z",
    "created_at": "2026-01-03T10:00:00.000Z"
  }
}

For an explanation of the response fields, see the response fields of Create Broadcast.

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
broadcast_session_not_found404The specified broadcast was not foundVerify that the broadcast ID is correct
broadcast_cannot_revoke422Only broadcasts in the pending state can be revokedCheck the current broadcast status

DELETE /api/v1/broadcasts/batch (Batch Revoke Broadcasts)

Description

Batch revoke multiple broadcasts. Only broadcasts in the pending state are revoked; IDs in other states are ignored. Up to 100 can be operated on per request.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDescription
idsbodyarrayYesArray of broadcast IDs (each element a UUID, up to 100)

Request Example

curl -X DELETE "https://vas-poc.vurbo.ai/api/v1/broadcasts/batch" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
    ]
  }'

Success Response (HTTP 200)

{
  "data": {
    "affected_count": 2
  }
}
Response Fields
FieldTypeDescription
data.affected_countnumberNumber of broadcasts actually revoked (only pending-state broadcasts are counted)

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
validation_failed422Parameter validation failedMake sure ids is an array of UUIDs with no more than 100 entries

Viewer API

The viewer-side API does not require API Key authentication. It is used for viewers to view broadcast information and verify passwords.

Both endpoints can be called directly from a web page on any domain, so your viewer page can live on your own domain; do not send credentials with the request. See Calling from a Browser.


GET /api/v1/viewer/broadcasts/{token} (Get Broadcast Public Info)

Description

Retrieve the public information of the specified broadcast, for the viewer side to display channel information.

Use Cases

  • Display channel information before a viewer enters the broadcast page
  • Determine whether a password is required

Authentication

No authentication required

Request Parameters

ParameterTypeRequiredDescription
tokenstringYesBroadcast token (4-character short code a-z0-9)

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/viewer/broadcasts/a3f9"

Success Response (HTTP 200)

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "My Broadcast Channel",
    "access_type": "password",
    "requires_password": true,
    "status": "active",
    "is_live": true,
    "transcription_language": "zh-TW",
    "transcription_languages": ["zh-TW", "en-US"],
    "translation_languages": ["en-US", "ja-JP"],
    "tts_languages": ["en-US", "ja-JP"],
    "tts_voices": {
      "en-US": [
        { "voice_name": "en-US-JennyNeural", "display_name": "Jenny", "gender": "Female" },
        { "voice_name": "en-US-GuyNeural", "display_name": "Guy", "gender": "Male" }
      ],
      "ja-JP": [
        { "voice_name": "ja-JP-NanamiNeural", "display_name": "Nanami", "gender": "Female" },
        { "voice_name": "ja-JP-KeitaNeural", "display_name": "Keita", "gender": "Male" }
      ]
    }
  }
}
FieldTypeDescription
idstringBroadcast ID (UUID)
namestringChannel name
access_typestringAccess type: public/password
requires_passwordbooleanWhether password verification is required
statusstringBroadcast status
is_livebooleanWhether currently live
transcription_languagestringTranscription language (backward compatible; equals the first element of transcription_languages)
transcription_languagesarrayList of transcription languages (string[], up to 10, distinct)
translation_languagesarrayTranslation language list
tts_languagesarrayLanguages for which the host has enabled voice playback; an empty array when the channel is not live
tts_voicesobjectTTS voice list for each translation language

tts_voices structure:

tts_voices is an object keyed by language code, where each language contains an array of available voices:

FieldTypeDescription
voice_namestringVoice name (for API use)
display_namestringDisplay name
genderstringGender: Female/Male

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
broadcast_token_invalid401Token invalid or not foundVerify that the token is correct
broadcast_token_revoked401Broadcast has been revokedThis broadcast is no longer available
too_many_requests429Too many requests: per channel, the limit per minute is about twice the channel's maximum number of viewers (minimum 200); too many lookups of nonexistent channels from the same source also return 429 temporarily. See Rate LimitsWait for the number of seconds in the Retry-After response header, then retry

POST /api/v1/viewer/broadcasts/{token}/verify (Password Verification)

Description

Verify the password and obtain a viewer access token. The obtained viewer_access_token is used to connect to the SSE real-time subtitle stream.

Use Cases

  • Verify the password before a viewer enters a password-protected broadcast
  • Obtain the viewer_access_token required for the SSE connection

Authentication

No authentication required

Request Parameters

ParameterTypeRequiredDescription
tokenstringYesBroadcast token (path parameter)
passwordstringYesChannel password (max 12 characters)

Request Example

curl -X POST "https://vas-poc.vurbo.ai/api/v1/viewer/broadcasts/a3f9/verify" \
  -H "Content-Type: application/json" \
  -d '{
    "password": "mySecret123"
  }'

Success Response (HTTP 200)

Correct password:

{
  "data": {
    "viewer_access_token": "aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vWaB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW",
    "expires_at": "2026-01-04T10:00:00.000Z"
  }
}

Public channel (no password required):

{
  "data": {
    "viewer_access_token": null,
    "message": "此頻道為公開,不需要密碼驗證"
  }
}

The message text is returned in Traditional Chinese and is meant for display only -- do not parse or match on it.

FieldTypeDescription
viewer_access_tokenstringViewer access token (valid for 24 hours)
expires_atstringToken expiration time (ISO 8601)

Usage: After obtaining the viewer_access_token, include it when connecting to SSE: GET /broadcast/{token}/text?viewer_access_token=xxx

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
broadcast_token_invalid401Invalid tokenVerify that the token is correct
broadcast_token_revoked401Broadcast has been revokedThis broadcast is no longer available
broadcast_password_incorrect401Incorrect passwordRe-enter the correct password
validation_failed422Parameter validation failedVerify that the password format is correct
too_many_requests429Too many requests, or temporarily locked after too many incorrect passwords (30 from the same source within 5 minutes, or 100 for the same channel within 5 minutes). See Rate LimitsWait for the number of seconds in the Retry-After response header, then retry; while locked, even the correct password must wait

Recording Speaker Editing API

The Recording Speaker editing API provides transcript speaker editing for offline recordings, behaving consistently with the Speaker editing feature of the real-time mode WebSocket.

Limitation: This API applies only to recordings in multi-speaker recognition mode (multi_speaker). Single-speaker recordings return a speaker_diarization_required error.


PATCH /api/v1/tasks/{taskId}/speakers/rename (Globally Rename Speaker)

Description

Globally rename the specified speaker ID to a new name. This operation updates the speakerAliases mapping and updates the speaker field of all transcript entries that use that speaker ID to the new name.

Use Cases

  • Change an automatically recognized speaker ID (e.g. Guest-1) to a real name
  • Uniformly change the display name of a speaker

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask UUID (path parameter)
speaker_idstringYesThe original speaker ID (e.g. Guest-1); the current display label is also accepted for consecutive renames; max 100 characters
new_labelstringYesThe new display label; max 100 characters, must not contain control characters (\x00-\x1F, \x7F) or line breaks (it is written to the transcript and export files)

Request Example

curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/speakers/rename" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "speaker_id": "Guest-1",
    "new_label": "Manager Wang"
  }'

Success Response (HTTP 200)

{
  "data": {
    "speaker_id": "Guest-1",
    "new_label": "Manager Wang",
    "affected_sids": [1, 3, 5, 8, 12]
  }
}
FieldTypeDescription
speaker_idstringThe resolved original speaker ID (even if the request sends a display label, the response is the original ID)
new_labelstringThe new display label
affected_sidsarray<int>List of affected sentence SIDs

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct
speaker_transcript_not_found404Transcript not foundConfirm the recording has finished transcribing
speaker_diarization_required422This feature requires diarization recordingApplies only to recordings in multi-speaker recognition mode
speaker_name_empty422new_label is emptyProvide a valid new_label
validation_failed422Parameter validation failedCheck the length and characters of speaker_id / new_label (must not contain control characters)
transcript_revision_conflict409Another write to the same transcript is in progressRetry shortly; this change did not take effect
storage_upload_failed500Failed to write the transcript back to storageRetry shortly; this change did not take effect

PATCH /api/v1/tasks/{taskId}/speakers/reassign (Reassign a Single Sentence Speaker)

Description

Change the speaker identity of a single sentence, assigning the sentence to an existing speaker.

Use Cases

  • Correct speaker recognition errors
  • Reassign a sentence to the correct speaker

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask UUID (path parameter)
sidintegerYesSentence number
target_speaker_idstringYesThe target speaker's original ID (taken from init_sentence.speaker_id; display labels are not accepted); max 100 characters

Request Example

curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/speakers/reassign" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "sid": 5,
    "target_speaker_id": "Guest-2"
  }'

Success Response (HTTP 200)

{
  "data": {
    "sid": 5,
    "old_speaker_id": "Guest-1",
    "new_speaker_id": "Guest-2",
    "new_speaker_label": "Lily Lee"
  }
}
FieldTypeDescription
sidintegerThe ID of the modified sentence
old_speaker_idstringThe original speaker ID
new_speaker_idstringThe new original speaker ID
new_speaker_labelstringThe new speaker display label (after applying speaker_aliases; equals new_speaker_id when there is no alias)

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
recording_not_found404The specified recording was not foundVerify that taskId is correct
speaker_transcript_not_found404Transcript not foundConfirm the recording has finished transcribing
speaker_diarization_required422This feature requires diarization recordingApplies only to recordings in multi-speaker recognition mode
speaker_sid_not_found422The specified sentence was not foundConfirm that sid exists
speaker_not_found422The specified speaker was not foundConfirm that target_speaker_id exists
invalid_data422Creating a new speaker is not supportedUse an existing speaker ID
validation_failed422Parameter validation failedVerify that the parameter format is correct
transcript_revision_conflict409Another write to the same transcript is in progressRetry shortly; this change did not take effect
storage_upload_failed500Failed to write the transcript back to storageRetry shortly; this change did not take effect

PATCH /api/v1/tasks/{taskId}/speakers/merge (Merge Speakers)

Description

Assign all sentences of the source speaker to the target speaker; the source's alias (if any) is transferred to the target. This applies when the diarization model mistakenly identifies the same person as two speakers.

vs. reassign: reassign changes only a single sentence; merge changes all sentences of the speaker. vs. rename: rename changes only the display name; merge consolidates multiple speakers.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
taskIdstringYesTask ID (UUID, path parameter)
source_speaker_idstringYesThe original speaker ID or current display label to be merged (e.g. Guest-2 or Manager Wang), max 100 characters
target_speaker_idstringYesThe original ID or current display label of the merge target speaker (e.g. Guest-1), max 100 characters

Request Example

curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/speakers/merge" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "source_speaker_id": "Guest-2",
    "target_speaker_id": "Guest-1"
  }'

Success Response (HTTP 200)

{
  "data": {
    "source_speaker_id": "Guest-2",
    "target_speaker_id": "Guest-1",
    "target_speaker_label": "Manager Wang",
    "affected_sids": [3, 5, 7]
  }
}
FieldTypeDescription
source_speaker_idstringThe original speaker ID to be merged (resolved back to the original ID even if the request sends a display label)
target_speaker_idstringThe original speaker ID of the merge target
target_speaker_labelstringThe target speaker display label (after applying speaker_aliases; equals the original ID when there is no alias)
affected_sidsarray<int>List of affected sentence SIDs: sentences that belonged to the source speaker, plus the target speaker's existing sentences whose display name changed because of the merge (for example, when the source speaker's custom name is carried over to the target)

Error Responses

Error CodeHTTP StatusDescriptionRecommended Action
merge_speakers_same_id400Source and target are the same speakerProvide different speaker IDs
speaker_name_empty422Source or target is an empty stringProvide a valid speaker ID
speaker_not_found422Source or target does not exist in the recordingVerify that the speaker ID is correct
recording_not_found404Recording not foundVerify that taskId is correct
speaker_transcript_not_found404Transcript not foundConfirm the recording has finished transcribing
speaker_diarization_required422The recording is not in multi-speaker modeApplies only to recognition_mode: multi_speaker
validation_failed422Parameter validation failedConfirm both source and target are provided
transcript_revision_conflict409Another write to the same transcript is in progressRetry shortly; this change did not take effect
storage_upload_failed500Failed to write the transcript back to storageRetry shortly; this change did not take effect

For the full specification, see reference/rest/speakers.md.


Recording Entry Editing API (added in v1.4.0)

For historical recordings, this provides an API to correct the STT original text of a single sentence. After correction, you can call GET /api/v1/sse/recordings/{taskId}/entries/{sid}/retranslate to retranslate automatically. For the full specification, see reference/rest/entries.md.

PATCH /api/v1/tasks/{taskId}/entries/{sid} (Edit a Single Sentence's Original Text)

Description

Edit the original text (original_text) of a single sentence in a historical recording. On the first edit, the system automatically backs up the raw STT output to original_text_raw, and writes original_text_edited_at and the transcript revision. This changes only the original text, not the translation — to retranslate, call the corresponding SSE endpoint.

Limitations

  • Only recordings with processing_status === completed are allowed; in-progress recordings return recording_not_completed
  • Optimistic locking: you can pass expected_revision; a mismatch returns 409 transcript_revision_conflict

Authentication

Header: X-API-Key

Request Parameters

ParameterLocationTypeRequiredDescription
taskIdpathstringYesTask ID (UUID)
sidpathnumberYesSentence ID (1-based)
original_textbodystringYesThe corrected original text, 1–2000 characters
expected_revisionbodynumberNoOptimistic lock; the current transcript revision

Request Example

curl -X PATCH "https://vas-poc.vurbo.ai/api/v1/tasks/{taskId}/entries/5" \
  -H "X-API-Key: vas_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "original_text": "The corrected text", "expected_revision": 3 }'

Success Response (HTTP 200)

{
  "data": {
    "sid": 5,
    "original_text": "The corrected text",
    "original_text_raw": "The raw STT output",
    "original_text_edited_at": "2026-05-06T10:30:00.000000Z",
    "translated_texts": { "en-US": "The outdated old translation" },
    "revision": 4
  }
}

Existing translations are not updated automatically; after receiving the response, the frontend should call GET /api/v1/sse/recordings/{taskId}/entries/{sid}/retranslate to retranslate.

Error Responses

Error CodeHTTPDescription
recording_not_found404The recording does not exist or does not belong to the user
recording_not_completed422The recording has not finished processing
entry_not_found404The specified sentence was not found
entry_text_empty422The original text is empty
entry_text_too_long422The original text exceeds 2000 characters
transcript_revision_conflict409The revision does not match, or another write to the same transcript is in progress
speaker_transcript_not_found404The transcript was not found

For the full specification and an "edit + automatic retranslate" workflow example, see reference/rest/entries.md.


Summary Template API

The summary template API provides a list of available summary templates, used to choose the summary style when importing audio files.


GET /api/v1/summary-templates (List Summary Templates)

For the full schema, see reference/rest/summary-templates.md.

Description

Retrieve the list of available summary templates. Each template represents a different summary style, suitable for different scenarios (such as meetings, medical consultations, legal consultations, etc.).

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDefaultDescription
categoryquerystringNosummaryTemplate category filter: summary / medical / legal / all

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/summary-templates?category=medical" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "data": [
    { "slug": "general",          "name": "General Summary", "description": "...", "category": "summary" },
    { "slug": "meeting",          "name": "Meeting Summary", "description": "...", "category": "summary" },
    { "slug": "meeting_minutes",  "name": "Meeting Minutes", "description": "...", "category": "summary" },
    { "slug": "speech",           "name": "Speech Summary", "description": "...", "category": "summary" },
    { "slug": "interview",        "name": "Interview Summary", "description": "...", "category": "summary" },
    { "slug": "course",           "name": "Course Summary", "description": "...", "category": "summary" }
  ]
}
FieldTypeDescription
slugstringTemplate identifier (used in API parameters)
namestringTemplate name
descriptionstringTemplate description (may be null)
categorystringTemplate category (summary / medical / legal)

Error Responses

Error CodeHTTPDescriptionRecommended Action
auth_missing_api_key401API Key not providedMake sure the header includes the API Key
auth_invalid_api_key401Invalid API KeyVerify that the API Key is correct
invalid_category400category is not in the allow listUse summary / medical / legal / all instead

GET /api/v1/summary-templates/{slug} (Get a Single Summary Template's Details)

Exposes the full raw text of the built-in template's prompt definition, for reference when enterprise customers integrate. For the full schema, see reference/rest/summary-templates.md.

Authentication

Header: X-API-Key: YOUR_API_KEY

Request Parameters

ParameterLocationTypeRequiredDescription
slugpathstringYesTemplate identifier

Request Example

curl -X GET "https://vas-poc.vurbo.ai/api/v1/summary-templates/medical_consultation" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"

Success Response

{
  "data": {
    "slug": "medical_consultation",
    "name": "Medical Consultation",
    "description": "Medical consultation record template",
    "category": "medical",
    "system_prompt": "You are a professional medical records specialist...",
    "template_prompt": "[Task]\nGenerate a structured summary...",
    "output_format": "[Summary Template Begin]\n## Patient Information\n..."
  }
}

Error Responses

Error CodeHTTPDescription
template_not_found404The template with the specified slug does not exist or has been disabled (is_active=false)

Glossary Validation API

POST /api/v1/glossary/validate (Validate a Glossary Before Saving)

Checks a glossary (terminology, fuzzy correction, translation dictionary) for format problems and internal conflicts before it is saved. Intended to be called from your glossary management UI before saving; it is not necessary to call it before every recording or audio import.

Most glossary problems produce no error message at all — they simply yield unexpected results, silently, during recording or translation. This endpoint surfaces problems of that kind at the moment the user presses Save, along with the index of each offending entry.

Note: The host is the realtime service domain (the same domain as wss://, with the scheme swapped for https://), which may differ from the host of the other REST endpoints.

  • Free: no points are deducted, and no task or recording is created
  • Rate limited to 120 requests per minute per API Key, as a separate quota counted independently of the other REST endpoints
  • The response carries no human-readable text; compose your own sentences from the conflict codes
curl -X POST "https://<realtime-host>/api/v1/glossary/validate" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{"fuzzy_correction":{"zh-TW":[{"correct":"報價","incorrect":["抱歉"]},{"correct":"抱歉"}]}}'

For the eight detectable conflicts, the full request/response specification, and every field definition, see the Glossary Validation API; for how to configure the glossary itself, see the Terminology Guide.


Error Handling

Unified Error Format

All API errors follow a unified format:

Simple format (external API):

{
  "error_code": "auth_invalid_api_key",
  "message": "Invalid API key"
}

Detailed format (internal API):

{
  "type": "error",
  "data": {
    "error_code": "auth_invalid_api_key",
    "severity": "fatal",
    "message": "Invalid or expired API key",
    "context": "auth",
    "request_id": "req_abc123xyz789",
    "timestamp": "2025-12-13T10:30:45.123Z",
    "details": null
  }
}

Error Code Overview

Authentication Errors

error_codeHTTP StatusseverityDescription
auth_missing_api_key401fatalAPI Key not provided
auth_invalid_api_key401fatalInvalid API Key
auth_key_expired401fatalAPI Key expired

Resource Errors

error_codeHTTP StatusDescription
recording_not_found404Recording does not exist
recording_audio_not_ready422Audio file not ready

Broadcast Errors

error_codeHTTP StatusDescription
broadcast_not_found404Broadcast not found
broadcast_session_ended410Broadcast ended
broadcast_unauthorized403Unauthorized access


Version: V1.24.1 Last Updated: 2026-10-07

Copyright © 2026