Streaming summaries combine file transcription and summarization in a multipart HTTP request. The response contains Server-Sent Events (SSE), including the completed transcript and summary text as it is generated.
Submit a recording
Use this endpoint:
POST /aiservices/speech-summarization/summarize
Authenticate with your Zoom AI Services credentials. The examples on this page send a token in the Authorization: Bearer header.
| Form field | Required | Description |
|---|---|---|
file | Yes | One audio or video file uploaded as binary data. |
config | No | JSON string containing transcribe and summary settings. Send it before file. |
This example uploads a project-update recording and selects the corresponding static summary template:
curl --no-buffer --fail-with-body \
https://api.zoom.us/v2/aiservices/speech-summarization/summarize \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream" \
-F 'config={"transcribe":{"language":"en-US","diarization":false,"profanity_filter":false},"summary":{"language":"en-US","template_id":"project_update","enable_dynamic_template":false,"citations":true,"should_remove_sentiment":false}}' \
-F 'file=@project-update.wav;type=audio/wav'
Add the config part before the file part.
Let your HTTP client set the multipart Content-Type header and boundary. In cURL, -F does this automatically. --no-buffer displays events as they arrive.
Keep credentials on a trusted backend. Read the POST response as a stream with your HTTP client; a browser's native EventSource cannot submit this multipart POST request.
Configure transcription
Put recognition settings in config.transcribe. The recognition model is selected automatically and can't be changed.
| Field | Type | Default | Description |
|---|---|---|---|
language | string | en-US | Input speech locale. Supports the ten languages listed under Multilingual model languages. |
diarization | boolean | false | Identify different speakers in the recording. |
profanity_filter | boolean | false | Filter profanity in the transcript. |
For accepted media formats and upload limits, see Recording requirements.
Configure summarization
Put summary settings in config.summary. The summary language can differ from the transcription language.
| Field | Type | Default | Description |
|---|---|---|---|
language | string | en-US | Summary output language. |
template_id | string | None | Predefined summary template. See Static templates. |
custom_template | string | None | A Markdown template. The summary follows its headings, structure, and formatting. |
summary_length | string | short | short or long. |
citations | boolean | true | Include references to transcript evidence in the summary. |
should_remove_sentiment | boolean | false | Remove most sentiment and emotion expressions from the summary. Removal isn't guaranteed to be complete. |
enable_dynamic_template | boolean | true | Automatically select a template based on the meeting type when no static or custom template is specified. |
Automatic template
Omit template_id and custom_template and set enable_dynamic_template to true, or leave it at its default. The API detects the meeting type and selects a template.
{
"summary": {
"language": "en-US",
"enable_dynamic_template": true,
"citations": true
}
}
Static templates
Set template_id to one of these values. Selecting a static template disables automatic template selection. You can also set enable_dynamic_template to false explicitly.
| Template ID | Purpose |
|---|---|
one_on_one | One-on-one meeting |
stand_up | Stand-up meeting |
brainstorm | Brainstorming session |
project_update | Project update |
discussion | General discussion |
q_a | Question-and-answer session |
customer_success | Customer success call |
user_feedback | User feedback session |
lecture_summary | Lecture summary |
next_steps | Next steps and action items |
Custom template
Set custom_template to a Markdown template. The summary follows the template's headings, structure, and formatting. A custom template overrides automatic template selection. Choose one template mode per request.
{
"summary": {
"language": "en-US",
"custom_template": "## Decisions\n- \n\n## Owners\n| Person | Task |\n| --- | --- |\n",
"enable_dynamic_template": false,
"citations": false
}
}
Handle the event stream
A successful streaming response uses Content-Type: text/event-stream. Each event has an event: name and JSON in its data: field. A blank line separates events.
HTTP response chunks do not necessarily align with SSE event boundaries. Buffer incomplete events before parsing their JSON.
| Event | Meaning | Client action |
|---|---|---|
transcribe_started | Transcription has started. | Show transcription progress. |
transcribe_complete | The complete transcript is available. | Save transcript for display or downstream use. |
summary_updated | The summary has been updated. | Replace the displayed summary with summary_result. Check response_state. |
done | Processing completed. | Save the last summary and mark the request complete. |
error | A processing stage failed. | Handle the error and retain any completed transcript. |
Transcription events
event: transcribe_started
data: {"status":"transcribing"}
event: transcribe_complete
data: {"transcript":{"request_id":"3f2b8c1e-7a4d-4e9b-b6f0-1c5d8a2e9b47","duration_sec":5.2,"result":{"text_display":"We agreed to release the documentation on October fifteenth.","segments":[{"id":"utt_0000","start":0.0,"end":5.2,"channel":0,"speaker":"","text":"We agreed to release the documentation on October fifteenth.","words":[]}]}},"latency_ms":5234,"body_bytes":12456,"status_code":200}
transcribe_complete includes the transcription result in transcript, the transcription latency in latency_ms, the size of the transcription result in body_bytes, and the transcription status in status_code. The example shows a shortened transcript; it is not a complete list of response fields.
Summary updates
Each summary_updated event contains the full summary so far in summary_result. Replace the displayed text with each update. response_state is working during generation and completed in the final update.
Skip empty summary_result values when updating the display. HTML in the summary is escaped: <br> arrives as <br>.
event: summary_updated
data: {"summary_result":"## Decisions\n- Release the documentation on October fifteenth.","citations":null,"response_state":"working","error":null}
event: summary_updated
data: {"summary_result":"## Decisions\n- Release the documentation on October fifteenth.[^1]","response_state":"completed","error":null,"citations":[{"id":1,"marker":"[^1]","start_time":"00:00:00.000","end_time":"00:00:05.200","start_item_index":0,"end_item_index":0}]}
The summary is Markdown. When citations is enabled, the final update adds Markdown footnote markers, such as [^1], and a citations array that links each marker to the transcript. Earlier updates have "citations": null.
| Field | Description |
|---|---|
id | Citation number. |
marker | The marker used in the summary text, such as [^1]. |
chunk_id | ID of the transcript chunk that supports the statement. |
speaker | Speaker label of the cited chunk. |
start_time, end_time | The cited span of the recording, in HH:MM:SS.mmm format. Use them to find the matching transcript segments. |
start_item_index, end_item_index | The first and last transcript segments in the cited span. |
Preserve the markers when displaying or storing the summary.
Completion
event: done
data: {"status":"complete","total_latency_ms":8500,"transcribe_ms":5234,"summary_ms":3266}
The done event reports total processing latency and the transcription and summary stage latencies, in milliseconds. Save the last summary_result; the done payload does not repeat the summary text.
Handle errors
Check the HTTP status, then read the SSE events. HTTP 200 starts the stream. A successful request ends with a summary_updated event with response_state: "completed", followed by done.
Treat an error event, a summary_updated event with response_state: "error", or a connection that ends before done as a failure. When processing fails, the API sends an error event without done.
| HTTP status | Meaning |
|---|---|
200 | Streaming response. Read events to determine the outcome. |
400 | Invalid configuration, missing file, or unsupported format. |
401 / 403 | Invalid credentials, or the request isn't authorized. |
402 | Your credit is exhausted, or the credential's credit limit was reached. |
405 | Incorrect HTTP method; use POST. |
413 | Upload exceeds 50 MB. |
429 | Too many requests. See rate limits. |
502 | Transcription or summary service error. |
503 | The summary service is temporarily unavailable. |
An SSE error identifies the failed stage:
event: error
data: {"error":"transcribe failed: connection timeout","stage":"transcribe"}
| Stage | Meaning |
|---|---|
transcribe | Transcription failed. |
summary_preparation | Preparing the transcript for summarization failed. |
summary | Summary generation failed. |
If transcription fails, the API does not return a partial transcript. If summary generation fails after transcribe_complete, retain the completed transcript and show that summarization did not finish.