FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
emcho
emchohello-transcription
Remix of emcho/hello-mcp
Public
Like
hello-transcription
Home
Code
10
.claude
1
docs
1
frontend
1
routes
3
.gitattributes
.vtignore
CLAUDE.md
README.md
deno.json
H
main.tsx
Branches
1
Pull requests
Remixes
1
History
Environment variables
1
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
docs
/
guides
/
realtime-server-controls.md
Code
/
docs
/
guides
/
realtime-server-controls.md
Search
9/4/2025
Viewing readonly version of main branch: v41
View latest version
realtime-server-controls.md

Webhooks and server-side controls

Use webhooks and server-side controls with the Realtime API.

The Realtime API allows clients to connect directly to the API server via WebRTC or SIP. However, you'll most likely want tool use and other business logic to reside on your application server to keep this logic private and client-agnostic.

Keep tool use, business logic, and other details secure on the server side by connecting over a β€œsideband” control channel. We now have sideband options for both SIP and WebRTC connections.

With WebRTC

When establishing a peer connection, you receive an SDP response from the Realtime API to configure the connection. If you used the sample code from the WebRTC guide, that looks something like this:

const baseUrl = "https://api.openai.com/v1/realtime/calls"; const model = "gpt-realtime"; const sdpResponse = await fetch(`${baseUrl}?model=${model}`, { method: "POST", body: offer.sdp, headers: { Authorization: `Bearer ${EPHEMERAL_KEY}`, "Content-Type": "application/sdp", }, });

The SDP response will contain a Location header that has a unique call ID that can be used on the server to establish a WebSocket connection to that same Realtime session.

const location = sdpResponse.headers.get("Location"); const callId = location?.split("/").pop(); console.log(callId); // rtc_u1_9c6574da8b8a41a18da9308f4ad974ce

On a server, you can then listen for events and configure the session just as you would from the client, using the ID from this URL:

import WebSocket from "ws"; // You'll need to get the call ID from the browser to your // server somehow: const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce"; // Connect to a WebSocket for the in-progress call const url = "wss://api.openai.com/v1/realtime?call_id=" + callId; const ws = new WebSocket(url, { headers: { Authorization: "Bearer " + process.env.OPENAI_API_KEY, }, }); ws.on("open", function open() { console.log("Connected to server."); // Send client events over the WebSocket once connected ws.send( JSON.stringify({ type: "session.update", session: { type: "realtime", instructions: "Be extra nice today!", }, }) ); }); // Listen for and parse server events ws.on("message", function incoming(message) { console.log(JSON.parse(message.toString())); });

In this way, you are able to add tools, monitor sessions, and carry out business logic on the server instead of needing to configure those actions on the client.

With SIP

  1. A user connects to OpenAI via phone over SIP.
  2. OpenAI sends a webhook to your application’s backend webhook URL, notifying your app of the state of the session.
POST https://my_website.com/webhook_endpoint user-agent: OpenAI/1.0 (+https://platform.openai.com/docs/webhooks) content-type: application/json webhook-id: wh_685342e6c53c8190a1be43f081506c52 # unique id for idempotency webhook-timestamp: 1750287078 # timestamp of delivery attempt webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= { "object": "event", "id": "evt_685343a1381c819085d44c354e1b330e", "type": "realtime.call.incoming", "created_at": 1750287018, // Unix timestamp "data": { "call_id": "some_unique_id", "sip_headers": [ { "name": "From", "value": "sip:+142555512112@sip.example.com" }, { "name": "To", "value": "sip:+18005551212@sip.example.com" }, { "name": "Call-ID", "value": "03782086-4ce9-44bf-8b0d-4e303d2cc590"} ], } }
  1. The application server opens a WebSocket connection to the Realtime API using the call_id value provided in the webhook. This call_id looks like this: wss://api.openai.com/v1/realtime?call_id={callId}. The WebSocket connection will live for the life of the SIP call.

Was this page useful?

Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
Β© 2025 Val Town, Inc.