Skip to content

Quickstart for servers

In a few minutes you will have a voice answering from your own machine. You need a Kheelona API key, and the example folder for your language: the examples you received from the Kheelona team, with the SDK package. They are proprietary and shared privately; the commands below run inside that folder, so cd examples/node-server means the node-server folder of what you received.

  • Node: Node 24 or newer and pnpm.
  • Python: Python 3.12 or newer and uv.

Sign in to your Kheelona console. From the public launch, the first time anyone signs in to your console, they set up a second sign-in step with an authenticator app on their phone (before the launch it may be optional). Have the phone at hand if asked. Then open API keys and create a key. Copy it when it is shown: it is shown once. It starts with kv_live_.

The key belongs on your server only. Never put it in a toy, an app or a web page.

Terminal window
export KHEELONA_API_KEY=kv_live_…

The examples read the key only from this variable. They never print it.

Terminal window
cd examples/node-server
pnpm install

A typed turn needs no microphone and no recording. The relay creates a session, connects, sends your text, saves the reply audio and ends the session.

Terminal window
pnpm relay --text "Hello! Tell me a short story."

The relay prints each event on one line, and the text of what the voice says under it. The middle lines vary with the reply. The last line is always the summary.

event session.ready
event state
…
event reply.sentence
text: Once upon a time, a little dragon found a shiny stone.
…
event reply.done
event state
event session.ended
session ses_… ended client_ended replies 1 audio 8.4s saved reply.wav

Open reply.wav to hear it (24 kHz, 16-bit, mono).

A typed turn gives one reply, as above. A recording can give more: the voice may hear it as more than one turn, and you may see input.speech_started and interrupted events when the person, or the clip, keeps talking while the voice is replying. Then there is more than one reply.done, and the count in the last line is higher. That is normal. See Turn-taking.

If something is wrong, the relay prints one line to standard error and exits with 1:

error unauthenticated request_id req_…

Quote that line if you ask us for help: a request ID comes with a refused request, and the session ID with an error during a session. An exit code of 2 means a usage mistake, such as a missing key or no --text and no --wav. See Errors and retries.

The relay sends a WAV file the way a toy would: 20 ms frames, at real time. The file must be 16 kHz, 16-bit, mono. Convert any recording with ffmpeg:

Terminal window
ffmpeg -i in.wav -ac 1 -ar 16000 -sample_fmt s16 question.wav

Then run the relay with it:

Terminal window
pnpm relay --wav question.wav --out reply.wav

You now see transcript.final with what was heard, and the reply as before. The relay keeps sending silence after your recording ends, as a live microphone does, until the reply is finished. Set the languages the session listens for with --languages, for example --languages en,hi.

You can give both --text and --wav. The typed turn goes first and the recording follows once its reply is done. A recording can be heard as more than one turn, so expect more than one reply.done and, at times, interrupted events.

Every session leaves a record: when it ran, how long, how many turns, why it ended. It never holds what was said. Read the one you just ran with GET /v1/sessions/{id} (the ID is in the relay’s last line). The call, with its fields and errors, is in the REST reference. Your API key needs the sessions:read scope.

To see the call that creates a session, here is the same thing with curl (it needs uuidgen; the key goes to curl on standard input so it never shows in a process list):

create-session.sh
API_URL="${KHEELONA_API_URL:-https://api.voice.kheelona.com}"
VOICE_ID="${KHEELONA_VOICE_ID:-lumi-dragon}"
# One Idempotency-Key per logical session: repeating the request with the same key returns the same session.
printf 'Authorization: Bearer %s\n' "$KHEELONA_API_KEY" | curl -sS --fail-with-body \
-H @- \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-X POST "$API_URL/v1/sessions" \
-d "{\"voice_id\": \"$VOICE_ID\", \"languages\": [\"en\", \"hi\"]}"

The answer holds a client secret. It works once and for about 60 seconds. Don’t paste it into chat or logs.