openapi: 3.0.1
info:
title: Lightning V3.1 API
description: 'API for the Lightning V3.1 text-to-speech model.
Features improved speech synthesis with support for English and Hindi languages.
'
version: 3.1.0
servers:
- url: https://api.smallest.ai
description: Waves API server
x-fern-server-name: waves
paths:
/waves/v1/lightning-v3.1/get_speech:
post:
tags:
- Lightning V3.1
operationId: synthesizeLightningV31Speech
summary: Generate speech from text (Lightning V3.1)
description: |
**Endpoint scheduled for retirement.** This URL will stop accepting requests **60 days from the Lightning v3.1 Pro launch (2026-05-15)** — i.e. on **2026-07-14**. The Lightning v3.1 model itself is current and stays. Migrate to [`POST /waves/v1/tts`](/waves/api-reference/api-reference/text-to-speech/synthesize-speech) and select Lightning v3.1 via the `model` body field (default).
Synthesize speech from text in a single request. The simplest way to get audio when you have the full text up front — pass `text` + `voice_id`, get back binary audio.
## When to use this
- **Use this** for short utterances you can render before playback (notifications, prompts, batch jobs, audio file generation).
- **Use the SSE streaming endpoint** when you want playback to start before the full audio is ready (long passages, latency-sensitive apps).
- **Use the WebSocket endpoint** when text arrives incrementally (LLM token streams, live captioning).
## Key features
- 44 kHz natural, expressive synthesis
- Cloned voice IDs (`voice_*`) work — same param as catalog voices
- 12 documented languages — see the model card for the full list
- Output formats: `pcm`, `mp3`, `wav`, `ulaw`, `alaw`
- Sample rates: 8 kHz – 44.1 kHz
- Speed: 0.5× – 2×
- Per-call pronunciation dictionaries via `pronunciation_dicts`
## Examples
**cURL**
```bash
curl -X POST "https://api.smallest.ai/waves/v1/lightning-v3.1/get_speech" \
-H "Authorization: Bearer $SMALLEST_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: audio/wav" \
-d '{
"text": "Hello from Lightning v3.1.",
"voice_id": "magnus",
"sample_rate": 24000,
"output_format": "wav"
}' --output speech.wav
```
**Python** (`pip install smallestai>=4.4.0`)
```python
from smallestai import SmallestAI
client = SmallestAI(api_key="YOUR_API_KEY")
with open("speech.wav", "wb") as f:
for chunk in client.waves.synthesize_lightning_v3_1(
text="Hello from Lightning v3.1.",
voice_id="magnus",
sample_rate=24000,
output_format="wav",
# Optional: cloned voice support
# voice_id="voice_FlPKRWI7DX",
# Optional: pin pronunciations for specific words
# pronunciation_dicts=[""],
):
f.write(chunk)
```
**JavaScript / TypeScript** (using `fetch`)
```typescript
const res = await fetch("https://api.smallest.ai/waves/v1/lightning-v3.1/get_speech", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMALLEST_API_KEY}`,
"Content-Type": "application/json",
Accept: "audio/wav",
},
body: JSON.stringify({
text: "Hello from Lightning v3.1.",
voice_id: "magnus",
sample_rate: 24000,
output_format: "wav",
}),
});
const audio = Buffer.from(await res.arrayBuffer());
require("node:fs").writeFileSync("speech.wav", audio);
```
## Common gotchas
- **Set `Accept: audio/wav`.** Omitting it can return an empty or unplayable response.
- **Cloned voices** (`voice_*` from `add_voice`) work on this endpoint and support `pronunciation_dicts`.
- **`pronunciation_dicts` validates IDs at request time.** Passing an unknown ID returns `Invalid input data` — create the dict first via the pronunciation-dicts endpoint and save the returned `id`.
- **Pronunciation matching is case-sensitive.** Add both `Synopsis` and `synopsis` if your text uses both casings.
- **44.1 kHz output** is supported but most playback environments are happy with 24 kHz — drop the sample rate if bandwidth matters.
- **JavaScript / TypeScript**: the official `smallestai` npm package predates Lightning v3.1, so call this endpoint with `fetch` or `axios` as shown above.
parameters:
- name: Accept
in: header
required: true
schema:
type: string
enum:
- audio/wav
default: audio/wav
description: Must be `audio/wav` to receive binary audio. Required for proper playback.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LightningV31Request'
example:
text: Hey i am your a text to speech model
voice_id: daniel
output_format: mp3
sample_rate: 44100
speed: 1.0
responses:
'200':
description: Synthesized speech retrieved successfully.
headers:
X-Session-Id:
schema:
type: string
description: Internal session identifier (system-generated UUID).
X-Request-Id:
schema:
type: string
description: Internal request identifier (system-generated UUID).
X-External-Session-Id:
schema:
type: string
description: Echoed client-provided session_id (empty if not provided).
X-External-Request-Id:
schema:
type: string
description: Echoed client-provided request_id (empty if not provided).
content:
audio/wav:
schema:
type: string
format: binary
description: A PCM int16 WAV file at the specified sample rate.
'400':
description: Bad request.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error type.
message:
type: string
description: Error message.
example:
error: InvalidRequest
message: The 'text' field is required.
'401':
description: Unauthorized.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error type.
message:
type: string
description: Error message.
example:
error: Unauthorized
message: Bearer token is missing or invalid.
'500':
description: Server error occurred.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error type.
message:
type: string
description: Error message.
example:
error: InternalServerError
message: An unexpected error occurred.
/waves/v1/lightning-v3.1/stream:
post:
tags:
- Lightning V3.1
operationId: streamLightningV31Speech
summary: Stream speech from text (Lightning V3.1)
description: |
**Endpoint scheduled for retirement.** This URL will stop accepting requests **60 days from the Lightning v3.1 Pro launch (2026-05-15)** — i.e. on **2026-07-14**. The Lightning v3.1 model itself is current and stays. Migrate to [`POST /waves/v1/tts/live`](/waves/api-reference/api-reference/text-to-speech/synthesize-speech-sse) and select Lightning v3.1 via the `model` body field (default).
Synthesize speech and stream the audio back over Server-Sent Events. The body and parameters are identical to the sync `/get_speech` endpoint — the difference is the response is a stream of base64-encoded PCM chunks instead of one binary blob.
## When to use this
- **Use this** when you want playback to start before synthesis is complete — long passages, latency-sensitive UI, live narration.
- **Use sync `/get_speech`** when total latency doesn't matter and you'd rather get one buffer.
- **Use the WebSocket endpoint** when the *text* arrives incrementally (LLM token stream). SSE assumes you have the full text up front.
## How it works
1. POST your text + voice settings — same payload as `/get_speech`.
2. The response is `Content-Type: text/event-stream`. Each chunk frame is `event: audio\n` followed by `data: {"audio": ""}\n\n`.
3. Decode each chunk's `audio` field with base64 and feed the PCM bytes to your audio pipeline (browser `MediaSource`, ffmpeg pipe, raw PCM player, etc.).
4. A final `data: {"done": true}\n\n` frame marks end of stream.
## Examples
**cURL**
```bash
curl -N -X POST "https://api.smallest.ai/waves/v1/lightning-v3.1/stream" \
-H "Authorization: Bearer $SMALLEST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Streaming this paragraph chunk by chunk so playback can start sooner.",
"voice_id": "magnus",
"sample_rate": 24000,
"output_format": "pcm"
}'
```
**Python** (`pip install smallestai>=4.4.0`)
```python
import base64
from smallestai import SmallestAI
client = SmallestAI(api_key="YOUR_API_KEY")
with open("stream.pcm", "wb") as f:
for chunk in client.waves.synthesize_sse_lightning_v3_1(
text="Streaming this paragraph chunk by chunk so playback can start sooner.",
voice_id="magnus",
sample_rate=24000,
output_format="pcm",
):
# Each chunk is `{"audio": ""}`.
# Decode and pipe to your audio pipeline.
if chunk.get("audio"):
f.write(base64.b64decode(chunk["audio"]))
```
**JavaScript / TypeScript** (using `fetch` + a reader)
```typescript
const res = await fetch("https://api.smallest.ai/waves/v1/lightning-v3.1/stream", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMALLEST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "Streaming this paragraph chunk by chunk so playback can start sooner.",
voice_id: "magnus",
sample_rate: 24000,
output_format: "pcm",
}),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
let buf = "";
let finished = false;
while (!finished) {
const { value, done } = await reader.read();
if (done) break;
buf += decoder.decode(value);
const events = buf.split("\n\n");
buf = events.pop() ?? "";
for (const ev of events) {
// SSE frames are "event: audio\ndata: {json}" or just "data: {json}".
// We only care about the data line — pull it out and parse.
const dataLine = ev.split("\n").find((l) => l.startsWith("data:"));
if (!dataLine) continue;
const payload = JSON.parse(dataLine.slice(5).trim());
if (payload.done) { finished = true; break; }
if (payload.audio) {
const pcm = Buffer.from(payload.audio, "base64");
// … hand pcm to your audio pipeline
}
}
}
```
## Common gotchas
- **Use a streaming-friendly client.** `curl -N`, Python `iter_lines`, or a `fetch` `ReadableStream` reader. Buffering clients will hide the latency win.
- **Audio is base64 inside the event payload**, not the raw event bytes. Decode the `data.audio` field per event.
- **`output_format=pcm`** gives the lowest overhead for streaming playback. `wav`/`mp3` work but add per-chunk framing bytes.
- **First-chunk latency** depends on model warm-up + network distance. Use `output_format=pcm` and a streaming-friendly client to minimize what you can control.
- **JavaScript / TypeScript**: the official `smallestai` npm package predates Lightning v3.1, so call this endpoint with `fetch` as shown above.
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LightningV31Request'
responses:
'200':
description: Synthesized speech retrieved successfully.
headers:
X-Session-Id:
schema:
type: string
description: Internal session identifier (system-generated UUID).
X-Request-Id:
schema:
type: string
description: Internal request identifier (system-generated UUID).
X-External-Session-Id:
schema:
type: string
description: Echoed client-provided session_id (empty if not provided).
X-External-Request-Id:
schema:
type: string
description: Echoed client-provided request_id (empty if not provided).
content:
text/event-stream:
example:
data: 'event: chunk
data:
done: false
'
'400':
description: Bad request.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error type.
message:
type: string
description: Error message.
example:
error: InvalidRequest
message: The 'text' field is required.
'401':
description: Unauthorized.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error type.
message:
type: string
description: Error message.
example:
error: Unauthorized
message: Bearer token is missing or invalid.
'500':
description: Server error occurred.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error type.
message:
type: string
description: Error message.
example:
error: InternalServerError
message: An unexpected error occurred.
components:
schemas:
LightningV31Request:
type: object
required:
- text
- voice_id
properties:
text:
type: string
description: The text to convert to speech.
default: Hey i am your a text to speech model
voice_id:
type: string
description: The voice identifier to use for speech generation.
default: daniel
model:
type: string
description: |
TTS model to route the request to.
- `lightning_v3.1` (default) — standard Lightning v3.1 pool.
- `lightning_v3.1_pro` — Lightning v3.1 Pro pool with a curated
voice catalog. See the
[Pro model card](/waves/model-cards/text-to-speech/lightning-v-3-1-pro).
New integrations should use the unified
`/waves/v1/tts` route instead of this endpoint, but the `model`
field is supported here for backwards-compatible Pro opt-in.
enum:
- lightning_v3.1
- lightning_v3.1_pro
default: lightning_v3.1
sample_rate:
type: integer
description: The sample rate for the generated audio.
enum:
- 8000
- 16000
- 24000
- 44100
default: 44100
speed:
type: number
description: The speed of the generated speech.
minimum: 0.5
maximum: 2
default: 1.0
language:
type: string
description: |
Language code for synthesis. Influences pronunciation, number/date
normalization, and phoneme selection.
- **Indian:** `en`, `hi`, `mr` (Marathi), `kn` (Kannada), `ta` (Tamil),
`bn` (Bengali), `gu` (Gujarati), `te` (Telugu), `ml` (Malayalam),
`pa` (Punjabi), `or` (Odia)
- **European:** `es` (Spanish)
default: en
enum:
- en
- hi
- mr
- kn
- ta
- bn
- gu
- te
- ml
- pa
- or
- es
number_pronunciation_language:
type: string
description: |
Optional. Sets the language used to read out numeric content —
numbers, currency amounts, times, and the numeric parts of dates
and years — independently of the synthesis voice. Ordinary words
are not translated.
- If you **omit `language`**, this value also becomes the
synthesis language: model selection and voice routing follow it.
- If you **set `language` explicitly**, `language` always wins for
synthesis and `number_pronunciation_language` only changes how
numeric content is normalized. It works both ways — read numbers
in Hindi under an English voice, or in English under a Hindi
voice (tuned for Indian, often mixed-script, use cases).
- Omit this field to keep the existing behaviour — normalization
follows `language`.
Note: only numeric tokens are re-spoken; the words around them
stay in the text language. On a cross-language request names may
also render in the target script (e.g. "Smith" → "स्मिथ"), which
is generally the desired reading for native-language voices.
Accepts the same language codes as `language`.
enum:
- en
- hi
- mr
- kn
- ta
- bn
- gu
- te
- ml
- pa
- or
- es
output_format:
type: string
description: 'Format of the returned audio. `pcm` is the lowest-latency option
but requires a decoder to play; `mp3` and `wav` are directly
playable in browsers and most media players. The server default
is `pcm` when the field is omitted — the API playground uses
`mp3` so the generated audio is directly playable.
'
default: pcm
example: mp3
enum:
- mp3
- pcm
- wav
- ulaw
- alaw
pronunciation_dicts:
type: array
items:
type: string
description: The ID of the pronunciation dictionary to use for speech generation.
description: The IDs of the pronunciation dictionaries to use for speech generation.
session_id:
type: string
description: Optional client-provided session identifier for correlation. Only alphanumeric characters, hyphens, underscores, and dots are allowed. Max 128 characters. Echoed back in response headers as `X-External-Session-Id`.
maxLength: 128
pattern: ^[a-zA-Z0-9_\-.]+$
request_id:
type: string
description: Optional client-provided request identifier for correlation. Only alphanumeric characters, hyphens, underscores, and dots are allowed. Max 128 characters. Echoed back in response headers as `X-External-Request-Id`.
maxLength: 128
pattern: ^[a-zA-Z0-9_\-.]+$
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT