엔드포인트·이벤트 참조¶
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 응답은 일반적으로 아래 순서를 사용합니다.
response.createdresponse.output_item.addedresponse.content_part.addedresponse.output_audio_transcript.deltaresponse.output_audio_transcript.doneresponse.content_part.doneresponse.output_item.doneresponse.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는 큐에 넣은 전체 길이로 자막 진행률의 분모입니다.
실제 재생이 잘렸을 때 발생합니다. 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_resultsohri.analysis.emotion_resultsohri.analysis.dementia_resultsohri.analysis.depression_resultsohri.analysis.biomarker_resultsohri.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는 가능한 경우 보존합니다.