콘텐츠로 이동

엔드포인트·이벤트 참조

HTTP 엔드포인트

POST /v1/realtime/calls

WebRTC offer를 answer로 교환합니다.

요청

항목 값
Authorization Bearer <sr_... API key 또는 client-secret JWT>
Content-Type application/sdp
body offer SDP text, 비어 있지 않고 최대 1 MiB

클라이언트는 POST 전에 로컬 ICE gathering 완료를 기다려야 합니다. Gateway도 로컬 후보 수집을 완료한 answer를 반환하므로 별도 trickle candidate API는 없습니다.

응답

상태 의미
201 application/sdp answer SDP
400 빈 offer, 잘못된 세션/EPD query
401 Bearer 누락·형태 오류 또는 backend 인증 거부
502 WSS, PeerConnection, SDP/ICE setup 등 세션 시작 실패

선택 query는 camelCase를 정본으로 하며 snake_case 별칭도 받습니다.

  • 엔진·사용자: conversationEngine, externalUserId, latitude, longitude
  • DM: scenarioId, scenarioSlug, sessionCreateMode, botFirst
  • TTS 선택: voicePreset, ttsProvider, ttsModel, voiceType
  • EPD: minSpeech, endSilence, epdTimeout (timeout 별칭 포함)

instructions와 객체형 scenarioGraph는 URL에 넣지 않고 데이터채널 session.update로만 보냅니다.

OPTIONS /v1/realtime/calls

CORS_ALLOWED_ORIGINS가 비어 있지 않을 때만 등록됩니다. 허용 Origin과 POST 요청이면 204, 그 외는 403입니다. CORS 비활성 시 405입니다.

GET /healthz

200과 ok를 반환합니다. backend·ICE 의존성 readiness 검사는 아닙니다.

GET /metrics

Prometheus text exposition을 반환합니다.

제거된 /v1/realtime/client_secrets

어떤 메서드로도 등록되지 않으며 404입니다. app-backend가 client-secret JWT를 발급해야 합니다.

데이터채널

  • label: oai-events
  • payload: UTF-8 JSON text
  • 오디오: 데이터채널이 아니라 RTP track
  • 서버 이벤트: 채널 open 전에는 제한된 queue에 저장하고 open 뒤 순서대로 flush

클라이언트 이벤트

session.update

언어, EPD와 SOHRI 확장 세션 파라미터를 갱신합니다.

{
  "type": "session.update",
  "event_id": "evt-1",
  "session": {
    "language": "ko",
    "sohri": {
      "conversationEngine": "sohri",
      "externalUser": {"id": "user-42"},
      "scenarioSlug": "daily-checkin",
      "botFirst": true,
      "minSpeech": 0.3,
      "endSilence": 1.2,
      "epdTimeout": 7
    }
  }
}

Gateway는 session.sohri, session, top-level sohri 순으로 확장을 찾습니다. EPD 설정은 한 위치에만 제공해야 하며 minSpeech ≤ epdTimeout이어야 합니다. 엔진 setup ACK가 필요한 경우 session.updated는 backend ACK까지 지연됩니다.

conversation.item.create

item.content[]의 input_text 또는 text를 찾아 /sohri text{message}로 전달합니다.

{
  "type": "conversation.item.create",
  "item": {
    "type": "message",
    "role": "user",
    "content": [{"type": "input_text", "text": "안녕하세요"}]
  }
}

response.create

SOHRI 엔진에서는 사용자 활동 전 최초 선인사를 시작하거나 이미 진행되는 자동 DM 응답 lifecycle에 연결합니다. 대화 시작 뒤 proactive 선인사를 반복하는 요청은 error가 될 수 있습니다. OpenAI 엔진에서는 backend의 provider 세션으로 전달됩니다.

response.cancel / cancel_response

활성 응답과 playout을 취소하고 /sohri에 cancel_response를 보냅니다.

output_audio_buffer.clear

대기 중인 playout generation을 무효화하고 output_audio_buffer.cleared{response_id}를 회신합니다.

input_audio_buffer.*

append, commit, clear 등은 무해하게 폐기합니다. 인바운드 오디오는 RTP track에서 받습니다.

서버 이벤트

세션·음성 인식

이벤트 주요 필드·의미
session.created session.id: backend WSS session ID
session.updated 적용된 SOHRI/engine snapshot
input_audio_buffer.speech_started EPD 발화 시작
input_audio_buffer.speech_stopped EPD 발화 종료
conversation.item.input_audio_transcription.completed transcript, content_index: 0
sohri.speech_candidate data, duck/pause 후보
sohri.speech_candidate_cancelled 후보 취소

응답 lifecycle

SOHRI 응답은 일반적으로 아래 순서를 사용합니다.

  1. response.created
  2. response.output_item.added
  3. response.content_part.added
  4. response.output_audio_transcript.delta
  5. response.output_audio_transcript.done
  6. response.content_part.done
  7. response.output_item.done
  8. response.done

response_id, item_id, output_index, content_index로 이벤트를 상관시킵니다. 취소·오류에서는 response.done.response.status가 cancelled 또는 failed가 됩니다.

TTS 재생 확장

{
  "type": "sohri.tts_stream_start",
  "response_id": "resp_...",
  "format": {"encoding": "opus", "sample_rate": 48000, "channels": 1}
}

첫 가청 Opus frame을 트랙에 실제 기록한 직후 한 번 발생합니다. 유휴 무음은 start를 만들지 않습니다.

{
  "type": "sohri.tts_stream_end",
  "response_id": "resp_...",
  "status": "completed",
  "duration_ms": 4120
}

duration_ms는 큐에 넣은 전체 길이로 자막 진행률의 분모입니다.

{
  "type": "sohri.tts_stream_aborted",
  "response_id": "resp_...",
  "played_ms": 1240
}

실제 재생이 잘렸을 때 발생합니다. played_ms는 사용자에게 기록된 위치이며 pause 구간은 포함하지 않습니다.

sohri.dialog_text는 스트리밍 wire에서 첫 가청 frame 시 start 바로 앞에 발생하며 같은 response_id를 사용합니다. text, turn_count, is_initial, current_node를 포함할 수 있습니다.

기타 커스텀 이벤트

  • sohri.dialog_complete: 전체 대화 종료; 개별 response 종료와 다름
  • sohri.analysis.summary_result
  • sohri.analysis.emotion_result
  • sohri.analysis.dementia_result
  • sohri.analysis.depression_result
  • sohri.analysis.biomarker_result
  • sohri.analysis.analysis_processing, sohri.analysis.analysis_complete

오류

서버 오류는 다음 외피를 사용합니다.

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "code": "SESSION_PARAM_INVALID",
    "message": "...",
    "status": 400,
    "correlation_id": "..."
  }
}

backend status는 401 authentication_error, 403 permission_error, 429 rate_limit_error, 5xx server_error, 그 외 invalid_request_error로 분류됩니다. code, status, session_id, correlation_id, details는 가능한 경우 보존합니다.