Connect your application.
Rainboots supports OpenAI Live-style WebSocket and WebRTC connections. POST an offer to /v1/live/sessions with a one-use client secret for WebRTC media and an oai-events channel. Your backend mints a one-use client secret; your browser streams microphone audio and plays Sprinkler-1's audio. The SDK API guide documents every event, including the Rainboots extensions.
1. Mint a client secret on your backend
const response = await fetch(WILLOW_URL + "/v1/live/client_secrets", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.WILLOW_PROJECT_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({ session: {
model: "sprinkler-1",
audio: { output: { voice: "harper" } }, // or "sofiah", "freya", "mason", "felix", "oliver"
willow: {
origin: "https://your-app.example",
conversation_id: conversationId, // Created with POST /v1/conversations
budget_micro_usd: 1_000_000 // $1 ceiling for this session
}
} })
});
if (!response.ok) throw new Error(await response.text());
const { value, ice_servers } = await response.json();
// Return both fields to your authenticated frontend.Keep the project key on your backend. Client secrets expire after 60 seconds and can connect once. The origin must exactly match the browser's origin. A backend can instead connect directly with its project key in the Authorization header.
Inworld TTS-2 offers klo, callion, jared and lennette. Legacy voice names map harper, sofiah and freya to Klo, and mason, felix and oliver to Callion; an unknown voice falls back to harper. The model is sprinkler-1. Fields set in the secret cannot be changed by the browser.
2. Connect and speak in the browser
For WebRTC, pass the returned ice_servers to new RTCPeerConnection({ iceServers: ice_servers }), then POST your offer to /v1/live/sessions using value as the bearer secret. These one-hour credentials include TURN/TLS on port 443 for networks that block direct UDP. STUN-only works on open networks. The WebSocket alternative follows.
const ws = new WebSocket(WILLOW_WS_URL + "/v1/live/sessions",
["openai-insecure-api-key." + value]);
ws.onopen = () => ws.send(JSON.stringify({
type: "session.start",
session: { instructions: "Help with the project open in this application." }
}));
ws.onmessage = ({ data }) => {
const event = JSON.parse(data);
if (event.type === "session.started") startMicrophone(); // 24 kHz mono PCM16
if (event.type === "session.output_audio.delta") play(event.delta); // queue in order
if (event.type === "session.output_transcript.delta") console.log(event.delta);
if (event.type === "error") console.error(event.error.message);
};
// For each microphone chunk, base64-encoded:
ws.send(JSON.stringify({ type: "session.input_audio.append", audio: base64Pcm }));
// When done: ws.send(JSON.stringify({ type: "session.close" }));Sprinkler-1 detects speech, transcribes it and decides when you have finished. Free-flow is the default and allows voice barge-in. Set session.willow.turn_taking to true to silence microphone input during the model’s playback and a short echo tail, change it with session.update, or send willow.interrupt for a manual stop in either mode. Audio arrives paced close to real time and needs no playback acknowledgements.
Conversation boundaries
State persists until you clear or delete it. POST /v1/conversations/:id/clear erases its history and summary and also clears its shared context, affecting other conversations that use that context. POST /v1/contexts/:id/clear clears shared understanding alone. DELETE removes the chosen conversation or context. Pending updates cannot restore cleared notes. No audio is archived. See the SDK API guide for archive reads, errors, and retention details.
Beta contract
Pricing is $0.03 per minute, with a 90% discount for every second that has no user or agent speech. Recognized speech from any source in the room, such as a TV, counts as active voice. Voice time covers the union of user speech and actual model playback, plus one second after activity ends. Typed input and text-only replies follow the same rule from request to reply. Background tools, model calls, recognition and context maintenance are included. Missing usage stays visibly pending for operator review.
Sessions currently last up to two hours and close after two hours without client activity. Create a conversation on your backend with POST /v1/conversations, optionally supplying a context_id. Include its conversation_id in each client secret to persist history and resume after disconnect. Rainboots compacts older history automatically. A context_id shares selected useful understanding across conversations. Without a conversation_id, the session remembers itself only until it closes; nothing is saved.
Expose your application's tools as function tools in a responses delegation. Rainboots sends each call as a function_call; the application executes it and replies with a function_call_output. Public sessions cannot access host credentials, Codex account controls, or change the backend-selected model.
Current beta capacity is four simultaneous sessions across the service, with at most two per project. Rainboots transcribes your microphone audio on the server. The speech providers are replaceable behind the same audio-in/audio-out interface.