openapi: 3.0.1 info: title: Pulse ASR API description: 'API for speech-to-text conversion using the Pulse ASR model. Upload audio files and receive transcribed text using the Pulse model. ' version: 1.0.0 servers: - url: https://api.smallest.ai description: Waves API server x-fern-server-name: waves paths: /waves/v1/pulse/get_text: post: tags: - Speech to Text summary: Convert speech to text description: | 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 ``` 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. **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. operationId: speechToText security: - BearerAuth: [] requestBody: required: true content: application/octet-stream: schema: type: string format: binary description: Raw audio bytes. Content-Type header should specify the audio format (e.g., audio/wav, audio/mp3). All parameters are passed as query parameters. application/json: schema: type: object properties: url: type: string format: uri description: URL to the audio file to transcribe. Must be publicly accessible example: https://example.com/audio.mp3 required: - url example: url: https://example.com/audio.mp3 parameters: - name: language in: query required: false schema: type: string enum: - 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 default: multi-eu description: | Language of the audio file. Set explicitly to the known language for best accuracy. **26 single-language codes** on this endpoint: `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`. **Regional auto-detect aggregators** for unknown audio: - `multi-eu` (default) — auto-detects across all 21 European codes above plus `en`. - `multi-asian` — auto-detects across `zh`, `ko`, `ja`, `en`. - `multi-indic`: auto-detects across `en`, `hi`, `gu`, `mr`, `bn`, `or`. India region only. Omitting `language` routes to `multi-eu`. See the [Pulse model card](/models/model-cards/speech-to-text/pulse) for the full table. - name: encoding in: query required: false schema: type: string enum: - linear16 - linear32 - alaw - mulaw - opus - ogg_opus description: | Audio encoding of the bytes you upload. Mirrors the `encoding` parameter on the realtime WS endpoint. - `linear16`, `linear32` — raw PCM (16-bit and 32-bit) - `alaw`, `mulaw` — 8 kHz telephony codecs - `opus`, `ogg_opus` — Opus compressed audio (raw and Ogg container) When omitted, the server detects the format from the file's container header (works for `.wav`, `.mp3`, `.flac`, `.ogg`, `.m4a`, `.webm`). - name: webhook_url in: query required: false schema: type: string format: uri description: URL to the webhook to receive the transcription results example: https://example.com/webhook - name: webhook_extra in: query required: false schema: type: string description: 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" example: custom_key:custom_value,custom_key2:custom_value2 - name: word_timestamps in: query required: false schema: type: boolean default: false description: Whether to include word and utterance level timestamps in the response - name: diarize in: query required: false schema: type: boolean default: false description: Whether to perform speaker diarization - name: gender_detection in: query required: false schema: type: string enum: - 'true' - 'false' default: 'false' description: Whether to predict the gender of the speaker - name: emotion_detection in: query required: false schema: type: string enum: - 'true' - 'false' default: 'false' description: Whether to predict speaker emotions - name: format in: query required: false schema: type: string enum: - 'true' - 'false' default: 'true' description: 'Master formatting switch for the transcript. When `false`, forces `punctuate=false`, `capitalize=false`, and also disables Inverse Text Normalization (ITN) so it cannot silently reintroduce punctuation or casing. When `true`, the `punctuate` and `capitalize` params take effect independently. Leave `format=true` and use those two to fine-tune. ' - name: punctuate in: query required: false schema: type: string enum: - 'true' - 'false' default: 'true' description: 'When `false`, strips end-of-sentence punctuation (`.`, `,`, `?`, `!`) from the transcript, `words[].word`, and `utterances[].transcript`. Does not affect casing — use `capitalize` for that. Overridden to `false` when `format=false`. ' - name: capitalize in: query required: false schema: type: string enum: - 'true' - 'false' default: 'true' description: 'When `false`, lowercases the entire transcript output (transcript, `words[].word`, and `utterances[].transcript`). Does not affect punctuation — use `punctuate` for that. Overridden to `false` when `format=false`. ' responses: '200': description: Speech transcribed successfully content: application/json: schema: type: object properties: status: type: string description: Status of the transcription request example: success transcription: type: string description: The transcribed text from the audio file example: Hello world. audio_length: type: number description: Duration of the audio file in seconds example: 1.7 words: type: array description: Word-level timestamps in seconds. items: type: object properties: start: type: number example: 0.0 end: type: number example: 0.5 speaker: type: string description: Speaker if diarization is enabled example: speaker_0 word: type: string example: Hello utterances: type: array description: List of utterances with start and end times items: type: object properties: text: type: string example: Hello world. start: type: number example: 0.0 end: type: number example: 0.9 speaker: type: string description: Speaker if diarization is enabled example: speaker_0 gender: type: string description: Predicted gender of the speaker if requested example: male enum: - male - female emotions: type: object description: Predicted emotions of the speaker if requested properties: happiness: type: number format: float example: 0.8 sadness: type: number format: float example: 0.15 disgust: type: number format: float example: 0.02 fear: type: number format: float example: 0.03 anger: type: number format: float example: 0.05 metadata: type: object description: Metadata about the transcription properties: filename: type: string description: Name of the audio file example: audio.mp3 duration: type: number description: Duration of the audio file in minutes example: 1.7 fileSize: type: number description: Size of the audio file in bytes example: 1000000 example: status: success transcription: Hello world. words: - start: 0.0 end: 0.5 speaker: speaker_0 word: Hello - start: 0.6 end: 0.9 speaker: speaker_0 word: world. utterances: - text: Hello world. start: 0.0 end: 0.9 speaker: speaker_0 gender: male emotions: happiness: 0.8 sadness: 0.15 disgust: 0.02 fear: 0.03 anger: 0.05 metadata: filename: audio.mp3 duration: 1.7 fileSize: 1000000 '400': description: | 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). content: application/json: schema: $ref: '#/components/schemas/PulseSttErrorResponse' examples: invalid_format: summary: Invalid file format value: errors: 'Invalid file format. Supported formats: audio/*' status: error message: Error handling audio data audio_too_large: summary: Oversized upload (>250 MB) value: errors: Audio data too large status: error message: Error handling audio data missing_url: summary: Missing or invalid `url` field in JSON body value: errors: "Invalid JSON data: missing or invalid 'url' field" status: error message: Error handling audio data language_not_enabled: summary: Language not enabled in this region value: status: error error_code: LANGUAGE_NOT_ENABLED_IN_REGION message: "Language 'multi-asian' has not been enabled in this region. Please contact support to request access." language: multi-asian region: ap-south-1 '401': description: | 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}` content: application/json: schema: oneOf: - $ref: '#/components/schemas/PulseSttAuthMissingResponse' - $ref: '#/components/schemas/PulseSttErrorResponseLegacy' examples: no_auth_header: summary: No `Authorization` header value: message: 'Unauthorized: No tokens provided' invalid_key: summary: Invalid Bearer key value: error: unauthorized '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/PulseSttErrorResponseLegacy' example: error: Internal server error components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT description: 'API key authentication using Bearer token format. Include your API key in the Authorization header as: `Bearer YOUR_API_KEY` ' schemas: PulseSttErrorResponse: type: object description: | Canonical error shape for 400-class responses from the Pulse STT REST endpoint. Live-probed against prod 2026-06-16. Two variants share the same envelope: - Generic validation: `{errors, status, message}` (e.g. invalid params, malformed body, oversized upload). - Discriminated: `{status, error_code, message, language?, region?}` for known classes such as `LANGUAGE_NOT_ENABLED_IN_REGION`. Clients should treat `errors` and `error_code` as mutually exclusive — exactly one will be present. `status` and `message` are always set. Note: the platform's field naming is inconsistent — `errors` (plural) on 400-class responses vs `error` (singular) on some 401 responses. See `PulseSttErrorResponseLegacy` for the singular-`error` shape. properties: status: type: string enum: [error] description: Always `"error"`. message: type: string description: Generic error category (e.g. "Error handling audio data"). errors: type: string description: Human-readable error message (validation variant). error_code: type: string description: Machine-readable error code (discriminated variant, e.g. `LANGUAGE_NOT_ENABLED_IN_REGION`). language: type: string description: Echo of the requested language (present on `LANGUAGE_NOT_ENABLED_IN_REGION`). region: type: string description: Region the request hit (present on `LANGUAGE_NOT_ENABLED_IN_REGION`). required: - status - message PulseSttErrorResponseLegacy: type: object description: | Legacy singular-`error` shape returned by 401 bad-key and 500 responses. Distinct from `PulseSttErrorResponse` (the plural `errors` shape used by 400-class responses) — the platform is inconsistent across error paths. Live-probed 2026-06-16; see verifications/ log. properties: error: type: string description: Error message describing what went wrong. required: - error PulseSttAuthMissingResponse: type: object description: | Shape returned when the request omits the `Authorization` header entirely. Distinct from invalid-token (which uses `PulseSttErrorResponseLegacy`). Live-probed 2026-06-16. properties: message: type: string description: Human-readable explanation of why auth failed. required: - message