Skip to main content
The fastest way to understand the bridge is to run its example project - a minimal, working embedding you can copy straight into your own repo. Budget about 10 minutes once the Teams setup is done.

examples/basic-bridge

loadConfig() + startServer() in a few lines, with a custom vision hook (your own model answers the agent’s look tool) and a custom lookup_order function tool the bridge executes. Env-file config and graceful shutdown are built in.

What you need first

  • Node.js >= 20.
  • An OpenAI API key with Realtime access (platform.openai.com). No agent to create - the bridge configures each gpt-realtime session itself.
  • A StandIn identity with its shared secret (from pairing or the dashboard). The sandbox works too if you have no Teams bot yet.

1. Clone and install

2. Configure the environment

The example reads the same env file as the CLI - copy the fully commented template from the repo root:
Open .env and fill in the two required values: Worth setting while you are there: OPENAI_VOICE (e.g. marin), OPENAI_INSTRUCTIONS (the agent’s personality), and OPENAI_FIRST_MESSAGE (a deterministic greeting / AI disclosure). The example still boots with dummy values, so you can check the wiring before the credentials are real. Everything else (PORT, MAX_CALL_MINUTES, goodbye behavior, VAD mode) has sensible defaults - see the configuration reference.

3. Start it

The bridge prints the WebSocket URL to give StandIn:

4. Expose port 9442

StandIn connects from the internet, so the port needs a public wss:// URL. Any tunnel works:
Your URL: wss://<machine>.<tailnet>.ts.net/voice/msteams/stream

5. Connect it to StandIn and call

  1. In your StandIn dashboard, set the identity’s Agent calling URL to the wss:// URL from step 4.
  2. Make sure the identity’s shared secret equals WORKER_SHARED_SECRET.
  3. Place a Teams call to your bot (or join the sandbox meeting). StandIn joins, connects to the bridge, and your gpt-realtime agent answers.

The vision hook

The example ships a custom VisionDescriber in index.mjs. When your agent calls its built-in look tool, the bridge hands your function the current camera or screen-share frame and returns your text description to the agent - the raw frame never leaves your process. The example answers with gpt-4o-mini; swap in any vision-capable model. If you prefer configuration over code, the VISION_API_URL / VISION_API_KEY / VISION_MODEL variables do the same against any OpenAI-compatible endpoint - see Vision.

The custom tool

The example also registers a lookup_order function tool:
Ask the agent on a call “where is order KO-12?” and it calls your handler, then speaks the answer. This is the pattern for wiring the agent to your own systems (CRM lookups, transfers, bookings); remote MCP servers are the config-only alternative - see Extending the agent’s tools.

From example to your own project

Depend on the published package instead of the local checkout:
Then copy the example’s index.mjs as your starting point. The library API documents the programmatic surface (config, server options, tools, hooks).

If something does not work

  • WebSocket rejected with 401 - WORKER_SHARED_SECRET does not match the secret in StandIn.
  • Bot joins the call but stays silent - the Agent calling URL is unreachable from the internet or points at the wrong port; re-check the tunnel.
  • Call connects, then ends with agent-unavailable - the OpenAI key is invalid, lacks Realtime access, or OPENAI_REALTIME_MODEL names a model your account cannot use; the log line carries the underlying error.
  • More: Troubleshooting.

Example README

Configuration

Library API