---
title: "Create and update live transcription sessions in Speak AI"
description: "Open a live transcription session in Speak AI, mint the token that authorizes the streaming connection, and send words and the recording back as it runs."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.speakai.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Create and update live transcription sessions in Speak AI


import EndpointIndex from "@/components/api/EndpointIndex.astro";

The Speak AI API exposes 3 live transcription endpoints under the base URL `https://api.speakai.co/v1`. Every request needs the `x-speakai-key` and `x-access-token` headers described in [Authentication](/api/authentication/).

Live transcription turns a running audio or video session into a transcript while the session is still going. The three REST endpoints below open the session, feed it, and close it.

A session runs in three steps. Create the media record with `POST /live-transcription/create`, mint a handshake token with `POST /live-transcription/token`, then send transcribed words to `POST /live-transcription/update/{mediaId}` as they arrive.

When the session ends, send the finished recording to the same update endpoint. Speak AI transcodes it and runs the full analysis, so a live session ends up with the same transcript, speakers, and insights as an uploaded file.

The audio itself streams over a separate WebSocket connection that the handshake token authorizes. That connection is not part of the REST API and its host is not documented here.

## Supported languages

Pass one of these codes as `sourceLanguage` when you create the session.

| value | name |
| --- | --- |
| en-US | English (US) |
| en-AU | English (Australia) |
| en-GB | English (British) |
| en-IN | English (Indian) |
| en-IE | English (Irish) |
| en-NZ | English (New Zealand) |
| en-AB | English (Scottish) |
| en-ZA | English (South African) |
| en-ES | English + Spanish (Multiple) |
| fr-FR | French |
| fr-CA | French (Canada) |
| es-ES | Spanish |
| es-MX | Spanish (Mexico) |
| bg-BG | Bulgarian |
| ca-ES | Catalan |
| zh-CN | Chinese (Simplified) |
| zh-TW | Chinese (Traditional) |
| zh-HK | Chinese (Cantonese, Traditional) |
| cs-CZ | Czech |
| da-DK | Danish |
| nl-NL | Dutch |
| et-EE | Estonian |
| nl-BE | Flemish |
| fi-FI | Finnish |
| de-CH | German (Swiss) |
| de-DE | German |
| el-GR | Greek |
| hi-IN | Hindi |
| hi-Latn | Hindi (Latin) |
| hu-HU | Hungarian |
| id-ID | Indonesian |
| it-IT | Italian |
| ja-JP | Japanese |
| ko-KR | Korean |
| lt-LT | Lithuanian |
| lv-LV | Latvian |
| ms-MY | Malay |
| nb-NO | Norwegian |
| pl-PL | Polish |
| pt-BR | Portuguese (Brazilian) |
| pt-PT | Portuguese (Portugal) |
| ro-RO | Romanian |
| ru-RU | Russian |
| sk-SK | Slovak |
| sv-SE | Swedish |
| taq | Tamasheq |
| th-TH | Thai |
| tr-TR | Turkish |
| uk-UA | Ukrainian |
| vi-VN | Vietnamese |

## What can you do with the live transcription endpoints?

Speak AI groups these 3 endpoints under the live transcription resource. Each entry below links to the full reference for that endpoint further down this page.

| Method | Path | What it does |
| --- | --- | --- |
| `POST` | [`/live-transcription/create`](#post-live-transcription-create) | Create a live transcription session |
| `POST` | [`/live-transcription/token`](#post-live-transcription-token) | Mint a live transcription handshake token |
| `POST` | [`/live-transcription/update/{mediaId}`](#post-live-transcription-update-media-id) | Update a live transcription session |

<h2 id="post-live-transcription-create">Create a live transcription session</h2>

Create the media record that a live transcription session writes into, and get back the `mediaId` the streaming connection needs.

Call this first. The record is created in the `liveTranscript` state with its processing progress already at 100, so it appears in the folder straight away and fills with words as the session runs.

Every field in the body is optional. When `folderId` is left out, Speak AI stores the record in the first folder on the account.

#### Sessions that already exist

Pass `meetingAssistantId` to attach the session to a scheduled meeting assistant event. When that event already has a media record, Speak AI returns the existing `mediaId` instead of creating a second one, so the call is safe to repeat.

### Request body

Field types and names come from the request body the spec records. The spec does not mark request body fields as required, so read this as the shape the endpoint accepts rather than a required field list.

| Field | Type | Description |
| --- | --- | --- |
| `name` | string | Name for the media record. A meeting assistant event overrides this with its own title. |
| `mediaType` | string | Recording MIME type, for example `audio/webm` or `video/mp4`. Speak AI keeps the part before the slash, and stores anything it does not recognise as `audio`. |
| `sourceLanguage` | string | Language code for the session. Defaults to `en-us`. |
| `folderId` | string | Folder to store the record in. Defaults to the first folder on the account. |
| `tag` | string | Single tag stored on the record. |
| `uploadType` | string | How the session was started. Speak AI sets this itself for meeting assistant and embedded recorder sessions. |
| `meetingAssistantId` | string | Id of a scheduled meeting assistant event to attach the session to. |
| `recorderToken` | string | Token of a recorder, when the session comes from an embedded recorder. Speak AI then takes the folder and the source language from the recorder. |

<div slot="code">

<CodePanel label="Example request">

```bash
curl -X POST 'https://api.speakai.co/v1/live-transcription/create' \
  -H 'x-speakai-key: sk_test_speak_0000000000000000' \
  -H 'x-access-token: eyJhbGciOiJIUzI1NiJ9.test-access-token.0000000000' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Weekly customer call",
  "mediaType": "audio/webm",
  "sourceLanguage": "en-us",
  "folderId": "your_folder_id_here"
}'
```

</CodePanel>

<ResponsePanel id="post-live-transcription-create" statuses={[{"code":"200","description":"OK"},{"code":"500","description":"Internal Server Error"}]}>

<div slot="status-200">

**`200` OK**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `data` | object |
| `data.mediaId` | string |
| `data.folderId` | string |
| `data.userId` | string |
| `data.message` | string |

Example response (Session created), `application/json`.

```json
{
  "status": "success",
  "data": {
"mediaId": "3f8d1ec6ca39",
"folderId": "your_folder_id_here",
"userId": "609d7de35bde285f4c98ca63",
"message": "Live transcript media created successfully"
  }
}
```

Example response (Meeting assistant event already had a record), `application/json`.

```json
{
  "status": "success",
  "data": {
"mediaId": "3f8d1ec6ca39",
"folderId": "your_folder_id_here",
"userId": "609d7de35bde285f4c98ca63",
"message": "Existing live transcript media returned successfully"
  }
}
```

</div>

<div slot="status-500">

**`500` Internal Server Error**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `requestId` | string |
| `code` | integer |
| `message` | string |
| `hints` | string[] |

Example response (Internal server error), `application/json`.

```json
{
  "status": "failed",
  "requestId": "ca665625-645e-438a-867d-366a6e3f133a",
  "code": 500,
  "message": "Something went wrong. Please try again later.",
  "hints": [
"Something went wrong. Please try again later."
  ]
}
```

</div>

</ResponsePanel>

</div>

<h2 id="post-live-transcription-token">Mint a live transcription handshake token</h2>

Mint the short-lived token that opens a live transcription streaming connection for the calling session.

The token is scoped to live transcription only. It is rejected anywhere else in the API, so it cannot stand in for an access token.

This endpoint takes no request body. The response carries the token and the number of seconds it stays valid for.

#### Rate limit

This endpoint is limited to 5 requests per 60 seconds per IP address. Going over returns `429` with a plain text body, so mint one token per session and reuse it until it expires.

<div slot="code">

<CodePanel label="Example request">

```bash
curl -X POST 'https://api.speakai.co/v1/live-transcription/token' \
  -H 'x-speakai-key: sk_test_speak_0000000000000000' \
  -H 'x-access-token: eyJhbGciOiJIUzI1NiJ9.test-access-token.0000000000'
```

</CodePanel>

<ResponsePanel id="post-live-transcription-token" statuses={[{"code":"200","description":"OK"},{"code":"429","description":"Too Many Requests"},{"code":"500","description":"Internal Server Error"}]}>

<div slot="status-200">

**`200` OK**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `data` | object |
| `data.token` | string |
| `data.expiresIn` | string |

Example response (Token minted), `application/json`.

```json
{
  "status": "success",
  "data": {
"token": "eyJhbGciOiJIUzI1NiJ9.test-live-token.0000000000",
"expiresIn": "18000s"
  }
}
```

</div>

<div slot="status-429">

**`429` Too Many Requests**

Example response (Rate limited), `text/plain`.

```text
Too many token requests from this IP, please try again after a minute
```

</div>

<div slot="status-500">

**`500` Internal Server Error**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `requestId` | string |
| `code` | integer |
| `message` | string |
| `hints` | string[] |

Example response (Internal server error), `application/json`.

```json
{
  "status": "failed",
  "requestId": "ca665625-645e-438a-867d-366a6e3f133a",
  "code": 500,
  "message": "Something went wrong. Please try again later.",
  "hints": [
"Something went wrong. Please try again later."
  ]
}
```

</div>

</ResponsePanel>

</div>

<h2 id="post-live-transcription-update-media-id">Update a live transcription session</h2>

Append transcribed words to a live transcription session, and hand Speak AI the finished recording when the session ends.

Send `words` while the session runs. Speak AI merges them into sentences by speaker and language and appends them to the transcript already on the record.

Send `aws` once, after the recording is uploaded. That moves the record into the `preparingAnalysis` state, triggers transcoding, and starts the same analysis an uploaded file gets. Include `totalDuration` with it so the duration is right when the uploaded file does not report one.

Both fields are optional and they can be sent in the same call.

### Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `mediaId` | path | string | Yes | Id returned by `POST /live-transcription/create`. |

### Request body

Field types and names come from the request body the spec records. The spec does not mark request body fields as required, so read this as the shape the endpoint accepts rather than a required field list.

| Field | Type | Description |
| --- | --- | --- |
| `words` | object[] | Words transcribed since the last call, in order. |
| `words[].id` | integer | Position of the word in the session. |
| `words[].text` | string | The word itself. |
| `words[].confidence` | number | Recogniser confidence for the word, from 0 to 1. |
| `words[].language` | string | Language code the word was recognised in. |
| `words[].speakerId` | string | Speaker the word is attributed to. |
| `words[].instances` | object | Where the word sits in the recording. |
| `words[].email` | string | Email of the speaker, when the session knows it. |
| `words[].userId` | string | Speak AI user id of the speaker, when the session knows it. |
| `aws` | object | Location of the finished recording. Send this once, at the end of the session. |
| `aws.bucket` | string |  |
| `aws.key` | string |  |
| `aws.location` | string |  |
| `totalDuration` | number | Length of the session in seconds, used when the uploaded file reports a duration of 0. |

Deeper nested fields are not listed. See the example response below for the full shape.

<div slot="code">

<CodePanel label="Example request">

```bash
curl -X POST 'https://api.speakai.co/v1/live-transcription/update/3f8d1ec6ca39' \
  -H 'x-speakai-key: sk_test_speak_0000000000000000' \
  -H 'x-access-token: eyJhbGciOiJIUzI1NiJ9.test-access-token.0000000000' \
  -H 'Content-Type: application/json' \
  -d '{
  "words": [
{
  "id": 1,
  "text": "hello",
  "confidence": 0.95,
  "language": "en",
  "speakerId": "speaker-1",
  "instances": {
    "startInSec": 1.2,
    "endInSec": 1.5
  }
}
  ]
}'
```

</CodePanel>

<ResponsePanel id="post-live-transcription-update-media-id" statuses={[{"code":"200","description":"OK"},{"code":"404","description":"Not Found"},{"code":"500","description":"Internal Server Error"}]}>

<div slot="status-200">

**`200` OK**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `message` | string |

Example response (Words appended), `application/json`.

```json
{
  "status": "success",
  "message": "Live transcription updated successfully"
}
```

</div>

<div slot="status-404">

**`404` Not Found**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `requestId` | string |
| `code` | integer |
| `message` | string |
| `hints` | string[] |

Example response (No media record for that id), `application/json`.

```json
{
  "status": "failed",
  "requestId": "3fcf7e0c-a977-4c37-bae5-a72485206cd0",
  "code": 404,
  "message": "Media does not exist!",
  "hints": [
"The requested operation failed because a resource associated with the request could not be found."
  ]
}
```

</div>

<div slot="status-500">

**`500` Internal Server Error**

Response body, `application/json`.

| Field | Type |
| --- | --- |
| `status` | string |
| `requestId` | string |
| `code` | integer |
| `message` | string |
| `hints` | string[] |

Example response (Internal server error), `application/json`.

```json
{
  "status": "failed",
  "requestId": "ca665625-645e-438a-867d-366a6e3f133a",
  "code": 500,
  "message": "Something went wrong. Please try again later.",
  "hints": [
"Something went wrong. Please try again later."
  ]
}
```

</div>

</ResponsePanel>

</div>

## Related pages

- [API reference](/api/) for the base URL, authentication, and the error format.
- [Authenticate with the Speak AI API using access tokens](/api/authentication/)
- [Upload audio and video to Speak AI and read insights](/api/media/)
- [Analyze text notes with the Speak AI text endpoints](/api/text/)
- [Export Speak AI transcripts and insights to a file](/api/exports/)

Get an API key on the [Speak AI developer page](https://app.speakai.co/developers?utm_source=docs&utm_medium=referral&utm_campaign=api-reference&utm_content=api-live-transcription).

Source: https://docs.speakai.co/api/live-transcription/index.mdx
