The API
Every client talks to one HTTP API on the core, http://127.0.0.1:8080 by default. The pages in
this section are generated from contracts/, the source of truth for every request and response
shape, so they cannot describe a route the server does not have. The same contracts produce the
OpenAPI 3.1 document, and a running core serves its own at GET /openapi.json, which describes that core rather than this site's copy of the latest release.
The prose that says why each route behaves as it does is the protocol. Where a page here says what, the protocol says why, and where the two disagree the protocol is right and the other one is a bug.
Who may call what
Speaking is open. POST /speak, the engines and their capabilities, voices and previews, and
OpenAI's POST /v1/audio/speech answer anybody who can reach the port. The worst a stranger can do
with them is make it talk.
Managing is not. Installing, uninstalling, reinstalling, pulling weights, unloading, creating or
deleting a voice, the install jobs and the settings answer callers on this machine, and nobody else
unless management.token is set, in which case Authorization: Bearer <token> is admitted from
anywhere. An install runs pip, so a management route open to the LAN would be remote code execution
for anyone on it. GET /catalog is the exception and answers everybody. The full rules, including
how a web page and a proxy are judged, are § 10, "Who may call
them".
Clients
TypeScript:
@maroonedsoftware/rhapsode-sdk,
generated from the same contracts and depending on nothing.
import { RhapsodeSdk } from '@maroonedsoftware/rhapsode-sdk';
const rhapsode = new RhapsodeSdk({ baseUrl: 'http://127.0.0.1:8080' });
const engines = await rhapsode.public.engines();
A job's event stream is the one operation it cannot serve, because the stream does not end on its
own: read /installs/{job}/events with an EventSource.
Any OpenAI client: point its base URL at http://127.0.0.1:8080/v1 and name an engine as the
model. See OpenAI speech and OpenAI clients.
Anything else: the OpenAPI document above, or curl.
Errors
A refusal on the native routes is one envelope: a code a client branches on, a message written
for a person, and whether trying again could help.
{ "error": { "code": "unknown_voice", "message": "no voice \"narrator_99\"", "retryable": false } }
The codes and when each is used are in § 6, "Errors". The OpenAI route answers in OpenAI's own envelope instead, so that its clients can read it.