통화 기능

걸려온 통화의 발신자 번호로 이어 걸기 (CallToken)

걸려온 통화가 이어지는 동안, 그 통화의 발신자 번호가 상대에게 표시되는 통화를 겁니다. Twilio callToken 과 같은 방식입니다.

Markdown으로 보기

걸려온 통화의 발신자 번호로 이어 걸기 (CallToken)

걸려온 통화가 이어지는 동안, 그 통화의 발신자 번호가 상대에게 표시되는 통화를 겁니다. Twilio callToken 과 같은 방식입니다.

걸려온 전화를 넘기는 착신전환입니다. 받는 쪽에는 걸려온 통화의 발신자 번호가 표시되지만, 발신번호를 그 번호로 바꿔 새로 거는 것이 아닙니다. 통신사에는 그 전화를 받은 번호(예: 070 번호)에서 전환된 통화로 전달되므로, 받는 장비에 따라 그 번호가 표시될 수도 있습니다.

1. 걸려온 통화에서 CallToken 받기

걸려온 통화의 웹훅 요청에 CallToken 이 실립니다.

CallId=CA7f3a9c0e21
From=01012345678
To=07012340001
Direction=inbound
CallToken=ctk_Q2FsbFRva2VuRXhhbXBsZTAxMjM0NTY3

2. 이어서 통화 걸기

CallToken 을 넣고, From 에는 걸려온 통화의 발신자 번호를 넣습니다. 이 값은 받는 쪽에 어떤 번호를 표시할지를 정합니다.

curl -X POST https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/calls \
  -H "Authorization: Bearer $CLAWOPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "To": "01098765432",
    "From": "01012345678",
    "CallToken": "ctk_Q2FsbFRva2VuRXhhbXBsZTAxMjM0NTY3",
    "Url": "https://my-app.com/agent-leg"
  }'

이어 건 통화는 한국AI통신 기록·과금에서 걸려온 통화와 연결되지 않은 별개의 통화입니다. 두 통화를 잇는 것은 직접 구성합니다. 예를 들어 두 통화를 각각 <Connect><Stream> 으로 같은 서버에 붙여 오디오를 주고받습니다.

3. 이어 건 통화 끊기

상대가 거절했거나 더 필요 없으면 이어 건 통화만 끊습니다. 벨이 울리는 중이면 연결 전에 취소됩니다. 걸려온 통화는 그대로 유지됩니다.

curl -X POST https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/calls/CA9b10d44d2 \
  -H "Authorization: Bearer $CLAWOPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "Status": "completed" }'

SIP 트렁크에서 쓰기

착신을 SIP 로 직접 받는 번호는 웹훅 대신 착신 INVITE 의 X-ClawOps-CallToken 헤더로 CallToken 을 받습니다. Twilio X-Twilio-CallToken 과 같은 방식입니다.

INVITE sip:07012340001@sbc.example.com SIP/2.0
From: <sip:01012345678@sip.claw-ops.com>;tag=...
X-ClawOps-CallToken: ctk_Q2FsbFRva2VuRXhhbXBsZTAxMjM0NTY3

이어 걸 때는 SIP 트렁크 발신 INVITE 의 From 에 걸려온 통화의 발신자 번호를 넣고, 받은 헤더를 그대로 실어 보냅니다.

INVITE sip:01098765432@ac1a2b3c4d.sip.claw-ops.com SIP/2.0
From: <sip:01012345678@ac1a2b3c4d.sip.claw-ops.com>;tag=...
X-ClawOps-CallToken: ctk_Q2FsbFRva2VuRXhhbXBsZTAxMjM0NTY3

LiveKit 을 쓰면 인바운드 트렁크의 headers_to_attributes 로 헤더를 참가자 속성으로 받고, CreateSIPParticipant 의 headers 로 돌려보냅니다. 속성은 벨이 울리는 단계부터 읽을 수 있습니다.

from livekit import api

# 1. 인바운드 트렁크 — X-ClawOps-CallToken 을 참가자 속성 clawops.callToken 으로
await lk.sip.create_inbound_trunk(api.CreateSIPInboundTrunkRequest(
    trunk=api.SIPInboundTrunkInfo(
        name="clawops-inbound",
        numbers=["07012340001"],
        headers_to_attributes={"X-ClawOps-CallToken": "clawops.callToken"},
    ),
))

# 2. 걸려온 통화의 참가자에서 토큰과 발신자 번호를 읽어 상담원에게 이어 걸기
caller = ...  # 방에 들어온 SIP 참가자
await lk.sip.create_sip_participant(api.CreateSIPParticipantRequest(
    sip_trunk_id=OUTBOUND_TRUNK_ID,
    sip_call_to="01098765432",
    sip_number=caller.attributes["sip.phoneNumber"],   # 걸려온 통화의 발신자 번호
    room_name=room,
    participant_identity="agent",
    headers={"X-ClawOps-CallToken": caller.attributes["clawops.callToken"]},
))

SIP 발신에서 CallToken 을 쓸 수 없으면 다음 응답으로 거절합니다.

응답Reason뜻
403—CallToken 없이 계정 번호가 아닌 From 으로 걸었음
403Q.850;cause=21;text="call token invalid"유효하지 않은 CallToken
403Q.850;cause=21;text="call token expired"걸려온 통화가 이미 끊김
403Q.850;cause=21;text="from does not match call token"From 이 걸려온 통화의 발신자 번호와 다름

사용 조건

  • CallToken 은 통신사망으로 직접 걸려온 통화이면서 발신자가 국내 번호일 때만 실립니다. 그 외에는 파라미터가 오지 않습니다.
  • 번호의 수신 처리가 Voice URL(웹훅) 일 때만 실립니다. SIP 트렁크에서는 착신을 SIP 로 직접 받는 번호에만 실립니다.
  • SIP 트렁크 자격증명에 발신번호를 지정했으면 SIP 발신에서 CallToken 을 쓸 수 없습니다.
  • 걸려온 통화가 끊기면 더는 쓸 수 없습니다.
  • 이어 건 통화도 계정의 동시통화 수에 들어갑니다. 걸려온 통화와 함께 2통이 동시에 진행됩니다.
  • REST 발신은 Url 로 거는 통화에만 쓸 수 있습니다. 수신 번호는 국내 번호만 가능합니다.

오류

상태code뜻
400call_token_invalid유효하지 않은 CallToken
400call_token_from_mismatchFrom 이 걸려온 통화의 발신자 번호와 다름
400call_token_mode_unsupportedUrl 없이 사용함
409call_token_expired걸려온 통화가 이미 끊김