Regenerate Summary
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} |
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 | Writes DB | Saves transcript | Billed | Purpose |
|---|---|---|---|---|---|
| GET | /api/v1/sse/regenerate/summary/{taskId} | ❌ | ❌ | ✅ | Preview (dry run, compare results across prompts) |
| POST | /api/v1/sse/regenerate/summary/{taskId} | ✅ | ✅ + bump revision | ✅ | 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 | ≤2000 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 (pass-through) |
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 → 422 validation error (summary_mode_field_mismatch)
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
- ✅ Adds one billing record with
type=summarytousage_logs(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
- ✅ Adds one billing record with
type=summarytousage_logs - ✅ 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 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
connected
{
"message": "Summary regeneration stream connected (recordingId: 550e8400-..., mode: custom, endpoint: preview)"
}
⚠️ Avoid confusion: The
modein the message is the business 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,
"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 | Business 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) |
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) |
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 summary template was not found (builtin mode) | Confirm template is correct |
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 |
llm_content_filtered | 400 | Blocked by content filtering (the custom prompt or transcript contains sensitive terms) | As of v1.5.5, the SSE endpoint has not yet integrated the fallback chain; we recommend using the POST /api/v1/summary REST endpoint to trigger automatic downgrade, or revise the prompt and retry |
Content filtering fallback chain — current status of the SSE endpoint (v1.5.5):
WebSocket realtime summaries and file-import summaries integrated the L1→L2→L3 fallback chain in v1.5.5; when blocked, they automatically downgrade to produce a simplified summary. However, this endpoint (SSE
regenerate/summary) has not yet integrated it, and will still returnllm_content_filtereddirectly.A follow-up PR will integrate the fallback chain and extend the
doneevent withfallback_level/dropped_segmentsfields. At that point the client can usedone.fallback_levelto determine whether a fallback occurred. Until then, if your integration requires the automatic downgrade behavior for content filtering, we recommend triggering it through thePOST /api/v1/summaryREST endpoint. |summary_text_too_long| 400 | The transcript exceeds the length limit (100,000 characters) | Shorten the recording or split the file | |summary_invalid_mode| 422 |modeis notbuiltin/custom| Change to a valid mode | |summary_mode_field_mismatch| 422 | The mode and field combination do not match (a required field is missing or a forbidden field was included) | Adjust the fields according to the mode rules | |summary_prompt_too_long| 422 |promptexceeds 2000 characters | Shorten it | |summary_prompt_slug_too_long| 422 |promptSlugexceeds 64 characters | Shorten it | |summary_prompt_slug_invalid| 422 |promptSlugcontains control characters (\n/\r/\t/\0, etc.) | Remove the control characters | |sse_summary_regeneration_failed| 500 | Summary regeneration failed (internal errors are sanitized and will not leak the LLM raw error) | Retry later |
Version: V1.5.7 Last Updated: 2026-05-20