> ## Documentation Index
> Fetch the complete documentation index at: https://docs.comfy.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Comfy Router 실시간 음성 세션

> Comfy Router를 통해 Grok Voice 실시간 WebSocket 세션을 엽니다. 엔드포인트, 인증, 초당 요금, 세션 제한, 그리고 발생할 수 있는 오류와 종료 코드를 다룹니다.

Comfy Router는 fal이 제공하는 xAI의 Grok Voice와 실시간 음성 대 음성 세션을 중계합니다. Comfy API 키를 사용해 Router에 WebSocket 하나를 엽니다. Router는 계정과 크레딧을 확인하고, 업스트림에서 세션을 연 뒤 양방향으로 이벤트를 중계합니다. 세션 시간(초)만큼 Comfy 크레딧에서 비용이 차감됩니다.

## 엔드포인트

```text theme={null}
wss://api.comfy.org/v2/realtime/fal/xai/grok-voice/realtime
```

요청은 WebSocket 업그레이드입니다 (`GET`과 `Connection: Upgrade`, `Upgrade: websocket` 포함). 그 외의 요청은 `426`으로 거부됩니다.

## 인증

업그레이드 요청의 헤더에 Comfy API 키를 `X-API-Key: comfyui-...` 또는 `Authorization: Bearer comfyui-...` 형식으로 전송하세요. Router는 쿼리 문자열이나 WebSocket 서브프로토콜에서 키를 읽지 않습니다.

> [!WARNING]
>
> 브라우저는 WebSocket에 헤더를 설정할 수 없으며, Comfy API 키는 절대 브라우저에 도달해서는 안 됩니다. 서버에서 세션을 열고 오디오를 브라우저로 직접 중계하세요.

## 연결

업그레이드가 성공하면 xAI가 Grok Voice에 대해 문서화한 실시간 이벤트를 주고받습니다. 이 예제는 세션을 구성하고, 텍스트 턴 하나를 전송하며, 수신하는 각 이벤트 유형을 출력합니다.

```python Python theme={null}
# pip install websockets msgpack
import asyncio
import os

import msgpack
import websockets

URL = "wss://api.comfy.org/v2/realtime/fal/xai/grok-voice/realtime"


async def send(ws, event):
    await ws.send(msgpack.packb(event))


async def main():
    async with websockets.connect(
        URL,
        additional_headers={"X-API-Key": os.environ["COMFY_API_KEY"]},
    ) as ws:
        await send(ws, {
            "type": "session.update",
            "session": {
                "voice": "eve",
                "instructions": "You are a helpful assistant.",
                "turn_detection": {"type": "server_vad"},
            },
        })
        await send(ws, {
            "type": "conversation.item.create",
            "item": {
                "type": "message",
                "role": "user",
                "content": [{"type": "input_text", "text": "Hello!"}],
            },
        })
        await send(ws, {"type": "response.create"})

        async for message in ws:
            if isinstance(message, str):
                continue  # fal 자체의 x-fal-message 프레임
            event = msgpack.unpackb(message)
            print(event["type"])
            if event["type"] == "response.done":
                break


asyncio.run(main())
```

```javascript Node.js theme={null}
// npm install ws @msgpack/msgpack
import WebSocket from "ws";
import { encode, decode } from "@msgpack/msgpack";

const ws = new WebSocket(
  "wss://api.comfy.org/v2/realtime/fal/xai/grok-voice/realtime",
  { headers: { "X-API-Key": process.env.COMFY_API_KEY } },
);

ws.on("unexpected-response", (req, res) => {
  // 업그레이드가 거부되었습니다. JSON 본문에 사유가 표시됩니다.
  let body = "";
  res.on("data", (chunk) => (body += chunk));
  res.on("end", () => console.error(res.statusCode, body));
});

const send = (event) => ws.send(encode(event));

ws.on("open", () => {
  send({
    type: "session.update",
    session: {
      voice: "eve",
      instructions: "You are a helpful assistant.",
      turn_detection: { type: "server_vad" },
    },
  });
  send({
    type: "conversation.item.create",
    item: {
      type: "message",
      role: "user",
      content: [{ type: "input_text", text: "Hello!" }],
    },
  });
  send({ type: "response.create" });
});

ws.on("message", (data, isBinary) => {
  if (!isBinary) return; // fal 자체의 x-fal-message 프레임
  const event = decode(data);
  console.log(event.type);
  if (event.type === "response.done") ws.close();
});

ws.on("close", (code) => console.log("closed", code));
```

작업이 끝나면 즉시 소켓을 닫으세요. 과금은 마지막 응답이 아니라 세션이 종료될 때까지 부과됩니다.

## 이벤트

Router는 자체 이벤트 프로토콜을 정의하지 않습니다. 서버 이벤트는 fal이 보내는 그대로 도착하며, Router가 허용하는 클라이언트 이벤트는 변경 없이 전달됩니다. 이벤트 목록, 세션 필드, 음성, 오디오 형식은 다음 문서를 참고하세요:

* [xAI Speech to Speech](https://docs.x.ai/developers/model-capabilities/audio/speech-to-speech) 및 xAI의 [realtime event schema](https://docs.x.ai/voice-realtime.ws.json)
* fal의 [Grok Voice realtime 모델 페이지](https://fal.ai/models/xai/grok-voice/realtime) 및 [API 페이지](https://fal.ai/models/xai/grok-voice/realtime/api)

예제에서처럼 각 클라이언트 이벤트를 하나의 msgpack 바이너리 메시지로 전송하세요. 이는 fal의 realtime 클라이언트가 사용하는 프레이밍이며, 모델의 이벤트도 `session.created`로 시작하는 msgpack 바이너리 메시지로 같은 방식으로 돌아옵니다. fal은 `x-fal-message` 유형의 자체 JSON 텍스트 메시지(타이밍 정보)도 보내는데, 이는 건너뛰어도 됩니다. Router의 검사는 클라이언트 이벤트를 하나의 JSON 텍스트 메시지로도 허용하지만, 클라이언트에서 JSON을 테스트해 보지 않았다면 msgpack을 사용하세요.

Router는 전달하기 전에 각 클라이언트 이벤트를 검사합니다:

* **이벤트 유형:** `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`, 그리고 fal의 `x-fal-session.configure`.
* **모델:** `session.update`의 `model`은 `grok-voice-latest`, `grok-voice-3.0`, `grok-voice-2.0` 중 하나여야 합니다.
* **도구:** 클라이언트가 실행하는 함수 도구는 허용됩니다. 서버 측 도구(웹 검색, X 검색, 파일 검색, MCP)는 거부됩니다.
* **미디어:** 이미지 및 비디오 입력은 거부됩니다. 세션은 음성과 텍스트만 지원합니다.
* **크기:** 클라이언트 메시지 하나는 최대 1 MiB입니다.

거부된 이벤트는 전달되지 않으며, Router는 종료 코드 `1008`로 세션을 닫습니다.

## 가격

세션 비용은 \*\*초당 $0.0011869**입니다(분당 약 $0.0712, 초당 0.2504 크레딧, 분당 약 15.0 크레딧이며, 211 크레딧 = \$1 USD 기준입니다). 세션이 열려 있는 동안 15초 증가분 단위로 청구되며, 마지막 부분 증가분은 초 단위로 올림하여 청구됩니다. 청구는 오디오가 흐르는지 여부와 관계없이 업그레이드 시점부터 소켓이 닫힐 때까지 이루어집니다.

## 제한

| 제한 | 값 |
| - | - |
| 계정당 세션 | 한 번에 하나의 세션만 열 수 있습니다. 두 번째 세션을 열면 `429`와 `router.realtime.session_already_live`가 반환됩니다. |
| 세션 길이 | 최대 30분이며, 연결 시점의 보유 크레딧 잔액으로 감당할 수 있는 시간보다 길 수 없습니다. |
| 세션 중 크레딧 | Router는 15초마다 잔액을 다시 확인하며, 잔액이 다음 1초를 감당할 수 없게 되면 세션을 종료합니다. |
| 연결 빈도 | 각 업그레이드 시도는 다른 Router 호출과 공유되는 [호출자별 요청 속도](https://docs.comfy.org/ko/development/comfy-router/limitations.md#요청은-호출자별로-속도-제한됩니다)에 포함됩니다. |

세션이 시간 제한에 도달하거나 크레딧이 소진되면 연결이 종료 프레임 없이 닫힐 수 있습니다(흔히 종료 코드 `1006`으로 표시됨). 크레딧을 충전한 이후에만 다시 연결하거나, 더 많은 시간이 필요하면 새 세션을 시작하세요.

## 오류

### 업그레이드 이전

Router가 연결을 거부하면 프로토콜 전환 대신 HTTP 상태와 JSON 본문으로 응답합니다:

```json theme={null}
{
  "detail": "Insufficient credits to open a realtime session.",
  "error_type": "insufficient_credits",
  "code": "router.realtime.insufficient_credits"
}
```

`code`를 기준으로 분기하세요. `detail`은 사람이 읽기 위한 정보입니다.

| 상태 | `code` | 원인 | 해결 방법 |
| - | - | - | - |
| `426` | `router.realtime.upgrade_required` | 요청이 WebSocket 업그레이드가 아니었습니다. | WebSocket 클라이언트로 연결하세요. |
| `401` | `router.realtime.unauthorized` | API 키가 누락되었거나 유효하지 않습니다. | `X-API-Key` 또는 `Authorization: Bearer`에 유효한 키를 보내세요. |
| `402` | `router.realtime.insufficient_credits` | 잔액으로 최소 1초의 세션도 감당할 수 없습니다. | 크레딧을 추가한 뒤 다시 연결하세요. |
| `402` | `router.realtime.spend_denied` | 세션 요금이 청구될 지갑에 자금이 없습니다. 본문의 `denied_reason`과 `billed_workspace`가 어느 지갑인지 알려줍니다. | 해당 워크스페이스에 크레딧을 추가한 뒤 다시 연결하세요. |
| `403` | `router.realtime.provider_disabled` | 워크스페이스의 파트너 공급자 정책이 이 공급자를 허용하지 않습니다. | 워크스페이스 관리자에게 허용을 요청하세요. |
| `404` | `router.realtime.model_not_allowed` | URL의 모델은 실시간 세션에서 사용할 수 없습니다. | URL을 확인하세요. |
| `429` | `router.realtime.rate_limited` | 요청 속도를 초과했습니다. | `Retry-After`만큼 기다린 뒤 재시도하세요. |
| `429` | `router.realtime.session_already_live` | 계정에 이미 다른 세션이 열려 있습니다. | 먼저 해당 세션을 닫으세요. |
| `429` | `router.realtime.concurrency_limit` | 동시 파트너 모델 호출이 너무 많습니다. | 동시 작업을 줄이고 재시도하세요. |
| `502` | `router.realtime.upstream_refused`, `router.realtime.token_mint_failed` | 업스트림 공급자가 세션을 열지 않았습니다. | 백오프를 두고 재시도하세요. |
| `503` | 그 외 모든 `router.realtime.*` 코드 | 실시간 세션을 일시적으로 사용할 수 없습니다. | 백오프를 두고 재시도하세요. |

### 업그레이드 이후

| 종료 코드 | 의미 | 해결 방법 |
| - | - | - |
| `1008` | 클라이언트 이벤트가 거부되었습니다([이벤트](#이벤트) 참조). | 이벤트를 수정하세요. 세션은 종료되었습니다. |
| `1012` | Router가 재시작 중입니다. | 다시 연결하세요. 새 세션이 시작되며 새 업그레이드 시점부터 과금됩니다. |
| `1006` (종료 프레임 없음) | 세션이 시간 제한에 도달했거나 크레딧이 소진되었을 때 클라이언트가 흔히 보고하는 코드입니다. 네트워크 끊김도 동일하게 보입니다. | 크레딧을 추가하거나 새 세션을 시작하세요. |

그 외의 종료는 fal 또는 xAI에서 발생합니다. [이벤트](#이벤트)에 링크된 해당 문서를 참조하세요.

## 다음

* [청구](https://docs.comfy.org/ko/development/comfy-router/billing.md): Router가 요금을 부과하는 방식과 사용량을 대조하는 방법.
* [오류 및 재시도](https://docs.comfy.org/ko/development/comfy-router/errors.md): 다른 Router 호출이 반환하는 오류 분류.
* [제한 사항](https://docs.comfy.org/ko/development/comfy-router/limitations.md): 요청 속도 및 기타 제한.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.