사용할 API를 선택하면 연결 절차와 세션 이벤트를 확인할 수 있습니다.
SIP 트렁크를 통해 수신 및 발신 통화를 GPT-Live에 연결하세요. 통신 사업자는 OpenAI와 통화 오디오를 주고받고 백엔드는 세션 설정, 통화 제어, 비즈니스 로직을 처리합니다. SIP 시그널링에는 TLS를 사용하며, GPT-Live에서 통화 오디오를 전송하려면 SRTP가 필요합니다.
- 수신 전화 처리: 수신 전화 웹훅을 받은 다음 통화를 수락하거나 거절하세요.
- 전화 걸기: 세션을 생성해 통신 사업자를 통해 대상 번호로 전화를 거세요. 수신 전화 웹훅이나 수락 요청은 필요하지 않습니다.
백엔드에서 세션 이벤트를 받거나 명령을 보내야 할 때는 사이드밴드 연결을 사용하세요. 사이드밴드는 기존 대화에 연결되고 오디오는 SIP로 전송됩니다. 같은 웹훅이 중복 전달되거나 여러 연결에서 같은 이벤트를 수신해도 도구가 두 번 실행되지 않도록 각 작업을 하나의 핸들러에 맡기세요.
수신 전화 처리
SIP 통신 사업자에서 OpenAI 프로젝트로 수신 전화를 라우팅하세요. 백엔드는 웹훅을 받아 각 통화의 수락 여부를 결정합니다.
전화번호와 트렁크 설정
Twilio와 같은 SIP 트렁킹 사업자를 통해 전화번호를 GPT-Live에 연결하세요. 사업자에게서 전화번호를 구매한 후 다음 단계를 따르세요.
- OpenAI 설정에서 프로젝트를 여세요. 웹훅에서 웹훅 엔드포인트를 만들고
live.transport.incoming이벤트를 구독하도록 설정하세요. - 일반에서 프로젝트 ID를 확인하세요. ID는
proj_로 시작합니다. 웹훅을 만든 프로젝트의 ID를 사용하세요. - 통신 사업자의 SIP 트렁크 대상을 글로벌 SIP URI인
sip:$PROJECT_ID@sip.api.openai.com;transport=tls로 설정하거나 다음 지역별 엔드포인트 중 하나를 사용하세요.- 유럽 데이터 레지던시를 적용하려면
sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls를 사용하세요. - 인도에 물리적으로 위치한 SIP 호스트로 라우팅하려면
sip:$PROJECT_ID@sip-in.api.openai.com;transport=tls를 사용하세요.
- 유럽 데이터 레지던시를 적용하려면
이 플로우를 사용하기 전에 프로젝트에서 GPT-Live SIP 지원이 활성화되어 있고 통신 사업자의 SIP 트렁크가 해당 프로젝트로 통화를 라우팅하도록 설정되어 있는지 확인하세요.
수신 전화 알림 받기
OpenAI는 프로젝트로 걸려 온 전화를 받으면 웹훅 엔드포인트로 live.transport.incoming 이벤트를 보냅니다. 웹훅 서명을 검증하고 중복 전달을 걸러낸 다음 통화를 수락하거나 거절하세요.
웹훅은 data.type: "sip"로 SIP 통화임을 표시하고 data.session_id를 제공합니다. 모든 Live 통화 작업에 이 세션 ID를 그대로 사용하세요. data.sip_headers는 신뢰할 수 없는 발신자 메타데이터이므로 권한 확인에 사용하지 마세요.
웹훅 본문의 예시는 다음과 같습니다.
{
"object": "event",
"id": "evt_abc123",
"type": "live.transport.incoming",
"created_at": 1750287018,
"data": {
"type": "sip",
"session_id": "live_123",
"sip_headers": [
{ "name": "From", "value": "sip:+14155550123@sip.example.com" },
{ "name": "To", "value": "sip:+18005550100@sip.example.com" },
{ "name": "Call-ID", "value": "call-123@example.com" }
]
}
}created_at 필드는 초 단위의 Unix 타임스탬프입니다. 웹훅 전달 헤더에는 중복을 식별하는 webhook-id, 전달을 시도한 시각을 나타내는 webhook-timestamp, 서명 검증에 사용하는 webhook-signature가 포함됩니다. 서버 측 핸들러 구현은 웹훅 검증 예시를 참고하세요.
기존 연동에서는 사용 중단 예정(deprecated) 상태인 live.call.incoming 이벤트를 계속 받을 수 있습니다. 이 이벤트에는 data.type이 없습니다. 마이그레이션 중에는 두 이벤트 이름을 모두 처리하고, 기존 이벤트의 전달과 재시도가 모두 끝날 때까지 기존 구독을 유지하세요. 수락 대기 중인 같은 통화에 대해 Realtime 웹훅도 발생할 수 있습니다. 두 API에서 모두 수락을 시도하지 않도록 하나의 핸들러가 수락 여부를 결정하게 하세요.
통화 수락 또는 거절
애플리케이션의 권한 확인 및 라우팅 규칙을 적용하세요. 통화를 수락하려면 인증된 POST /v1/live/sessions/{session_id}/accept 요청을 보내고 본문 최상위에 session 객체를 포함하세요.
{
"session": {
"type": "live",
"model": "gpt-live-1",
"instructions": "You are answering an inbound support call.",
"audio": { "output": { "voice": "marin" } },
"delegation": { "type": "client" }
}
}신뢰할 수 있는 백엔드에서 통화 제어 요청을 보낼 때는 Authorization: Bearer $OPENAI_API_KEY를 사용하세요. 통화를 수락할 때 음성과 위임 모드를 선택하세요. 오디오 형식은 SIP에서 협상하므로 audio.format은 생략하세요. 이 예시에서는 클라이언트 위임을 선택하므로 백엔드가 위임된 작업을 처리해야 합니다. 클라이언트 및 Responses 설정은 위임과 도구를 참고하세요.
수락에 성공하면 세션 초기화가 끝난 뒤 본문이 비어 있는 200 OK 응답이 반환됩니다. 통화를 수락된 상태로 처리하기 전에 HTTP 오류를 확인하고 처리하세요.
통화를 거절하려면 POST /v1/live/sessions/{session_id}/reject 요청에 SIP 상태 코드를 포함하세요. 예를 들어 통화 중이면 { "status_code": 486 }을 보냅니다. 상태 코드는 300 이상 699 이하의 정수여야 합니다. 수락 또는 거절 중 먼저 내려진 결정이 적용되며, 뒤이어 같은 통화에 대해 결정을 시도하면 decision_already_made가 반환됩니다.
백엔드 연결
통화를 수락한 후 사이드밴드 WebSocket을 wss://api.openai.com/v1/live/sessions/{session_id}/attach에 연결하세요. 수락한 통화의 세션 ID를 사용하고 프로젝트 인증 정보와 연결 헤더도 동일하게 지정하세요. session.start를 다시 보내지 마세요.
통화 오디오는 SIP로 전송됩니다. 전사 텍스트, 위임, 도구, 명령, 반송되는 오디오는 사이드밴드에서 처리하세요. 여러 연결에서 같은 이벤트를 수신하더라도 각 사이드 이펙트는 한 곳에서만 처리하도록 하세요.
연결한 후에는 통화 제어 기능으로 키패드 톤을 보내거나 통화를 전환 또는 종료할 수 있습니다.
전화 걸기
세션 생성을 사용해 SIP 통신 사업자를 통해 전화번호로 전화를 걸 수 있습니다. 통신 사업자는 전화망 연결을 담당하고 GPT-Live는 대화를 진행합니다.
모든 조직에서 Live API를 통해 SIP 발신 기능을 사용할 수 있습니다. Realtime API의 통화 생성 엔드포인트에서는 이 기능을 사용할 수 없습니다.
트렁크 설정
TLS 시그널링과 SDES-SRTP 미디어를 지원하는 트렁크를 사용하세요. 전화를 걸기 전에 통신 사업자 설정에서 SRTP를 활성화하세요.
요청마다 다음 트렁크 설정을 포함하세요.
| 필드 | 값 |
|---|---|
transport.destination |
전화를 걸 대상 번호입니다. +14155550123과 같은 E.164 형식으로 입력하세요. SIP URI는 통화 대상으로 지원되지 않습니다. |
transport.trunk.provider_url |
sips:sip.example.com:5061과 같은 통신 사업자의 엔드포인트입니다. 기본 포트는 5061이며 ;transport=tcp는 선택 사항입니다. |
transport.trunk.auth.type |
SIP Digest 인증에는 digest를 사용합니다. |
transport.trunk.auth.username |
통신 사업자의 SIP 사용자 이름입니다. |
transport.trunk.auth.password |
통신 사업자의 SIP 비밀번호입니다. |
transport.trunk.caller_number |
통신 사업자에 보낼 발신자 전화번호입니다. E.164 형식으로 입력하세요. |
통신 사업자 엔드포인트는 TLS 시그널링을 위해 sips:를 사용해야 합니다. URL에 인증 정보, 경로, URI 헤더 또는 다른 URI 매개변수를 포함하지 마세요. 로컬 호스트 이름이나 직접 입력한 사설 또는 로컬 IP 주소는 거부됩니다. OpenAI API 키와 SIP 인증 정보는 서버에 보관하세요.
세션 생성
POST /v1/live/sessions 요청에 세션 설정과 transport.type: "sip"를 포함하세요. 세션을 생성할 때 음성과 위임 모드를 선택하세요. 오디오 형식은 SIP에서 협상하므로 audio.format은 생략하세요.
이 예시에서는 curl과 jq를 사용합니다. 서버 환경에 OPENAI_API_KEY, SIP_USERNAME, SIP_PASSWORD를 설정하고 예시의 통신 사업자 엔드포인트와 전화번호를 실제 사용할 값으로 바꾸세요. 이 예시에서는 클라이언트 위임을 선택하므로 백엔드가 위임된 작업을 처리해야 합니다.
jq -n \
--arg username "$SIP_USERNAME" \
--arg password "$SIP_PASSWORD" \
'{
"session": {
"model": "gpt-live-1",
"instructions": "Help the user schedule an appointment.",
"audio": { "output": { "voice": "marin" } },
"delegation": { "type": "client" }
},
"transport": {
"type": "sip",
"destination": "+14155550123",
"trunk": {
"provider_url": "sips:sip.example.com:5061",
"auth": {
"type": "digest",
"username": $username,
"password": $password
},
"caller_number": "+14155550100"
}
}
}' | curl https://api.openai.com/v1/live/sessions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @-세션 초기화가 끝나면 다음과 같은 본문과 함께 200 OK가 반환됩니다.
{
"session": { "id": "live_123" },
"transport": { "type": "sip" }
}이 응답만으로는 상대방이 전화를 받았는지 알 수 없습니다. 응답에는 SDP나 트렁크 인증 정보가 포함되지 않습니다. 사이드밴드 연결과 통화 제어에는 session.id를 그대로 사용하세요. 발신 통화에는 수신 전화 웹훅이나 수락 요청이 필요하지 않습니다.
통화 상태 모니터링 및 종료
OpenAI API 키를 사용해 백엔드를 wss://api.openai.com/v1/live/sessions/{session_id}/attach에 연결하세요. session.start를 다시 보내지 마세요. 사이드밴드 연결로는 대화 이벤트, 위임된 작업, 통화 진행 상태를 전달하고 SIP로는 오디오를 전송합니다.
| 이벤트 | 의미 |
|---|---|
transport.ringing |
통신 사업자가 호출 중 상태 또는 얼리 미디어를 보고했습니다. |
transport.answered |
상대방이 전화를 받았고 미디어 연결이 설정되었습니다. |
transport.failed |
세션 초기화 후 통화 연결에 실패했습니다. error.code와 error.message를 확인하세요. |
각 통화 진행 이벤트에는 event_id와 session_id가 포함됩니다. 세션 생성 직후 사이드밴드에 연결하세요. 사이드밴드는 직전 3초 동안의 이벤트만 다시 전달하므로 늦게 연결하면 초기 통화 진행 이벤트를 놓칠 수 있습니다. 다시 전달되는 이벤트는 원래 이벤트 ID를 유지합니다. event_id를 기준으로 중복 이벤트를 걸러내세요.
연결한 후에는 통화 제어 기능으로 키패드 톤을 보내거나 통화를 전환 또는 종료할 수 있습니다. session.closed 이벤트와 최종 사용량을 받을 때까지 사이드밴드 연결을 유지하세요. 자세한 내용은 사용량과 정상 종료를 참고하세요.
제한 및 오류 처리
상대방이 전화를 받을 때까지 호출을 유지할 수 있는 시간은 최대 3분이며, 연결된 통화는 최대 2시간까지 지속할 수 있습니다. 세션 생성 요청에서 이 제한을 변경할 수 없습니다.
세션 설정이 유효하지 않으면 생성 요청에 대한 응답으로 오류가 반환됩니다. 전송 연결 설정에 실패하면 502가 반환될 수 있으며, 초기화 시간이 초과되면 504가 반환됩니다. 생성에 성공한 후에는 transport.failed 이벤트를 모니터링해 비동기 연결 설정 실패를 확인하세요.
진행 중인 통화 관리
다음 제어 기능은 수신 및 발신 SIP 통화에 모두 적용됩니다.
키패드 이벤트 송수신
발신자가 키를 누르면 사이드밴드에서 transport.dtmf.received 이벤트를 받습니다. SIP 트렁크로 DTMF 톤을 보내려면 사이드밴드 WebSocket을 통해 transport.dtmf.send 클라이언트 이벤트를 보내세요. 톤 전송에 성공하면 사이드밴드에서 transport.dtmf.sent 이벤트를 받습니다.
event_id를 지정하면 알림의 client_event_id에 해당 값이 포함됩니다. 전송에 실패하면 error 이벤트가 반환되며, 이 이벤트에는 error.client_event_id가 포함됩니다.
통화 전환 또는 종료
통화를 전환하려면 POST /v1/live/sessions/{session_id}/refer 요청에 { "target_uri": "sip:agent@example.com" }과 같이 전환 대상을 지정하세요. 통화를 종료하려면 본문 없이 POST /v1/live/sessions/{session_id}/hangup 요청을 보내세요. 두 요청 모두 성공하면 본문이 비어 있는 200 OK 응답을 반환합니다.
전환 대상은 SIP Refer-To 헤더의 값이 됩니다. tel:+14155550123과 같은 전화번호 URI나 sip:agent@example.com과 같은 SIP URI를 사용할 수 있습니다. 나머지 통화 전환 절차는 통신 사업자가 처리합니다.
session.closed 이벤트로 최종 사용량을 받을 때까지 사이드밴드 연결을 유지하세요. 사용량 보고 및 종료 사유는 사용량과 정상 종료를 참고하세요.
SIP 네트워크 요구 사항
GPT-Live SIP 통화는 시그널링과 미디어에 별도의 네트워크 경로를 사용합니다. 두 경로의 트래픽을 모두 허용하도록 네트워크를 설정하세요.
- SIP 시그널링:
sip.api.openai.com과sip-eu.api.openai.com은 GeoIP 기반으로 라우팅되는 엔드포인트입니다. 인도 엔드포인트인sip-in.api.openai.com은 SIP 트래픽을 인도에 있는 SIP 호스트로 라우팅합니다. 선택한 엔드포인트를 DNS로 조회했을 때 반환되는 주소의5061포트로 나가는 TCP/TLS 트래픽을 허용하세요. - SRTP 미디어: API는 협상된 SDP에 별도의 미디어 IP 주소와 UDP 포트를 지정합니다. 다음 CIDR 대역과 UDP로 주고받는 SRTP 트래픽을 양방향으로 허용하세요.
13.79.45.80/2820.204.17.112/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
GPT-Live 다음 단계
- 프롬프트 작성 가이드를 참고해 음성 에이전트의 지침을 작성하세요.
- 웹훅과 서버 측 제어를 사용해 백엔드에서 세션을 관리하세요.
- 위임과 도구를 사용해 음성을 추론 및 도구 실행을 담당하는 백엔드에 연결하세요.
- 세션 관리를 참고해 전사 텍스트, 세션 상태, 세션 종료를 처리하세요.
- 지연 시간과 비용에서 지연 시간과 사용량을 알아보세요.
- GPT-Live 파트너 연동에서 통신 사업자별 설정 가이드와 예시를 확인하세요.
SIP는 인터넷으로 전화를 걸 때 사용하는 프로토콜입니다. SIP와 Realtime API를 사용하면 수신 전화를 API로 라우팅할 수 있습니다.
개요
전화번호를 Realtime API에 연결하려면 Twilio와 같은 SIP 트렁킹 사업자를 이용하세요. SIP 트렁킹은 전화 통화를 IP 트래픽으로 변환하는 서비스입니다. SIP 트렁킹 사업자에게서 전화번호를 구매한 후 아래 절차를 따르세요.
먼저 수신 전화용 웹훅을 만드세요. platform.openai.com 설정 > 프로젝트 > 웹훅 메뉴에서 만들 수 있습니다. 그런 다음 웹훅을 설정한 프로젝트의 ID를 사용해 SIP 트렁크 대상을 OpenAI의 글로벌 SIP URI인 sip:$PROJECT_ID@sip.api.openai.com;transport=tls로 설정하세요. 지역별로 라우팅하려면 다음 엔드포인트 중 하나를 사용하세요.
- 유럽 데이터 레지던시를 적용하려면
sip:$PROJECT_ID@sip-eu.api.openai.com;transport=tls를 사용하세요. - 인도에 물리적으로 위치한 SIP 호스트로 라우팅하려면
sip:$PROJECT_ID@sip-in.api.openai.com;transport=tls를 사용하세요.
$PROJECT_ID 값은 설정 > 프로젝트 > 일반 메뉴에서 확인할 수 있습니다. 이 페이지에 표시되는 프로젝트 ID는 proj_로 시작합니다.
OpenAI가 프로젝트에 연결된 SIP 트래픽을 받으면 웹훅으로 알림을 보냅니다. 이때 전달되는 realtime.call.incoming 이벤트의 예시는 다음과 같습니다.
POST https://my_website.com/webhook_endpoint
user-agent: OpenAI/1.0 (+https://platform.openai.com/docs/webhooks)
content-type: application/json
webhook-id: wh_685342e6c53c8190a1be43f081506c52 # unique id for idempotency
webhook-timestamp: 1750287078 # timestamp of delivery attempt
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= # signature to verify authenticity from OpenAI
{
"object": "event",
"id": "evt_685343a1381c819085d44c354e1b330e",
"type": "realtime.call.incoming",
"created_at": 1750287018, // Unix timestamp
"data": {
"call_id": "some_unique_id",
"sip_headers": [
{ "name": "From", "value": "sip:+142555512112@sip.example.com" },
{ "name": "To", "value": "sip:+18005551212@sip.example.com" },
{ "name": "Call-ID", "value": "03782086-4ce9-44bf-8b0d-4e303d2cc590"}
]
}
}웹훅에 포함된 call_id 값으로 통화를 수락하거나 거절할 수 있습니다. 수락할 때는 Realtime API 세션에 필요한 지침, 음성 등의 설정을 제공합니다. 세션이 설정되면 다른 세션과 마찬가지로 WebSocket을 연결해 모니터링할 수 있습니다. 아래에서는 통화 수락, 거절, 모니터링, 전환, 종료에 사용하는 API를 설명합니다.
통화 수락
통화 수락 엔드포인트를 사용해 수신 전화를 수락하고 전화를 받을 실시간 세션을 설정하세요. create client secret 요청과 동일한 매개변수를 보내세요. 통화를 모델에 연결하기 전에 실시간 모델, 음성, 도구 또는 지침을 설정해야 합니다.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/accept" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "realtime",
"model": "gpt-realtime-2.1",
"instructions": "You are Alex, a friendly concierge for Example Corp."
}'요청 경로에 포함할 call_id는 realtime.call.incoming 웹훅에서 가져오세요. 모든 요청에는 위 예시의 Authorization 헤더가 필요합니다. SIP 통화 구간이 호출 중 상태가 되고 실시간 세션 설정이 진행되면 엔드포인트가 200 OK를 반환합니다.
통화 거절
지원되지 않는 국가 코드에서 걸려 온 전화처럼 수신 전화를 처리하지 않으려는 경우 통화 거절 엔드포인트를 사용해 통화 요청을 거절하세요. 경로 매개변수로 call_id를 지정하세요. 통신 사업자에 보낼 응답을 지정하려면 JSON 본문에 선택 사항인 SIP status_code를 포함하세요. 예를 들어 486은 ‘통화 중’을 나타냅니다.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/reject" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status_code": 486}'상태 코드를 지정하지 않으면 API는 기본값으로 603 Decline을 사용합니다. 요청에 성공하면 OpenAI가 SIP 응답을 전달한 후 200 OK를 반환합니다.
통화 이벤트 모니터링
통화를 수락한 후 같은 세션에 WebSocket을 연결해 이벤트를 스트리밍하고 실시간 명령을 보내세요. call_id 매개변수로 기존 통화에 연결할 때는 model 인수를 사용하지 않습니다. 모델은 이미 accept 엔드포인트에서 설정했기 때문입니다.
WebSocket 요청
GET wss://api.openai.com/v1/realtime?call_id={call_id}
쿼리 매개변수
| 매개변수 | 유형 | 설명 |
|---|---|---|
call_id |
문자열 | realtime.call.incoming 웹훅에서 받은 식별자입니다. |
헤더
Authorization: Bearer YOUR_API_KEY
이 WebSocket은 다른 Realtime API 연결과 동일하게 동작합니다. response.create 등의 클라이언트 이벤트를 보내 통화를 제어하고, 서버 이벤트를 수신해 진행 상태를 추적하세요. 자세한 내용은 웹훅과 서버 측 제어를 참고하세요.
import WebSocket from "ws";
const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";
const ws = new WebSocket(`wss://api.openai.com/v1/realtime?call_id=${callId}`, {
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
});
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "response.create",
})
);
});통화 전환
통화 전환 엔드포인트를 사용해 진행 중인 통화를 전환하세요. call_id와 함께 target_uri를 지정하세요. 이 URI는 SIP Refer-To 헤더에 들어가며, 예를 들어 tel:+14155550123 또는 sip:agent@example.com을 사용할 수 있습니다.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/refer" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target_uri": "tel:+14155550123"}'OpenAI는 REFER 요청을 SIP 통신 사업자에 전달한 뒤 200 OK를 반환합니다. 이후 발신자의 통화 플로우는 다운스트림 시스템이 처리합니다.
통화 종료
애플리케이션에서 발신자와의 연결을 끊어야 할 때는 통화 종료 엔드포인트로 세션을 종료하세요. 이 엔드포인트로 SIP 및 WebRTC 실시간 세션을 모두 종료할 수 있습니다.
curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
-H "Authorization: Bearer $OPENAI_API_KEY"API는 통화 연결 해제를 시작하면 200 OK를 반환합니다.
SIP 시그널링 및 미디어 IP 범위
Realtime SIP 통화는 시그널링과 미디어에 별도의 네트워크 경로를 사용합니다. 통화가 정상적으로 작동하도록 아래 설명에 따라 시그널링 및 미디어 트래픽을 허용하세요.
SIP 시그널링
sip.api.openai.com과 sip-eu.api.openai.com은 GeoIP 기반으로 라우팅되는 엔드포인트입니다. 인도 엔드포인트인 sip-in.api.openai.com은 SIP 트래픽을 인도에 있는 SIP 호스트로 라우팅합니다. 선택한 엔드포인트를 DNS로 조회했을 때 반환되는 주소의 5061 포트로 나가는 TCP/TLS 트래픽을 네트워크에서 허용해야 합니다.
SRTP 미디어
API는 협상된 SDP에 별도의 미디어 IP 주소와 UDP 포트를 지정합니다. 네트워크에서 다음 CIDR 대역과 UDP로 주고받는 SRTP 트래픽을 양방향으로 허용해야 합니다.
13.79.45.80/2820.204.17.112/2823.98.140.64/2840.67.149.176/2840.83.204.240/28
서버 예시
다음은 realtime.call.incoming 핸들러의 예시입니다. 이 핸들러는 통화를 수락한 다음 Realtime API에서 받는 모든 이벤트를 로그에 기록합니다.
Ruby 예시를 실행하려면 OPENAI_API_KEY와 OPENAI_WEBHOOK_SECRET 환경 변수를 설정한 다음 gem install openai webrick async-websocket 명령으로 필요한 종속성을 설치하세요.
from flask import Flask, request, Response, jsonify, make_response
from openai import OpenAI, InvalidWebhookSignatureError
import asyncio
import json
import os
import requests
import time
import threading
import websockets
app = Flask(__name__)
client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
AUTH_HEADER = {"Authorization": "Bearer " + os.environ["OPENAI_API_KEY"]}
call_accept = {
"type": "realtime",
"instructions": "You are a support agent.",
"model": "gpt-realtime-2.1",
}
response_create = {
"type": "response.create",
"response": {
"instructions": ("Say to the user 'Thank you for calling, how can I help you'")
},
}
async def websocket_task(call_id):
try:
async with websockets.connect(
"wss://api.openai.com/v1/realtime?call_id=" + call_id,
additional_headers=AUTH_HEADER,
) as websocket:
await websocket.send(json.dumps(response_create))
while True:
response = await websocket.recv()
print(f"Received from WebSocket: {response}")
except Exception as e:
print(f"WebSocket error: {e}")
@app.route("/", methods=["POST"])
def webhook():
try:
event = client.webhooks.unwrap(request.data, request.headers)
except (InvalidWebhookSignatureError, ValueError) as e:
print("Invalid signature", e)
return Response("Invalid signature", status=400)
if event.type == "realtime.call.incoming":
requests.post(
"https://api.openai.com/v1/realtime/calls/"
+ event.data.call_id
+ "/accept",
headers={**AUTH_HEADER, "Content-Type": "application/json"},
json=call_accept,
).raise_for_status()
threading.Thread(
target=lambda: asyncio.run(websocket_task(event.data.call_id)),
daemon=True,
).start()
return Response(status=200)
if __name__ == "__main__":
app.run(port=8000)다음 단계
SIP 연결을 마쳤다면 왼쪽 탐색 메뉴나 아래 문서를 참고해 실시간 애플리케이션을 개발하세요.