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

# audio formats

> request wav, opus, pcm, mulaw, alaw, or mp3 audio from silk.

silk supports five explicit `audio_format` values on `muga`, `mulberry` and
`mulberry-1.6`: `opus`, `pcm`, `mulaw`, `alaw`, and `mp3`.

the field is optional. omit it entirely to preserve the original response:

* `post /v1/tts` returns a 24 khz mono wav file.
* `post /v1/tts/json` returns the same wav bytes in `audio_base64`.
* websocket sessions stream raw 24 khz mono signed 16-bit little-endian pcm.

<Warning>
  do not send `"audio_format": null`. explicit `null` is invalid and returns
  `400 unsupported_audio_format`. omit the field when you want the default.
</Warning>

## supported values

| value   | output                                          | content type                                      | common extension |
| ------- | ----------------------------------------------- | ------------------------------------------------- | ---------------- |
| omitted | wav containing 24 khz mono signed 16-bit pcm    | `audio/wav`                                       | `.wav`           |
| `opus`  | opus in an ogg container                        | `audio/ogg; codecs=opus`                          | `.ogg`           |
| `pcm`   | raw 24 khz mono signed 16-bit little-endian pcm | `audio/pcm; rate=24000; channels=1; format=s16le` | `.pcm`           |
| `mulaw` | raw 8 khz mono g.711 mu-law                     | `audio/x-mulaw; rate=8000; channels=1`            | `.mulaw`         |
| `alaw`  | raw 8 khz mono g.711 a-law                      | `audio/x-alaw; rate=8000; channels=1`             | `.alaw`          |
| `mp3`   | mp3 audio                                       | `audio/mpeg`                                      | `.mp3`           |

`wav` and `ogg` are not accepted values. omit `audio_format` for wav, and use
`opus` for opus audio in an ogg container.

## binary http response

add `audio_format` to the json request body. the response body contains the
audio bytes directly, and the response `content-type` identifies the format.

```bash curl theme={null}
api_key='rk_live_•••••••••'

curl --request post https://silk-api.rumik.ai/v1/tts \
  --header "authorization: bearer ${api_key}" \
  --header "content-type: application/json" \
  --data '{"model":"muga","text":"[happy] hello from silk.","audio_format":"opus"}' \
  --output speech.ogg
```

change only the `audio_format` value and output extension to request another
format. leave the field out to receive `speech.wav` with the original behavior.

## json base64 response

the json endpoint keeps the response object and replaces `audio_base64` with
the requested audio bytes encoded as base64.

```python python theme={null}
import base64
import requests

api_key = "rk_live_•••••••••"
response = requests.post(
    "https://silk-api.rumik.ai/v1/tts/json",
    headers={"authorization": f"bearer {api_key}"},
    json={
        "model": "mulberry",
        "text": "hello from silk.",
        "description": "a warm conversational voice",
        "audio_format": "mp3",
    },
    timeout=90,
)
response.raise_for_status()
result = response.json()

with open("speech.mp3", "wb") as output:
    output.write(base64.b64decode(result["audio_base64"]))
```

the response also includes `request_id`, `audio_duration_ms`, `credits_used`,
and `usage_cost_nanos`. the requested format does not change billing.

## websocket streaming

set `audio_format` when minting the one-shot session. do not add it to later
synthesis frames: the gateway stores the negotiated format in the session.

```python python theme={null}
import asyncio
import json
import requests
import websockets

api_key = "rk_live_•••••••••"

async def main():
    session_response = requests.post(
        "https://silk-api.rumik.ai/v1/tts/ws-connect",
        headers={"authorization": f"bearer {api_key}"},
        json={
            "model": "muga",
            "text": "stream this as opus.",
            "audio_format": "opus",
        },
        timeout=30,
    )
    session_response.raise_for_status()
    session = session_response.json()

    chunks = bytearray()
    async with websockets.connect(
        f'{session["ws_url"]}?token={session["token"]}'
    ) as websocket:
        await websocket.send(json.dumps({"text": "stream this as opus."}))
        async for message in websocket:
            if isinstance(message, bytes):
                chunks.extend(message)
            elif json.loads(message).get("type") == "done":
                break

    with open("speech.ogg", "wb") as output:
        output.write(chunks)

asyncio.run(main())
```

always connect to the returned `ws_url`. the negotiated format applies at the
silk gateway. connecting to any other endpoint is outside this contract.

for `opus` and `mp3`, concatenate binary websocket messages in order before
decoding the complete stream. individual messages are not guaranteed to be
standalone audio files.

## billing and stored audio

payg tts remains based on the exact submitted text character count. choosing a
different audio format does not add a surcharge and does not make billing depend
on encoded byte length or generated duration.

silk stores its canonical wav source for usage and audit workflows regardless
of the format returned to the client.
