SSE API

Summary Translation SSE

Connection Information

ItemValue
Base pathhttps://vas-poc.vurbo.ai/api/v1/sse
ProtocolHTTP + Server-Sent Events (SSE)
Data formattext/event-stream
AuthenticationHeader X-API-Key: {KEY} (this endpoint does not accept the key in the query string)

Note: This endpoint accepts POST only (JSON body), so the browser's native EventSource API cannot be used. Use the fetch API with a ReadableStream, or any HTTP client that can read a streaming response.


Endpoint Overview

MethodEndpointResult savedBilledPurpose
POST/api/v1/sse/summary/translateNoYesTranslate summary text supplied in the request into the specified language (not tied to any recording)

How it differs from Retranslate Summary:

  • Retranslate Summary: the input is the summary saved on the server for that recording, and it is not billed.
  • This endpoint: the input is the content in the request, for content the server does not have, such as a merged summary or a summary edited by the user.

Both translate the same way. The result is not saved and is only streamed back to the client.

Added in v1.17.0.


Request Parameters (JSON body)

ParameterTypeRequiredLimitsDescription
contentstringYes≤30,000 characters, not whitespace onlyThe summary text to translate
target_languagestringYesA language code from Supported LanguagesTarget language
source_languagestringNoA language code from Supported LanguagesSource language. Detected automatically when omitted. Returns 422 if it is the same as target_language
idempotency_keystringYes≤64 characters, A-Z a-z 0-9 . _ -Duplicate-request identifier that prevents double charging. Same rules as Ad-hoc Summary

Error Response Pattern

This endpoint is meant for backend integrations. Errors before the stream starts always return a real HTTP status code (JSON body), the same as Ad-hoc Summary:

StageResponse
Authentication failure (401/403), validation failure (422), insufficient credit (402), identifier conflict (409), rate limit or free-retry limit exceeded (429)Real HTTP status code with a JSON error body
After the stream starts (translation failure, timeout, content filtered, and so on)HTTP 200 with an SSE error event

A 422 JSON body lists the per-field messages in data.details.errors.


Billing

  • Billed by the character count of content: 0.1 credits per 200 characters (a partial unit counts as a full 200 characters). This is the same rate as full-transcript retranslation.
  • Examples: 450 characters = 0.3 credits; 30,000 characters = 15 credits.
  • Billed only on success. A request that ends with error is not billed.
  • A truncated translation (see "Processing Time and Truncation" below) is billed as usual; a translation judged to be unfinished is not billed. Always check billed in done to see whether credits were actually deducted.

Duplicate Requests and Billing Guarantees

The system uses the entire request (content, target_language, source_language) to decide whether two requests are retries of the same job:

SituationBehavior
Same identifier, identical requestNot billed again, but the translation is run again rather than replaying the previous result
Same identifier, any field different (including only the target language)Returns 409 summary_idempotency_key_conflict; not translated, not billed
Retry after the first request failed, or after it was judged unfinishedThe identifier is not consumed; the retry is treated as a new request

idempotency_key is scoped to a single API key. To translate new content or switch to another language, send a new idempotency_key.


Request Example

curl -N -X POST "https://vas-poc.vurbo.ai/api/v1/sse/summary/translate" \
  -H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "## 會議摘要\n\n1. 產品上線時程確認為下月初",
    "target_language": "ja-JP",
    "source_language": "zh-TW",
    "idempotency_key": "summary-7f3a-ja"
  }'

Event Sequence

1. connected              → connection confirmed
2. summary_translation    → translated text (repeated N times, cumulative)
3. done                   → translation complete
   or
   error                  → translation failed (the stream stops and done is not sent)

connected

{ "message": "Summary translation stream connected (target_language: ja-JP)" }

summary_translation

{ "text": "## 会議の要約\n\n1. 製品のリリース時期は来月初めに確定", "is_final": false }
FieldTypeDescription
textstringThe full translation accumulated so far. Each event extends the previous one
is_finalbooleanWhether this is the last event. The last event's text is the complete content delivered for this request; if done carries truncated, the translation is incomplete

How long content is streamed: when the content is long, the stream often delivers a large block at once (possibly thousands of characters), and there may be a pause of a few seconds between events. Each event is still the cumulative full text, in the original order.

If you want to render the text character by character, smooth it on the client side.

done

{
  "tokens_used": 230,
  "source_language": "zh-TW",
  "target_language": "ja-JP",
  "characters_billed": 24,
  "charged": "0.1",
  "idempotency_key": "summary-7f3a-ja",
  "billed": true
}
FieldTypeDescription
tokens_usednumberTotal tokens used
source_languagestring | nullThe source language sent in the request; null when it was omitted
target_languagestringTarget language
characters_billednumberBilling basis (the character count of content)
chargedstringCredits consumed, calculated from the rate. This value reflects usage: it is still reported for usage covered by an unlimited plan, for free retries, and when the translation is judged unfinished. Check billed to see whether credits were actually deducted
idempotency_keystringThe identifier sent in the request, echoed back for reconciliation
billedbooleanWhether credits were actually deducted for this request. It is false for a free retry with the same identifier and when the translation is judged unfinished. Reconcile against this field
truncatedbooleanPresent only when the translation is incomplete (the value is always true); absent when the translation is complete. There are two causes: the translation hit the processing-time or length limit and was cut off (billed as usual), or the translation is clearly shorter than the source and was judged unfinished (not billed). If this request is not a retry with the same identifier, billed tells them apart: true means cut off, false means judged unfinished

When you receive truncated: true, the last event's text is not the complete translation. We recommend not saving it as the final translation; you can prompt the user to retry.


Processing Time and Truncation

  • A request has a processing-time limit of about 230 seconds, counted from when the request is sent.
  • When the limit is reached, if some translation has already been received, the current content is sent as truncated: done carries truncated: true and the request is billed as usual. If nothing has been received yet, an error (Translation timed out) is sent and the request is not billed.
  • If no new content arrives for more than 60 seconds during translation, an error (Translation timed out) is sent and the request is not billed.

Endpoint-Specific Error Codes

Before the stream starts (real HTTP status code with JSON):

Error codeHTTPDescriptionSuggested handling
validation_failed422Validation failed, for example a missing field, more than 30,000 characters, whitespace only, an unsupported language, the same source and target language, or invalid text encodingFix the fields listed in data.details.errors
summary_idempotency_key_conflict409The same idempotency_key was already used for different request contentUse a new idempotency_key
stt_quota_exceeded402Available credit is not enough for the amount dueTop up and retry
too_many_requests429Rate limit exceeded, or the free-retry limit for the same idempotency_key has been reached (24-hour window). A 429 received when resending the same identifier means the free-retry limitFor the rate limit, retry later; for the free-retry limit, use a new idempotency_key and do not retry in a short loop

After the stream starts (HTTP 200 with an SSE error event):

Error codedetails.original_errorDescriptionSuggested handling
sse_summary_translation_failedTranslation timed outWaiting for a response timed out, translation paused for more than 60 seconds, or the time limit was reached before any translation arrivedRetry later
sse_summary_translation_failedEmpty translationThe translation result was empty. For long content, part of the translation may already have been receivedCheck the content and retry
sse_summary_translation_failedTranslation service unavailableThe translation service is temporarily unavailable, or the connection was interruptedRetry later
sse_summary_translation_failedService errorOther errors, including being unable to reach the translation service at allRetry later; if it persists, contact us with the request_id
llm_content_filteredContent filteredThe content cannot be translatedRetrying will not help; revise the content

None of these errors are billed, and none of them consume the identifier.


Version: V1.24.1 Last Updated: 2026-09-28

Copyright © 2026