Regenerate Summary SSE
Connection Information
| Item | Value |
|---|---|
| Base path | https://vas-poc.vurbo.ai/api/v1/sse |
| Protocol | HTTP + Server-Sent Events (SSE) |
| Data format | text/event-stream |
| Authentication | Header X-API-Key: {KEY}, or query ?api_key={KEY} (either works; query takes precedence) |
Note: The browser's native EventSource API does not support custom headers. Use the fetch API with a ReadableStream, or use an SSE client library that supports headers.
Endpoint Overview
Split into two endpoints, preview and persist:
| Method | Endpoint | Persists Result | Saves transcript | Billed | Purpose |
|---|---|---|---|---|---|
| GET | /api/v1/sse/regenerate/summary/{taskId} | No | No | Yes | Preview (dry run, compare results across prompts) |
| POST | /api/v1/sse/regenerate/summary/{taskId} | Yes | Yes (and increments revision) | Yes | Persist (official save) |
Known limitation: The GET preview is still billed — the LLM genuinely consumes tokens, so the GET endpoint cannot be used for free. Calling GET repeatedly is billed each time, but does not change the backend's stored state.
Shared: Request Parameters
GET uses the query string and POST uses a JSON body, with identical field names and types:
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
taskId (path) | string | Yes | UUID | Recording ID |
mode | string | Yes | enum "builtin" | "custom" | Explicit path selection |
template | string | Required for builtin / forbidden for custom | exists prompt_templates.slug | Built-in template slug |
prompt | string | Required for custom / forbidden for builtin | ≤3000 characters | The customer's complete prompt (replaces the built-in layered prompt) |
promptSlug | string | Required for custom / forbidden for builtin | ≤64 characters, Unicode, no control characters | The customer's own identifier (returned as-is, not processed) |
language | string | No | - | Summary output language code (e.g. zh-TW, en-US); when unspecified, the first transcription language is used |
plainText | boolean | No | Default false | Request plain-text output (the backend performs additional markdown post-processing) |
Mutual exclusion rules:
- With
mode=builtin, you may not includepromptorpromptSlug - With
mode=custom, you may not includetemplate, butpromptandpromptSlugare required
Violations → parameter validation failure (an error event whose data carries only message, with no error_code)
GET /api/v1/sse/regenerate/summary/{taskId} (preview)
Description
Runs the LLM once to regenerate the summary, streaming only to the client. Does not write the DB and does not update the transcript record.
Use case: the client wants to try different prompt / plain_text settings, compare the results, and then decide whether to persist.
Request Examples
builtin mode
curl -N "https://vas-poc.vurbo.ai/api/v1/sse/regenerate/summary/550e8400-e29b-41d4-a716-446655440000?mode=builtin&template=meeting&language=zh-TW&plainText=true" \
-H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"
custom mode
curl -N "https://vas-poc.vurbo.ai/api/v1/sse/regenerate/summary/550e8400-e29b-41d4-a716-446655440000?mode=custom&prompt=%E8%AB%8B%E5%BC%B7%E8%AA%BFKPI&promptSlug=acme-meeting-v2&plainText=true" \
-H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"
Side Effects
- Incurs one summary billing charge (the LLM genuinely consumes tokens)
- Does not update the three columns
recordings.summary_mode/summary_template/summary_prompt_slug - Does not overwrite the saved summary
POST /api/v1/sse/regenerate/summary/{taskId} (persist)
Description
All actions of the GET preview, plus writing to the DB and the transcript record.
Request Examples
builtin mode
curl -N -X POST "https://vas-poc.vurbo.ai/api/v1/sse/regenerate/summary/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: vas_..." \
-H "Content-Type: application/json" \
-d '{
"mode": "builtin",
"template": "meeting",
"language": "zh-TW",
"plainText": true
}'
custom mode
curl -N -X POST "https://vas-poc.vurbo.ai/api/v1/sse/regenerate/summary/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: vas_..." \
-H "Content-Type: application/json" \
-d '{
"mode": "custom",
"prompt": "You are a dermatology specialist assistant. Extract the Fitzpatrick skin type from the transcript...",
"promptSlug": "skin-clinic-acme-v2",
"language": "zh-TW",
"plainText": true
}'
Side Effects
- Incurs one summary billing charge
- Mutually exclusive writes to the three
recordingscolumns, depending on mode:- builtin →
summary_mode='builtin',summary_template=<slug>,summary_prompt_slug=NULL - custom →
summary_mode='custom',summary_template=NULL,summary_prompt_slug=<customer slug>
- builtin →
- Updates the task's summary language: the
summary_languagein the task list and in the historyinit_metadatachanges to the language used this time - Updates the top-level fields of the transcript record and bumps
revision += 1:summary(plain string),summary_language,summary_mode,summary_template(effective slug),summary_plain_text- Required in custom mode:
summary_prompt_snapshot(a verbatim snapshot of the customer's prompt, the only basis for reconstruction)
Event Sequence (same for both endpoints)
1. connected → connection confirmation
2. summary_regeneration → sends summary chunks (repeats N times, cumulative)
3. done → generation complete
or
3. error → generation failed (sse_summary_regeneration_failed; can occur on both endpoints;
nothing is saved or billed, and **no** done is sent)
or
3. error → save failed, or another write is in progress (storage_upload_failed /
transcript_revision_conflict; the request stops and **no** done is sent)
The
errorfor a failed save or a concurrent write occurs only on the save endpoint (POST). The preview endpoint (GET) does not write to the transcript and never reaches it.
connected
{
"message": "Summary regeneration stream connected (taskId: 550e8400-..., mode: custom, endpoint: preview)"
}
Note: Avoid confusion: The
modein the message is the summary mode (builtin/custom, the mode passed in the request);endpointis the endpoint mode (previewfor GET /persistfor POST). The two have different meanings; do not conflate them.
summary_regeneration
{ "text": "This meeting discussed the following topics:\n1. Product development progress", "is_final": false }
| Field | Type | Description |
|---|---|---|
text | string | Cumulative summary content (when plainText=true, the text of the is_final=true event is the cleaned plain text) |
is_final | boolean | Whether this is the final result |
done
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"tokens_used": 123,
"final_content": "This meeting... (complete cleaned content)",
"mode": "custom",
"template": "skin-clinic-acme-v2",
"plain_text": true,
"persisted": true,
"summary_language": "zh-TW",
"characters_billed": 12700,
"charged": "1.3",
"billed": true,
"prompt_snapshot": "You are a dermatology specialist assistant..."
}
| Field | Type | Description |
|---|---|---|
task_id | string | Recording UUID |
tokens_used | number | Total token usage |
final_content | string | Complete summary content (cleaned plain text when plainText=true) |
mode | string | Summary mode: "builtin" or "custom" |
template | string | effective slug — builtin → built-in template slug; custom → customer slug |
plain_text | boolean | Whether plain-text mode is enabled |
persisted | boolean | Whether this summary has been officially saved (false for GET, true for POST) |
summary_language | string | The language actually used for this summary (BCP 47). The language value if one was sent; otherwise the first transcription language. Present for both preview (GET) and save (POST), and always has a value (added in v1.16.5) |
characters_billed | number | Character count used as the billing basis for this request |
charged | string | Points consumed by this operation, calculated from the rate. This value reflects usage: usage already covered by an unlimited plan is still reported here |
billed | boolean | Whether this request incurred consumption; always true (all three fields are absent when nothing was consumed) |
prompt_snapshot | string | Appears only in custom mode; the verbatim prompt content passed in by the customer (a required snapshot, the only basis for reconstruction) |
truncated | boolean | Present only when the summary could not be produced in full (the value is always true). The field is absent entirely when the summary is complete. When present, final_content is not a complete summary: the summary reached the output length limit, or generation reached the processing time limit (only the part completed so far is returned). Both cases are billed as usual, and the save endpoint (POST) also saves this incomplete summary |
Billing fields:
characters_billed,charged, andbilledappear only when the request actually incurred consumption. When nothing was consumed (for example, when generation fails), all three are absent. Always usebilledto determine whether a request was billed (billed only whenbilledistrue) — that criterion applies to every endpoint that carries billing fields, with no per-endpoint exceptions. Integrators that call this API on behalf of end users and bill them separately can usechargeddirectly instead of deriving it. Both preview (GET) and save (POST) are billed, so both carry the billing fields. If generation fails (sse_summary_regeneration_failed), or the save endpoint emitserrorbecause the save failed (see "Event Sequence", step 3), that request is not billed and nodoneis sent.
Specific Error Codes
| Error Code | HTTP | Description | Recommended Action |
|---|---|---|---|
recording_not_found | 404 | The specified recording was not found | Confirm taskId is correct |
sse_template_not_found | 404 | The template exists but has been disabled (builtin mode) | Use a different template |
sse_transcript_not_found | 404 | The transcript was not found | The recording may not have finished processing yet |
summary_text_empty | 400 | The transcript has no content to summarize | The recording content is too short or is entirely silence |
summary_text_too_long | 400 | The transcript exceeds the length limit (200,000 characters) | Shorten the recording or split the file |
sse_summary_regeneration_failed | 500 | Summary regeneration failed (the response does not include internal error details). Also returned when the stream stalls or does not end normally; nothing is saved or billed, and the summary_regeneration chunks received before it are not a complete result, so discard them | Retry later |
transcript_revision_conflict | 409 | Another write to the same transcript is in progress (save endpoint only) | The summary was not saved and is not billed; retry shortly. No done follows this code |
storage_upload_failed | 500 | Failed to write the transcript back to storage (save endpoint only) | The summary was not saved and is not billed; retry later. No done follows this code |
auth_insufficient_credit | 402 | Insufficient credit | This is a real HTTP 402 JSON response returned before the stream starts, not an SSE event; top up and retry |
stt_quota_exceeded | 402 | Available credit does not cover the estimated cost of this request | Also a JSON response returned before the stream starts; top up and retry |
Parameter validation failures carry no error code. An invalid
mode, a field combination that does not match the mode, apromptorpromptSlugthat is too long or contains control characters — all of these are rejected during parameter validation. The response is anerrorevent whosedatacarries onlymessage, with noerror_code. Presentmessageto the user; do not try to match on an error code.A nonexistent
templateslug is also a parameter validation failure (message:The specified summary template does not exist) - it is not a 422 and carries no error code.
Content filtering — current status of this SSE endpoint:
Realtime recording summaries and file-import summaries already support automatic content-filter fallback (standard mode -> neutral mode -> segment-omission mode), and produce a simplified summary when blocked. This endpoint (SSE
regenerate/summary) does not support it yet — when content filtering is triggered, this endpoint always returnssse_summary_regeneration_failed, and the response does not distinguish "filtered" from any other generation failure.A future release will add automatic fallback and extend the
doneevent withfallback_level/dropped_segmentsfields. Until then, if a retry still fails, revise the prompt or the transcript content.
Version: V1.24.1 Last Updated: 2026-09-28