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

# Get a Zoom transcript via API

> Zoom API get transcript: send a bot to the meeting with one POST, then read the live transcription over REST or WebSocket.

Send a bot to the meeting with **one POST**, then read the transcript **while the call is still
running**. The bot joins Zoom like any participant — no plugins, no host configuration — and streams
back a speaker-attributed transcript you either poll over REST or subscribe to over WebSocket.

<Tip>
  **Hosted, no install:** [connect your agent](https://vexa.ai/connect?utm_source=docs\&utm_medium=tip\&utm_campaign=how-to-zoom-transcript-api) (Claude Code, Codex, Cursor) or [get an API key](https://vexa.ai/start?utm_source=docs\&utm_medium=tip\&utm_campaign=how-to-zoom-transcript-api) (free credit, no card required). Self-hosting: [Deployment](/deployment).
</Tip>

## 1. Send the bot

```bash theme={null}
curl -X POST "$API_BASE/bots" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"platform":"zoom","native_meeting_id":"81234567890","bot_name":"Vexa"}'
```

`native_meeting_id` is the meeting id **inside** the join URL, not the whole URL. Have only the
URL? Send `meeting_url` alone instead of `platform` + `native_meeting_id` — the API parses it to
extract both, and, for a Zoom link that embeds one, the passcode. A URL that is not a recognizable
meeting link is refused with a `422` naming the missing `native_meeting_id`.

`$API_BASE` is `https://api.cloud.vexa.ai` hosted, or `http://localhost:18056` self-hosted.
Optional on the spawn: `language` (ISO code; omit for per-window auto-detection) and `task`
(`transcribe` default, or `translate`).

## 2. Read the transcript live

Segments stream in as the meeting runs. Poll:

```bash theme={null}
curl -H "X-API-Key: $API_KEY" \
  "$API_BASE/transcripts/zoom/81234567890"
```

```json theme={null}
{
  "segments": [
    { "speaker": "Jane Liu", "text": "Let's lock the renewal pricing by July 1.",
      "start": 12.4, "end": 15.1, "language": "en", "completed": true, "confidence": 0.93 }
  ]
}
```

Live drafts arrive as `completed: false` and are replaced by `completed: true` confirmations. For
per-segment push instead of polling, subscribe on the gateway's `/ws`:

```json theme={null}
{ "action": "subscribe",
  "meetings": [ { "platform": "zoom", "native_id": "81234567890" } ] }
```

## Zoom specifics

* **Web client only.** In 0.12.x the bot joins Zoom through the **web client**. The native SDK /
  OBF-token path is not carried — see [Roadmap → Status](/roadmap/status).
* **Passcodes.** The field is spelled **`passcode`**. `password`, `meeting_password` and the other
  near-misses are refused with a `422` naming the field to use, rather than accepted and dropped. A
  passcode already in the URL's query wins over a separate `passcode` field.
* **Language auto-detection.** Zoom rides the mixed-audio lane, where a low-confidence detection
  discards the window rather than guessing; those windows carry `language: null`. Pin `language` on
  the spawn to avoid it.
* **Leaving on its own.** An active bot leaves after 10 minutes with no remote microphone audio and
  finishes as `completed(left_alone)`. Widen it per meeting with
  `automatic_leave.max_time_left_alone`.

## Stop the bot

```bash theme={null}
curl -X DELETE "$API_BASE/bots/zoom/81234567890" -H "X-API-Key: $API_KEY"
```

## See also

* [Send a bot and get a transcript](/how-to/send-a-bot) — the full walkthrough, all platforms
* [Meetings API](/api/meetings) — every parameter, status, and response shape
* [Troubleshooting](/troubleshooting) — the bot joined but there is no transcript
