Skip to content

OpenAI Realtime

OpenAI’s Realtime API exposes a single WebSocket that handles speech-to-text, LLM reasoning, and text-to-speech in one pass. Pair it with Teler and you have a working AI voice agent in minutes.

VariableRequiredDefaultDescription
OPENAI_API_KEYyesnoneYour OpenAI API key.
TELER_API_KEYyesnoneYour Teler API key from the dashboard.
NGROK_AUTHTOKENyes (local)nonengrok auth token for the public tunnel.
SERVER_DOMAINautononePublic URL exposed to Teler. Detected from ngrok automatically.
Terminal window
git clone https://github.com/frejun-tech/teler-openai-bridge
cd teler-openai-bridge
cp .env.example .env
# fill OPENAI_API_KEY, TELER_API_KEY, NGROK_AUTHTOKEN
docker compose up -d --build
Terminal window
curl -X POST http://localhost:8000/api/v1/calls/initiate-call \
-H "Content-Type: application/json" \
-d '{
"from_number": "+91XXXXXXXXXX",
"to_number": "+91XXXXXXXXXX"
}'

The phone rings; the OpenAI agent answers. Talk to it.

The bridge implements the standard 3-endpoint pattern documented in Media Streaming → Bridge:

EndpointDirectionPurpose
POST /api/v1/calls/initiate-callclient → bridgeTrigger an outbound call.
POST /api/v1/calls/flowTeler → bridgeReturns a stream Call Flow.
WS /api/v1/calls/media-streamTeler → bridgeBidirectional audio.
POST /api/v1/webhooks/receiverTeler → bridgeLifecycle webhooks.

Inside the WebSocket handler, the bridge opens a parallel WebSocket to the OpenAI Realtime API and relays audio in both directions.

OpenAI Realtime returns 24 kHz PCM. Teler operates at 8 kHz (or 16 kHz if you configure it). The bridge handles downsampling automatically; you don’t need to touch this unless you fork the repo.

  • Replace ngrok with a real public host: Fly.io, Railway, ECS, or your own infra.
  • Pin the Docker image with a tagged release rather than :latest.
  • Set SERVER_DOMAIN explicitly in production; auto-detect is for local only.
  • Forward Teler webhooks to your backend rather than the bridge for durability.
  • Rotate OPENAI_API_KEY and TELER_API_KEY quarterly.
SymptomLikely causeFix
Phone rings but silenceMissing OPENAI_API_KEY or invalidCheck container logs; recreate .env
Bridge can’t be reachedngrok not running or SERVER_DOMAIN staledocker compose restart; wait for ngrok
Garbled / chipmunk audioSample rate mismatchShould not happen with this bridge; file an issue if it does
Long latency on first responseCold start of Realtime sessionSend a tiny warm-up message before connecting the call