---
title: "Convert speech to text"
method: POST
path: "/waves/v1/pulse/get_text"
tags: ["Speech to Text"]
---

# Convert speech to text

`POST /waves/v1/pulse/get_text`

Transcribe an audio file to text using the Pulse model. The fastest way to get a transcript when you already have a recording — pass either the raw bytes or a URL.

## When to use this

Use this endpoint when you have a complete audio file (call recording, voicemail, podcast episode) and want the transcript back in one response. For live transcription as audio arrives, use the realtime WebSocket endpoint (`WSS /waves/v1/pulse/get_text`) instead.

## Input methods

Send the audio in one of two ways:

1. **Raw bytes** — `Content-Type: application/octet-stream` with the audio in the body. All knobs (`language`, `word_timestamps`, etc.) are query parameters.
2. **URL** — `Content-Type: application/json` with `{"url": "..."}` in the body. Useful when the audio already lives in object storage. Same query parameters apply.

Pulse autodetects the language across 30+ supported locales. Pass `language` explicitly when you already know it — detection is fast but skipping it is faster.

## Examples

**cURL** (raw bytes)
```bash
curl -X POST "https://api.smallest.ai/waves/v1/pulse/get_text?language=en&word_timestamps=true" \
  -H "Authorization: Bearer $SMALLEST_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@./call.wav"
```

**cURL** (URL)
```bash
curl -X POST "https://api.smallest.ai/waves/v1/pulse/get_text?language=en" \
  -H "Authorization: Bearer $SMALLEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-bucket.s3.amazonaws.com/call.wav"}'
```

**Python** (`pip install smallestai>=5.3.0`)
```python
from smallestai import SmallestAI

client = SmallestAI(api_key="YOUR_API_KEY")
with open("./call.wav", "rb") as f:
    result = client.waves.speech_to_text.transcribe(
        model="pulse",
        request=f.read(),
        language="en",
        word_timestamps=True,
        diarize=True,
    )
print(result.status)         # "success"
print(result.transcription)  # the transcript string
```

<Note>
On `smallestai<5.3.0`, this method was `client.waves.transcribe_pulse(request=..., language=...)` and had no `model` parameter. See the [5.3.0 migration notes](/atoms/changelog) for the full rename table.
</Note>

**JavaScript / TypeScript** (using `fetch`)
```typescript
import { readFileSync } from "node:fs";

const audio = readFileSync("./call.wav");
const params = new URLSearchParams({ language: "en", word_timestamps: "true", diarize: "true" });

const res = await fetch(`https://api.smallest.ai/waves/v1/pulse/get_text?${params}`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMALLEST_API_KEY}`,
    "Content-Type": "application/octet-stream",
  },
  body: audio,
});
const result = await res.json();
console.log(result.transcription);
```

## Common gotchas

- **Max file size is 250 MB.** Larger files return HTTP `400` with `{errors: "Audio data too large", status: "error", message: "Error handling audio data"}`. Compress to mono 16 kHz PCM if you're close to the limit; quality is unaffected.
- **Formatting flags (`format`, `punctuate`, `capitalize`)** are accepted at the wire level and exposed in the Python SDK as of `smallestai>=4.4.0`. Today they currently return the same transcript regardless of value — pass them in your integration so it works as the behavior changes.
- **Webhook-driven flow**: pass `webhook_url` to receive the transcript asynchronously. The endpoint returns immediately; the transcript hits your webhook when ready. Useful for long files where you don't want to hold an HTTP connection open.
- **Speaker diarization** (`diarize=true`) adds latency. Skip it if you only need the words.
- **JavaScript / TypeScript**: the official `smallestai` npm package predates the Pulse model, so call this endpoint with `fetch` or `axios` as shown above.

## Query parameters

- `language` 'en' | 'hi' | 'de' | 'es' | 'ru' | 'it' | 'fr' | 'nl' | 'pt' | 'uk' | 'pl' | 'cs' | 'sk' | 'lv' | 'et' | 'ro' | 'fi' | 'sv' | 'bg' | 'hu' | 'da' | 'lt' | 'mt' | 'zh' | 'ja' | 'ko' | 'multi-eu' | 'multi-asian' | 'multi-indic'
- `encoding` 'linear16' | 'linear32' | 'alaw' | 'mulaw' | 'opus' | 'ogg_opus'
- `webhook_url` string, uri — URL to the webhook to receive the transcription results
- `webhook_extra` string — Extra parameters to pass to the transcription. These will be added to the request body as a JSON object. Add comma separated key-value pairs to the query string. eg "custom_key:custom_value,custom_key2:custom_value2"
- `word_timestamps` boolean
- `diarize` boolean
- `gender_detection` 'true' | 'false'
- `emotion_detection` 'true' | 'false'
- `format` 'true' | 'false'
- `punctuate` 'true' | 'false'
- `capitalize` 'true' | 'false'

## Request body

- object
  - `url` string, uri, required — URL to the audio file to transcribe. Must be publicly accessible

## Response `200`

Speech transcribed successfully

- object
  - `status` string — Status of the transcription request
  - `transcription` string — The transcribed text from the audio file
  - `audio_length` number — Duration of the audio file in seconds
  - `words` object[] — Per-word timestamps in seconds. **Empty unless the request sets `word_timestamps=true`.** Each entry carries `word`, `start`, `end`, `confidence` (0.0–1.0), and `speaker` when `diarize=true` is also set.
    - `start` number
    - `end` number
    - `speaker` string — Speaker label when `diarize=true` is set on the request. Omitted otherwise.
    - `word` string
  - `utterances` object[] — Sentence-level segments with start and end times. **Empty unless the request sets `word_timestamps=true`** (the same flag turns on both `words[]` and `utterances[]`).
    - `text` string
    - `start` number
    - `end` number
    - `speaker` string — Speaker if diarization is enabled
  - `gender` 'male' | 'female' — Predicted gender of the speaker if requested
  - `emotions` object — Predicted emotions of the speaker if requested
    - `happiness` number, float
    - `sadness` number, float
    - `disgust` number, float
    - `fear` number, float
    - `anger` number, float
  - `metadata` object — Metadata about the transcription
    - `filename` string — Name of the audio file
    - `duration` number — Duration of the audio file in minutes
    - `fileSize` number — Size of the audio file in bytes

## Other responses

- `400` — Bad request — validation error, malformed body, unreachable URL, or audio data too large. Oversized uploads (>250 MB) return HTTP 400 with `errors: "Audio data too large"` (not HTTP 413; the legacy 413 documentation was wrong).
- `401` — Unauthorized — missing or invalid Bearer token. Two distinct shapes depending on what is wrong with auth: - Missing `Authorization` header → `{message: string}` - Invalid Bearer token → `{error: string}`
- `500` — Internal server error

---

[API](https://skmtc.net/smallest-inc/apis/pulse-asr-api.md) · [All operations](https://skmtc.net/smallest-inc/apis/pulse-asr-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/smallest-inc/pulse-asr-api/versions/a683acc663f9/schema)
