Tasks API
Endpoint Overview
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/tasks | Get task list |
| DELETE | /api/v1/tasks/{taskId} | Delete task |
| PUT | /api/v1/tasks/{taskId}/pin | Update pin status |
| PUT | /api/v1/tasks/{taskId}/read | Mark as read |
| PATCH | /api/v1/tasks/{taskId}/name | Update task name |
| POST | /api/v1/tasks/{taskId}/force-fail | Manually force a task to be marked as failed |
| POST | /api/v1/tasks/{taskId}/retry | Reprocess a failed task |
| PUT | /api/v1/tasks/batch/pin | Batch update pin status |
| DELETE | /api/v1/tasks/batch | Batch delete tasks |
| GET | /api/v1/tasks/{taskId}/audio/export | Download task audio |
| GET | /api/v1/tasks/{taskId}/transcript/export | Download transcript (TXT / SRT / SBV / VTT / CSV) |
GET /api/v1/tasks
Description
Get the recording task list for the current user. Use the status parameter to filter tasks by processing stage, or task_ids[] to query specific tasks only.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Default | Description |
|---|---|---|---|---|---|
status | query | string | No | completed | Filter: completed (completed) / active (in progress) / all (all) |
task_ids[] | query | string[] | No | — | Query these tasks only (each element is a UUID, 1–100 entries) |
status Filter Details
| Value | Tasks Returned | Description |
|---|---|---|
completed | processing_status = completed | Default value, backward compatible. Returns only completed tasks |
active | processing_status IN (recording, importing, uploading, processing) | Tasks in progress (live recording, audio import, uploading, processing) |
all | No filter | Returns all tasks (including in-progress and completed) |
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.
statusstill applies: withoutstatus, only completed tasks are returned. To look up the listed tasks regardless of status, addstatus=all.- The response format is the same as without
task_ids. - More than 100 entries, an entry that is not a UUID, or
task_idsthat is not an array (for example,task_ids=<UUID>without[]) returns 422validation_failed.
Request Example
# Default: returns only completed tasks (backward compatible)
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
HTTP 200
{
"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,
"summary_mode": "custom",
"summary_template": "acme-meeting-v2",
"summary_language": "zh-TW"
}
]
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
data.tasks | array | Task list |
data.tasks[].task_id | string | Task ID (UUID) |
data.tasks[].title | string | Task title |
data.tasks[].type | string | Recording type |
data.tasks[].type_source | string | Source type (realtime / import / broadcast) |
data.tasks[].duration_ms | number | Recording duration (milliseconds) |
data.tasks[].duration_formatted | string | Formatted duration (min:sec) |
data.tasks[].transcription_languages | array | null | Transcription language list (null when there is no transcription language) |
data.tasks[].translation_languages | array | null | Translation language list (null when there is no translation language, e.g. conversation mode or an import with no translation language set) |
data.tasks[].created_at | string | Creation time (ISO 8601) |
data.tasks[].processing_status | string | Processing status (see below) |
data.tasks[].is_pinned | boolean | Whether the task is pinned |
data.tasks[].is_unread | boolean | Whether the task is unread |
data.tasks[].summary_mode | string | null | Summary mode: "builtin" / "custom" / null (null when no summary has been generated) |
data.tasks[].summary_template | string | null | effective slug — builtin → built-in template slug; custom → customer slug (i.e. the prompt_slug from the request, pass-through for traceability) |
data.tasks[].summary_language | string | null | Summary language. If no summary language was specified for the recording, this is usually the first transcription language; in two-way mode with active_language specified, it is that language. It may be null for tasks without a summary (same as summary_language in the history init_metadata) |
processing_status Details
The processing status of a recording is updated in real time as processing progresses:
| Status | Description | Scenario |
|---|---|---|
recording | Live recording in progress | Live recording, broadcast |
importing | Audio import in progress | Audio import |
uploading | Uploading to cloud storage | After recording stops, after import completes |
pending | Pending (kept for backward compatibility) | Appears only in legacy data; newly created records never enter this status |
processing | Speech recognition and translation in progress | After upload completes |
completed | Processing complete | Final status |
failed | Processing failed | Final status |
Status transitions:
Live recording/broadcast: recording → uploading → processing → completed / failed
Audio import: importing → uploading → processing → completed / failed
About the
pendingstatus: Kept for backward compatibility with legacy data; newly created records never enter this status.force-failstill accepts records inpendingso that leftover historical data can be cleaned up.
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
validation_failed | 422 | Parameter validation failed | Verify that task_ids is a UUID array of 1–100 entries |
DELETE /api/v1/tasks/{taskId}
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.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
taskId | path | string | Yes | Task 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
HTTP 200
{
"message": "Task deleted"
}
Response Field Details
| Field | Type | Description |
|---|---|---|
message | string | Operation result message |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
recording_not_found | 404 | Recording not found | Verify that taskId is correct |
invalid_processing_status | 422 | The task is still being processed and cannot be deleted | Wait 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/{taskId}/pin
Description
Update the pin status of a task. Pinned tasks are shown first in the list.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
taskId | path | string | Yes | Task ID (UUID) |
is_pinned | body | boolean | Yes | Pin 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
HTTP 200
{
"data": {
"is_pinned": true
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
data.is_pinned | boolean | Updated pin status |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
recording_not_found | 404 | Recording not found | Verify that taskId is correct |
validation_failed | 422 | Parameter validation failed | Verify that is_pinned is a boolean |
PUT /api/v1/tasks/{taskId}/read
Description
Mark a task as read.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
taskId | path | string | Yes | Task ID (UUID) |
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
HTTP 200
{
"data": {
"is_unread": false
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
data.is_unread | boolean | Updated unread status (always false) |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
recording_not_found | 404 | Recording not found | Verify that taskId is correct |
PATCH /api/v1/tasks/{taskId}/name
Description
Update the name of the specified task. The maximum name length is 60 characters (configured on the server side).
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
taskId | path | string | Yes | Task ID (UUID) |
name | body | string | Yes | Task 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
HTTP 200
{
"message": "Recording name updated",
"data": {
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Product Meeting Discussion",
"name_source": "user"
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
message | string | Operation result message |
data.task_id | string | Task ID (UUID) |
data.name | string | Updated task name |
data.name_source | string | Name source: default (system default) / llm (AI generated) / user (user defined) |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
not_found | 404 | The recording has been deleted | A taskId that simply does not exist is rejected earlier with 422 validation_failed; only deleted tasks reach this path |
recording_unauthorized | 403 | Unauthorized to access this recording | Verify that the task belongs to this user |
validation_failed | 422 | Validation failed | Verify that name is not empty and does not exceed 60 characters |
PUT /api/v1/tasks/batch/pin
Description
Batch update the pin status of multiple tasks. A single request can operate on up to 100 tasks. Only tasks belonging to the current user are affected; IDs that do not belong to this user are ignored.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
task_ids | body | array | Yes | Array of task IDs (each element is a UUID, up to 100) |
is_pinned | body | boolean | Yes | Pin 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
HTTP 200
{
"data": {
"affected_count": 2
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
data.affected_count | number | Number of tasks actually updated |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
validation_failed | 422 | Parameter validation failed | Verify that task_ids is a UUID array of no more than 100 entries, and is_pinned is a boolean |
DELETE /api/v1/tasks/batch
Description
Batch delete multiple tasks. Deletion is permanent and cannot be undone, with the same scope as single-task deletion. A single request can operate on up to 100 tasks. Only tasks belonging to the current user are affected; IDs that do not belong to this 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 (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
task_ids | body | array | Yes | Array of task IDs (each element is 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
HTTP 200
{
"data": {
"affected_count": 2,
"skipped_task_ids": []
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
data.affected_count | number | Number of tasks actually deleted |
data.skipped_task_ids | string[] | 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 |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
validation_failed | 422 | Parameter validation failed | Verify that task_ids is a UUID array of no more than 100 entries |
GET /api/v1/tasks/{taskId}/audio/export
Description
Download the original recording audio 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 filename uses the recording name (sanitized) when available; 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: attachmentheader; Range Requests are not supported.- Audio streaming: for playback; supports HTTP Range Requests for seeking; the response does not force a download.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
taskId | path | string | Yes | Task 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 -OJlets curl automatically name the saved file based on the server'sContent-Dispositionresponse.
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: The vast majority of recordings are returned as an M4A container (AAC encoded), with
Content-Typeaudio/mp4and the.m4aextension. The actualContent-Typedepends on the recording's storage format (a few legacy / broadcast recordings may beaudio/webmoraudio/wav), so rely on the response header.
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
recording_not_found | 404 | Recording not found, or the audio file does not exist in cloud storage | Verify that taskId is correct and the recording has not been deleted |
recording_audio_not_ready | 422 | Audio not yet uploaded or still processing | Retry later; you can first confirm via GET /api/v1/tasks that processing_status is completed |
storage_download_failed | 500 | Storage service download failed | Retry later; if it keeps failing, contact support |
Frontend Example
async function downloadAudio(taskId, apiKey) {
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/tasks/${taskId}/audio/export`,
{
headers: { 'X-API-Key': apiKey },
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Download failed: ${error.data?.message}`);
}
// Parse Content-Disposition to get the suggested filename
const disposition = response.headers.get('Content-Disposition') || '';
const match = disposition.match(/filename\*=UTF-8''([^;]+)/);
const filename = match ? decodeURIComponent(match[1]) : `audio-${taskId}`;
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
GET /api/v1/tasks/{taskId}/transcript/export
Description
Download the transcript of the specified task in one of five formats: plain text, SubRip subtitles, YouTube SBV subtitles, WebVTT subtitles, or a CSV spreadsheet. The response content includes the original text and all translation languages; it carries a Content-Disposition: attachment header for direct download. The filename uses the recording name (sanitized) when available; 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 in one response; can be opened directly in subtitle software or a spreadsheet.
- SSE history API: for progressive loading; pushes the raw structured data (JSON fragments) sentence by sentence as an event stream, for progressive rendering in a frontend UI.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Default | Description |
|---|---|---|---|---|---|
taskId | path | string | Yes | — | Task ID (UUID) |
format | query | string | No | txt | Format: txt / srt / sbv / vtt / csv |
format Details
| Format | Time Format | Content Structure | Typical Use |
|---|---|---|---|
txt | — | One line per segment, [Speaker] original text, with translations indented by 4 spaces as [language code] translated text | Reading, recordkeeping |
srt | HH:MM:SS,mmm | Includes sequence numbers; after each timecode, the original text and translations each occupy one line | SubRip subtitles (DaVinci Resolve, VLC, etc.) |
sbv | H:MM:SS.mmm | No sequence numbers; timecodes separated by ,; original text and translations joined into a single line with | (line breaks are replaced with spaces) | YouTube subtitle upload |
vtt | HH:MM:SS.mmm | Uses WEBVTT as the header; after each timecode, the original text and translations each occupy one line | HTML5 <track> subtitles, web players |
csv | HH:MM:SS (no milliseconds) | Starts with a UTF-8 BOM; columns index,start,end,speaker,text,<one column per translation language>. A language with no usable translations anywhere in the transcript gets no column | 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 (opens directly in Excel; the UTF-8 BOM keeps non-ASCII text from becoming 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
Tip:
curl -OJlets curl automatically name the saved file based on the server'sContent-Dispositionresponse.
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-Typeis determined dynamically by theformatparameter:
Format Content-Type txttext/plain; charset=UTF-8srtapplication/x-subripsbvtext/plain; charset=UTF-8vtttext/vtt; charset=UTF-8csvtext/csv; charset=UTF-8
Output Examples
Assume the transcript contains two English recording segments (en-US) with 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,多謝,ありがとう
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
recording_not_found | 404 | Recording not found | Verify that taskId is correct and the recording has not been deleted |
recording_transcript_not_ready | 422 | Transcript not yet generated or empty | First confirm via GET /api/v1/tasks that processing_status = completed before calling |
validation_failed | 422 | Parameter validation failed | Verify that format is one of the allowed values (txt / srt / sbv / vtt / csv) |
storage_download_failed | 500 | Storage service download failed | Retry later; if it keeps failing, contact support |
Frontend Example
async function downloadTranscript(taskId, apiKey, format = 'srt') {
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/tasks/${taskId}/transcript/export?format=${format}`,
{
headers: { 'X-API-Key': apiKey },
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Download failed: ${error.data?.message}`);
}
// Parse Content-Disposition to get the suggested filename
const disposition = response.headers.get('Content-Disposition') || '';
const match = disposition.match(/filename\*=UTF-8''([^;]+)/);
const filename = match
? decodeURIComponent(match[1])
: `transcript-${taskId}.${format}`;
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
POST /api/v1/tasks/{taskId}/force-fail
Description
Force-mark as failed a task that is stuck in a non-terminal state (recording / importing / uploading / pending / processing). Use case: the live connection broke abnormally but the follow-up status notification never arrived, or the user wants to abandon a recording that is still uploading and does not want to wait for the automatic cleanup of timed-out tasks.
After a successful operation:
processing_statusbecomesfailed, andprocessing_erroris written with the reason provided by the user- A
recording.failedwebhook is triggered, withpayload.failure_sourceset touser_forced, so subscribers can distinguish this source from "system processing failure" and "automatic timeout cleanup" - If
uploading/processingis pushed for this task afterwards, it is rejected with a 409, so the terminal-state protection takes effect
Note: Calling this endpoint on a task that is already in a terminal state (
completed/failed) returns 422. To remove a completed task, useDELETE /api/v1/tasks/{taskId}instead.
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Default | Description |
|---|---|---|---|---|---|
taskId | path | string | Yes | — | Task ID (UUID) |
reason | body | string | null | No | null | Failure reason description, up to 500 characters. When empty, the system automatically generates User-forced failure (previous status: xxx) |
Request Example
# Without a reason
curl -X POST "https://vas-poc.vurbo.ai/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000/force-fail" \
-H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"
# With a reason
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": "Recording client disconnected too long, giving up"}'
Success Response
HTTP 200
{
"data": {
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"processing_status": "failed",
"processing_error": "User-forced failure: Recording client disconnected too long, giving up (previous status: recording)"
}
}
Response Field Details
| Field | Type | Description |
|---|---|---|
data.task_id | string | Task ID (UUID) |
data.processing_status | string | Always failed after a forced failure |
data.processing_error | string | The complete failure reason written to the DB (including the previous status) |
Specific Error Codes
| Error Code | HTTP Status | Description | Suggested Action |
|---|---|---|---|
recording_not_found | 404 | Recording not found, or the recording does not belong to this user | Verify that taskId is correct and the recording has not been deleted |
invalid_processing_status | 422 | The task is already in a terminal state (completed / failed) and cannot be forced to fail | For completed tasks, use DELETE instead; failed tasks do not need to be force-failed again |
validation_failed | 422 | reason exceeds 500 characters, or taskId has an invalid format | Check the length of reason and the UUID format of taskId |
Frontend Example
async function forceFailTask(taskId, apiKey, reason = null) {
const body = reason ? JSON.stringify({ reason }) : undefined;
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/tasks/${taskId}/force-fail`,
{
method: 'POST',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
},
body,
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Force-fail failed: ${error.data?.message}`);
}
return await response.json();
}
POST /api/v1/tasks/{taskId}/retry
Description
Re-queue for processing a task that is in the failed state. This is for cases where a transient backend service failure (such as the LLM service being rate limited or the summary service briefly going down) caused processing to fail and the user wants to retry.
Preconditions
| Condition | Required Value |
|---|---|
processing_status | failed |
audio_status | success |
transcript_status | success |
If any condition is not met, 422 invalid_processing_status is returned. If the audio or transcript has not finished uploading, the retry would immediately fail again (because the source cannot be found), so this endpoint blocks it in advance to avoid a pointless retry loop.
Even when every prerequisite is met, if another processing run for the same task has not finished yet, 409 task_already_processing is returned and the task status is left unchanged; send the same request again later.
Note: After a task fails, the system retries it automatically a few times. During that period processing_status may already read failed while a retry still returns 409 — this means the automatic retries have not finished; send the same request again a few minutes later.
After a successful operation:
processing_statusbecomesprocessing, andprocessing_erroris cleared- The task is re-queued for processing; the platform guarantees the processor sees the updated status and never reruns against the previous one
- No webhook is triggered (
recording.completed/recording.failedis triggered only when the job finishes)
Authentication
Header: X-API-Key (see Authentication)
Request Parameters
| Parameter | Location | Type | Required | Default | Description |
|---|---|---|---|---|---|
taskId | path | string | Yes | — | Task 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"
}
}
Specific Error Codes
| Error Code | HTTP Status | Description | details Field | Suggested Action |
|---|---|---|---|---|
recording_not_found | 404 | Recording not found, or the recording does not belong to this user | — | Verify that taskId is correct |
invalid_processing_status | 422 | The task is not in the failed state | details.current_status | Only failed tasks can be retried |
invalid_processing_status | 422 | Audio / transcript not fully uploaded | details.audio_status, details.transcript_status | First confirm whether the source is complete; if the recording source is already corrupted, use force-fail to close it out and re-record |
task_already_processing | 409 | Another processing run for the same task has not finished yet | details.task_id | Send the same request again later; no parameter changes are needed |
Frontend Example
async function retryTask(taskId, apiKey) {
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/tasks/${taskId}/retry`,
{
method: 'POST',
headers: { 'X-API-Key': apiKey },
}
);
if (!response.ok) {
const error = await response.json();
const details = error.data?.details;
if (details?.audio_status && details.audio_status !== 'success') {
throw new Error(`Cannot retry: audio not ready (${details.audio_status})`);
}
throw new Error(`Retry failed: ${error.data?.message}`);
}
return await response.json();
}
Version: V1.24.1 Last Updated: 2026-09-29