Skip to main content
In this quickstart, you’ll send Prism a pre-recorded question over a secure WebSocket, without the Rime SDK, and listen to its answer in reply.wav. By the end, you’ll have a one-file script in Python or Node.js you can port to any language with a WebSocket client. Prism answers the phone for a made-up cafe, and a recorded caller asks when the cafe closes today. Take this path when your backend’s language has no Rime SDK, or you want to handle Prism’s JSON events yourself.
Working in Python or Node.js? In our SDK quickstart, you talk to Prism through your microphone, with your own instructions.

What you’ll need

  • A Rime API key. If you don’t have one yet, create one.
  • uv for Python, or Node.js 22 or later.
  • Your computer or a server to run the script. A browser can’t connect directly, because Prism checks your API key in the Authorization header, which the browser WebSocket API can’t set.

Build it step by step

1

Create the project and install a WebSocket client

Any WebSocket client works, as long as it can set headers on the connection request. These commands pin websockets 17.2 for Python and ws 8.22.0 for Node.js.
Create a project and add the websockets package:
2

Set your API key

The script reads your key from RIME_API_KEY and sends it as Authorization: Bearer YOUR_API_KEY when it connects. Set it in the terminal where you’ll run the script:
3

Download the sample question

Your caller is a 3-second recording made with Rime text-to-speech, asking, “Hi there! I was just wondering, what time do you close today?” This command saves it to your project folder:
You should now have question.wav, and question.pcm, the same audio without its 44-byte WAV header. That’s the input format Prism accepts: raw 16-bit samples at 16 kHz, mono. To hear the question first, open question.wav in your browser.To ask your own question, record it in English without pausing partway through. Prism ends the turn at a long pause, so a mid-sentence pause splits your question into two turns. Convert it to 16 kHz mono PCM16 with FFmpeg. This command reads recording.mp3 and writes recording.pcm:
Run the script with recording.pcm in place of question.pcm.
4

Save the script

The script prints when Prism hears the caller start and stop, prints the reply text, and saves the reply audio to reply.wav. Save it in your project folder:
ask.py
The instructions give Prism one fact you can check by ear: Juniper Cafe closes at 4 p.m. Each message is one JSON object, and audio is base64 in both directions. The script stops when response.done ends the reply, or after 60 seconds.
5

Run it and listen

Run the script with the question file:
After a few seconds, you should see output like this:
The first two lines come from input_audio_buffer.speech_started and input_audio_buffer.speech_stopped. Prism started its reply only after it found the end of the caller’s turn. The Prism: line is the reply text, printed one response.text.delta at a time. The words and audio length change from run to run.Now open reply.wav in an audio player. You should hear Prism say the cafe closes at 4 p.m. If the script doesn’t work, here’s where to look:
  • The script stops with an error: find its code in Errors and limits. In Python, KeyError: 'RIME_API_KEY' means the variable isn’t set in your terminal. In Node.js, a missing variable gives Unexpected server response: 401, because the script sends Bearer undefined.
  • Prism refuses the connection: the HTTP status in the error tells you why. Upgrade refusals lists each status.
  • Nothing prints until No reply within 60 seconds: check that the audio is 16 kHz mono PCM16.
6

Try another voice

The script uses aurora, one of four Prism voices, and Choose a voice describes the others: wawona, brando, and astra. Change the voice in the script’s session.update to wawona, and run it on the same question again:
You should see output like this:
The closing time is the same, but you’ll hear a higher voice in reply.wav. This script sets the voice and instructions once. To change them during a conversation, send another session.update, and the next reply uses the new settings.

How it works

The script behaves like a live call, so two things matter:
  • Order in the first messages: it sends session.update as soon as the connection opens. It holds the audio until session.updated arrives, because Prism refuses audio sent before it accepts the first update.
  • The pace of a microphone: it streams the recording in real time, a 40 ms chunk every 40 ms, and keeps sending silence after the question ends. The silence matters, because Prism finds the end of the caller’s turn by itself.
Here’s each step and the event behind it: Prism sends a few other events too, such as session.created, which comes first, and the caller’s transcript. The script ignores them, and so can a first port.

Next steps

Now that Prism answers a recording, you can build toward a live call: