Using Soundbox
Custom endpoints
Send generation to a server you already run, such as LocalAI or an OpenAI-compatible speech server.
A custom endpoint sends generation to a server you already run, instead of a model Soundbox downloads and runs itself. Use one when a machine on your network already serves the model (LocalAI, an OpenAI-compatible speech server, a gateway), or when the machine running Soundbox can't download weights.
Each endpoint appears as one model in the pickers. Its id is
endpoint:<id>. Sounds made with it go into the library like any other, and
work in the editor, the studio and over MCP the same way.
Adding one
Go to Settings → Endpoints → Add endpoint. Pick a preset or start blank, then check four things:
| Field | What it is |
|---|---|
| Used for | Sound effects, Music or Speech. This decides which picker the endpoint appears in. |
| URL | The full URL to POST to, path included, e.g. http://192.168.1.20:8080/v1/sound-generation. |
| API key | Optional. Sent as Authorization: Bearer <key>. Once saved it is never shown or returned again. Leave the field blank when editing to keep the saved key. |
| Body template | The JSON request body, with {{variables}} for what Soundbox fills in. |
Press Test before saving. It sends one short request with the form as it stands and reports the length and format of the audio that came back, or the server's error. Nothing is added to the library.
Presets
| Preset | Endpoint | Notes |
|---|---|---|
| LocalAI ACE-Step music | POST /v1/sound-generation |
Sends model_id, caption, lyrics, bpm, keyscale and duration_seconds. LocalAI's ACE-Step example uses model instead. If your server rejects model_id, rename it. |
| LocalAI sound effects | POST /v1/sound-generation |
ElevenLabs-shaped: model_id, text, duration_seconds. |
| OpenAI-compatible speech | POST /v1/audio/speech |
Works with LocalAI, OpenAI-compatible servers and most proxies. Asks for response_format: "wav", so ffmpeg is not needed. List your server's voices in Voices. |
Presets cover servers you run yourself. Any other server, including hosted
APIs, can be added by hand. Servers that expose the same path don't agree on
the body: two /v1/audio/music implementations take prompt and
duration_seconds and input and duration respectively. This is why the
body is a template and not a fixed format.
Where requests go
Soundbox is local-first, and an endpoint is the one setting that can send a prompt somewhere else. If an endpoint's URL is not on this machine or your local network, the form and the model's description say so, and the endpoint is marked Off-network in the list. Prompts, lyrics and any voice clip used with that endpoint are sent to that host.
"Local" is judged from the hostname: localhost, private IPv4 ranges
(10.*, 172.16–31.*, 192.168.*), IPv6 local addresses, names without a
dot (homeserver), and names ending in .local, .lan, .home, .internal
or .home.arpa. A public name that resolves to a LAN address counts as
off-network.
Templates
The template is JSON with placeholders. Where a placeholder sits decides what it becomes:
{
"model": "ace-step-turbo",
"bpm": {{bpm}},
"keyscale": "{{key}}",
"caption": "lofi, {{prompt}}",
"duration_seconds": {{duration}}
}- A bare placeholder (
{{bpm}}) becomes the JSON value: a number,trueorfalse, ornull. - A placeholder that is the whole string (
"{{key}}") also becomes the value, so a template can stay valid JSON in an editor. - A placeholder inside a longer string (
"lofi, {{prompt}}") is inserted as text. - A field whose value comes out
nullis left out of the request. When a prompt names no key,keyscaleis not sent, rather than sent asnull.
Values are JSON-encoded when they are inserted, so a quote or brace in a prompt cannot break the request.
| Variable | Value |
|---|---|
prompt |
The description from the composer. |
negative_prompt |
What to avoid, if the composer has one. |
lyrics |
Lyrics for a vocal track, or null. |
instrumental |
true when there are no lyrics. |
duration, duration_ms |
The requested length in seconds or milliseconds. |
bpm |
A tempo written in the prompt ("90 BPM"), or null. |
key |
A key written in the prompt ("A minor", "Ebm", "F# maj"), normalised to "Eb minor" form, or null. The note letter must be upper case. |
seed, steps, cfg |
Sampler settings, when set. |
text |
The line to speak (speech). |
voice |
The chosen voice, or the first in the endpoint's list (speech). |
voice_ref_b64 |
A cloned voice's reference clip as base64 WAV (speech), or null. |
language |
A language code, if one was chosen (speech). |
An unknown variable is rejected when you save, with the list of valid names.
The composer shows only the controls the template uses. If the template has
no {{seed}}, there is no seed control for that endpoint. If it uses
{{lyrics}}, the lyrics box appears.
What comes back
Soundbox expects the response body to be the audio:
- WAV is decoded directly, detected by its header, whatever the
Content-Typesays. audio/pcmis read as 16-bit mono at the endpoint's PCM sample rate (24 kHz by default), since raw PCM has no header.- Anything else (MP3, FLAC, Opus, AAC) is decoded with ffmpeg, if it is
on your
PATH. If it isn't, the error says so. Install ffmpeg, or ask for WAV in the template if the server offers it.
If a server wraps the audio in JSON, set Response path to where the base64
string is, e.g. data.0.b64_json or audio. A data:audio/...;base64,
prefix is stripped.
Requests time out after 10 minutes. A long music render on a busy GPU can take several minutes, and an early timeout would discard a track the server already made. Cancelling the job aborts the request.
Limits
- An endpoint can't extend, cover or repaint an existing sound, split stems, or convert a voice. Those still need a local model.
- There is no streaming progress. The job shows "Waiting for
" until the response arrives. - Endpoints are per profile. They are stored in that profile's
settings.json, underaudio_endpoints.
API
| Method | Path | Body |
|---|---|---|
GET |
/api/endpoints |
Returns { endpoints, presets, variables }. Keys appear only as api_key_set. |
PUT |
/api/endpoints/:id |
Creates or replaces one endpoint. api_key omitted keeps the saved key, "" clears it. |
DELETE |
/api/endpoints/:id |
Removes it. Sounds made with it stay in the library. |
POST |
/api/endpoints/test |
Same body as PUT, plus optional id (a saved endpoint whose key to use) and prompt. Returns { duration_s, sample_rate, channels }. |
Ids are lower-case letters, digits and hyphens, up to 48 characters.