Skip to main content
Comfy Router relays a realtime speech-to-speech session with xAI’s Grok Voice, served by fal. You open one WebSocket to Router with your Comfy API key. Router checks your account and credits, opens the session upstream, and then relays events in both directions. You pay per second of session from your Comfy credits.

Endpoint

The request is a WebSocket upgrade (GET with Connection: Upgrade and Upgrade: websocket). Anything else is refused with 426.

Authentication

Send your Comfy API key in a header on the upgrade request, either as X-API-Key: comfyui-... or as Authorization: Bearer comfyui-.... Router does not read a key from the query string or from the WebSocket subprotocol.
Browsers cannot set headers on a WebSocket, and a Comfy API key must never reach a browser. Open the session from your server and relay audio to the browser yourself.

Connect

Once the upgrade succeeds, send and receive the realtime events xAI documents for Grok Voice. This example configures the session, sends one text turn, and prints each event type it receives.
Close the socket as soon as you are done. You are billed until the session closes, not until the last response.

Events

Router does not define its own event protocol. Server events reach you exactly as fal sends them, and the client events Router accepts are forwarded unchanged. For the event list, session fields, voices, and audio formats, see: Send each client event as one msgpack binary message, as in the examples. This is the framing fal’s realtime clients use, and the model’s events come back the same way, as msgpack binary messages starting with session.created. fal also sends its own JSON text messages of type x-fal-message (timing information); you can skip them. Router’s checks also accept a client event as one JSON text message, but use msgpack unless you have tested JSON with your client. Router checks each client event before forwarding it:
  • Event types: session.update, input_audio_buffer.append, input_audio_buffer.commit, input_audio_buffer.clear, conversation.item.create, conversation.item.delete, conversation.item.truncate, response.create, response.cancel, and fal’s x-fal-session.configure.
  • Models: a model in session.update must be grok-voice-latest, grok-voice-3.0, or grok-voice-2.0.
  • Tools: function tools that your client executes are allowed. Server-side tools (web search, X search, file search, and MCP) are refused.
  • Media: image and video input is refused. The session is voice and text only.
  • Size: one client message may be at most 1 MiB.
A refused event is not forwarded, and Router closes the session with close code 1008.

Pricing

A session costs **$0.00083 per second** (about $0.05 per minute, or about 0.175 credits per second at 211 credits = $1 USD). It is billed in 15-second increments while the session is open, and the final partial increment is billed by the second, rounded up. Billing runs from the upgrade until the socket closes, whether or not audio is flowing.

Limits

When a session reaches its time limit or runs out of credits, the connection may close without a close frame (often surfaced as close code 1006). Reconnect only after topping up, or start a new session if you need more time.

Errors

Before the upgrade

If Router refuses the connection, it answers with an HTTP status and a JSON body instead of switching protocols:
Switch on code; detail is for people.

After the upgrade

Any other close comes from fal or xAI. See their documentation linked under Events.

Next