통화 전환 결과 (Transfer)
통화 조회 응답의 transferTo·transferStatus·transferDuration·transfers[] 전체 설명. 전환이 어느 경로에서 기록되는지, VoiceML Dial 결과와 무엇이 다른지, 다단계 전환은 어떻게 읽는지 안내합니다.
통화 전환 결과 (Transfer)
통화를 상담원이나 다른 번호로 넘겼을 때, 그 전환이 어떻게 됐는지가 통화 조회 응답의
transferTo · transferStatus · transferDuration 에 남습니다.
이 필드들은 읽기 전용 관측 필드입니다. 통화 조회 요청에 값을 실어 전환을 지정할 수는 없습니다.
전환은 따로 실행하고, 그 결과가 이 필드들에 사후에 채워집니다. 전환이 없었던 통화는 전부 null
입니다.
전환을 거는 방법은 전환 걸기 를 보세요.
어디서 받나요
| 경로 | 필드 |
|---|---|
| 통화 단건 조회 | transferTo · transferStatus · transferDuration · transferHangupCauseQ850 · transferSipResponseCode · transferReasonText · transfers[] |
| 통화 목록 조회 | 위와 동일 (통화마다) — transfers[] 는 제외 |
| Status Callback webhook | TransferStatus · TransferTo · TransferMode · TransferDuration 등 (transfer 이벤트, 실시간) |
어느 전환이 여기에 기록되나요
| 전환 방법 | 위 필드에 기록되나 |
|---|---|
Voice Agent SDK 의 transfer() · 내장 도구 transfer_call | ✅ |
| 콘솔에서 만든 에이전트의 도구 → 통화 전환 | ✅ |
| SIP 단말의 REFER 전환 (blind / attended) | ✅ |
통화 전환 API POST /calls/{callId}/actions/transfer | ✅ |
VoiceML <Dial> | ❌ — 아래 참고 |
VoiceML <Dial referUrl> 로 받은 SIP REFER | ❌ — 전환이 아니라 새 흐름입니다. referUrl 참고 |
전환 걸기
진행 중인 통화를 다른 번호나 SIP 엔드포인트로 넘깁니다.
curl -X POST "https://api.claw-ops.com/v1/accounts/{accountId}/calls/{callId}/actions/transfer" \
-H "Authorization: Bearer $CLAWOPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "0212345678",
"mode": "warm",
"whisper": "예약 변경 문의입니다.",
"callerIdMode": "original",
"requestId": "req_9f3c21"
}'{ "callId": "CA...", "transferSequence": 1, "status": "initiated", "requestId": "req_9f3c21" }접수만 하고 즉시 응답합니다. 대상이 받을 때까지 기다리지 않습니다. 진행과 결과는
Status Callback 의 transfer 이벤트로 오고, 응답의
transferSequence 가 그 결과를 아래 transfers[] 에서 찾는 키입니다.
Voice Agent SDK 또는 콘솔 에이전트가 진행 중인 통화에만 사용할 수 있습니다. VoiceML
(<Dial> 등)로 진행 중인 통화는 409 TRANSFER_UNSUPPORTED 로 거절됩니다 — 그쪽은
<Dial> 로 목적지를 붙이거나, SIP 단말이 보내는 REFER 를
referUrl 로 받아 처리하세요.
주요 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| to | string | 필수 | 전환 대상. destinationType 이 pstn(기본)이면 전화번호, sip 이면 SIP URI |
| mode | string | 선택 | blind(기본) = 받으면 바로 연결 / warm = whisper 안내를 대상에게만 들려준 뒤 연결 |
| whisper | string | 선택 | warm 일 때 대상에게만 들려줄 안내. 발신자에게는 들리지 않습니다 |
| callerIdMode | string | 선택 | original 을 주면 걸려 온 전화의 발신자 번호가 대상 단말에 표시됩니다. 통신사망으로 직접 걸려 온 통화이고 그 발신자가 국내 번호인 경우에만 성립하며, 성립하지 않으면 계정 번호로 표시합니다. 받는 쪽에 표시되는 번호만 바뀌는 것이고 통화 자체는 계정 번호에서 넘기는 전환이라, 받는 장비에 따라 계정 번호가 표시될 수도 있습니다 |
| afterTransfer | string | 선택 | return(기본) = 전환이 끝나도 통화를 유지하고 에이전트가 이어받습니다 / terminate = 통화를 종료합니다 |
| requestId | string | 선택 | 같은 값의 재요청은 새 전환을 만들지 않습니다(멱등). 전환 webhook 에 RequestId 로 되돌아옵니다. 255자 이하 |
전체 파라미터와 오류 코드는 API 레퍼런스 에 있습니다.
전환이 실패하면
대상이 받지 않거나 통화 중이면 발신자와의 통화는 그대로 유지됩니다(afterTransfer 기본값
return). 다른 대상으로 다시 걸 수 있습니다.
다만 이어받을 에이전트가 전환 결과를 받을 수 없는 통화 — 콘솔에서 만든 에이전트이거나,
에이전트 연결이 끊긴 경우 — 에서는 return 이 성립하지 않아 통화가 종료됩니다. 전환이 있었다는
사실을 모르는 에이전트가 맥락 없이 대화를 잇게 되기 때문입니다. 그때는 통화 이벤트에
transfer.after_transfer_downgraded 가 남습니다.
재시도
응답이 지연돼 503 transfer_timeout 을 받은 경우, 전환은 진행 중일 수 있습니다. 같은
requestId 로 재시도하면 중복 전환 없이 먼저 접수된 전환의 transferSequence 를 돌려줍니다.
<Dial> 은 다릅니다
VoiceML 의 <Dial> 은 통화 중에 다른 목적지를 붙이는 것이지, 통화를 넘기고 빠지는 전환이
아닙니다. 그래서 위 transfer* 필드에는 아무것도 남지 않습니다. 결과는 두 가지로 받습니다.
| 무엇을 알고 싶은가 | 어디서 받나 |
|---|---|
| 연결이 어떻게 끝났나 | <Dial action> 요청의 DialCallStatus (completed / busy / no-answer / failed / canceled) |
| 상대가 언제 받았나 | <Number statusCallback> / <Sip statusCallback> 통지 (answered · completed) |
필드
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| transferTo | string | null | 선택 | 전환 대상 번호 또는 SIP URI. 전환이 없었으면 null |
| transferStatus | string | null | 선택 | 전환 결과 — completed / no-answer / busy / canceled / failed. 아래 값 표 참고 |
| transferDuration | number | null | 선택 | 전환 통화 시간(초). 대상이 받은 시점부터 그 전환이 끝날 때까지. 연결되지 못했으면 null |
| transferHangupCauseQ850 | number | null | 선택 | 전환 leg 의 통신망 Q.850 cause. 사유 미상이면 null |
| transferSipResponseCode | number | null | 선택 | 전환 leg 의 SIP 응답코드 (예: 486, 500). 사유 미상이면 null |
| transferReasonText | string | null | 선택 | 통신망이 준 원본 진단 텍스트. 자유 형식이라 분기 조건으로 쓰지 마세요 |
| transfers | array | 선택 | 전환 leg 전체 이력. 단건 조회에만 실립니다 — 목록 조회 응답에는 없습니다 |
실패 사유 세 필드(transferHangupCauseQ850 · transferSipResponseCode · transferReasonText)의
값 해석은 통화 실패 사유 와 같습니다. 다만 그 페이지의 hangupCause
는 발신자와 ClawOps 사이의 통화(메인 leg) 에 대한 값이고, 여기 transfer* 는 전환 leg 에
대한 값입니다.
transferStatus 값
| 값 | 뜻 |
|---|---|
completed | 대상이 받아 통화가 이뤄졌고 정상 종료됐습니다 |
no-answer | 벨은 울렸으나 받지 않았습니다 |
busy | 대상이 통화 중입니다 |
canceled | 연결되기 전에 취소·중단됐습니다 (걸려 온 통화의 발신자가 먼저 끊는 경우 포함) |
failed | 그 외 실패. 사유는 transferHangupCauseQ850 · transferSipResponseCode 로 봅니다 |
진행 중 상태는 이 필드에 나타나지 않습니다. transferStatus 는 끝난 전환의 결과만 담습니다.
initiated(시작) · ringing · connected(연결됨) · interrupted(통화가 비정상 종료돼 시스템이
정리) 는 transfers[].status 와 Status Callback 의 transfer 이벤트에만 존재합니다.
다단계·재시도 전환
한 통화에서 전환을 여러 번 시도할 수 있습니다 — 1번 상담원이 안 받아 2번으로 넘기는 식입니다.
이때 transfers[] 에는 시도마다 한 건씩 쌓이고, 위 transfer* 단일 필드는 그중 대표 leg 하나만
보여줍니다.
대표 leg 는 끝난 leg 중 하나입니다 — completed 인 leg 가 있으면 그것을, 없으면 sequence 가
가장 큰 leg 를 보여줍니다.
즉 세 번 시도해 마지막에 성공했다면 transferStatus 는 completed, transferTo 는 그 성공한
번호이고, 앞선 두 번의 실패는 transfers[] 에만 남습니다. 전환 시도를 빠짐없이 보려면
transfers[] 를 쓰세요.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| sequence | number | 필수 | 이 통화에서 몇 번째 전환 시도인지 (1부터) |
| to | string | null | 선택 | 전환 대상 |
| mode | string | null | 선택 | blind(즉시 전환) / warm(대상에게 whisper 안내 후 연결) / refer, refer-attended(SIP 단말이 건 REFER 전환) |
| destinationType | string | null | 선택 | pstn(통신망 번호) / sip(SIP URI 직결). 2026-07-10 이전 전환은 null |
| status | string | null | 선택 | initiated / ringing / connected / completed / failed / no-answer / busy / canceled / interrupted |
| duration | number | null | 선택 | 연결→종료 초(관측용). 연결되지 못했으면 null |
| billable | boolean | 필수 | 과금 대상 여부. 한 통화에서 최대 한 건만 true 입니다 |
| billableDuration | number | null | 선택 | 과금 대상 초 |
| hangupCauseQ850 | number | null | 선택 | 이 leg 의 통신망 Q.850 cause |
| sipResponseCode | number | null | 선택 | 이 leg 의 SIP 응답코드 |
| reasonText | string | null | 선택 | 통신망 원본 진단 텍스트 |
| startedAt | string | null | 선택 | 전환을 시작한 시각 (ISO 8601). 2026-07-10 이전 전환은 null |
| answeredAt | string | null | 선택 | 대상이 전화를 받은 시각. 응답까지 걸린 시간은 answeredAt - startedAt 입니다. 연결 전 안내(warm) 도중 끝나도 남습니다. 받지 않았으면 null (⚠️ 2026-10-13 이전 전환은 받았어도 null — 아래 참고) |
| connectedAt | string | null | 선택 | 발신자와 대상이 연결된 시각. warm 전환은 안내가 끝난 뒤 시각이라 answeredAt 보다 늦습니다. 연결되지 못했으면 null (⚠️ 2026-07-10 이전 전환은 연결됐어도 null — 아래 참고) |
| endedAt | string | null | 선택 | 이 leg 가 끝난 시각. 2026-07-10 이전 전환은 null |
| timeout | number | null | 선택 | 이 전환에 적용한 대기 한도(초). 2026-10-13 이전 전환은 null |
담당자가 받기까지 걸린 시간은 answeredAt - startedAt 입니다. connectedAt 으로 계산하면
warm 전환에서 안내 길이만큼 길게 나옵니다.
받았는지는 answeredAt 으로 판정하세요. 값이 있으면 받은 전환입니다 — 연결 전 안내 도중 끝난
warm 전환은 status 가 failed · canceled · no-answer 여도 담당자는 받았습니다. answeredAt 이
없으면 connectedAt 이 있거나 status 가 completed 일 때만 받은 것입니다.
answeredAt · timeout 은 2026-10-13 부터 기록돼, 그 이전 전환은 null 이고 안내 도중 끝난 경우를
구분할 수 없습니다.
2026-07-10 이전 전환은 leg 별 시각과 destinationType 이 없습니다. 그때는 전환 결과를 통화 한
건에 한 줄로만 기록했고, 지금의 leg 이력은 그 기록에서 되살린 것이라 startedAt · connectedAt ·
endedAt · destinationType 이 전부 null 입니다. 연결 여부를 connectedAt 으로 판정하면 그
구간을 오분류합니다 — status 와 duration 을 보세요(그 둘은 레거시 전환에도 있습니다).
transferDuration 과 transfers[].duration 은 관측값이지 과금 초가 아닙니다. 청구 기준 초는
transfers[].billableDuration 이니 duration 을 합산하지 마세요. 합산·올림 규칙은 사용량
조회 를 보세요.
예시
전환을 두 번 시도해 두 번째에 연결된 통화입니다.
{
"callId": "CAabcdef1234567890",
"status": "completed",
"from": "01012345678",
"to": "07080588491",
"direction": "inbound",
"duration": 184,
"hangupCause": "normal_clearing",
"transferTo": "0212345679",
"transferStatus": "completed",
"transferDuration": 96,
"transferHangupCauseQ850": 16,
"transferSipResponseCode": null,
"transferReasonText": null,
"transfers": [
{
"sequence": 1,
"to": "0212345678",
"mode": "blind",
"destinationType": "pstn",
"status": "no-answer",
"duration": null,
"billable": false,
"billableDuration": null,
"hangupCauseQ850": 19,
"sipResponseCode": 480,
"reasonText": null,
"startedAt": "2026-10-14T04:11:02.000Z",
"answeredAt": null,
"connectedAt": null,
"endedAt": "2026-10-14T04:11:32.000Z",
"timeout": 30
},
{
"sequence": 2,
"to": "0212345679",
"mode": "blind",
"destinationType": "pstn",
"status": "completed",
"duration": 96,
"billable": true,
"billableDuration": 96,
"hangupCauseQ850": 16,
"sipResponseCode": null,
"reasonText": null,
"startedAt": "2026-10-14T04:11:33.000Z",
"answeredAt": "2026-10-14T04:11:41.000Z",
"connectedAt": "2026-10-14T04:11:41.000Z",
"endedAt": "2026-10-14T04:13:17.000Z",
"timeout": 30
}
]
}조회는 통화 ID 로 합니다.
curl "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/calls/CAabcdef1234567890" \
-H "Authorization: Bearer sk_..."통화가 끝나기 전에 알기
위 필드는 통화가 끝난 뒤에 조회해서 봅니다. 전환이 실패했을 때 바로 다른 상담원으로 재시도하거나
안내 문자를 보내려면 Status Callback 의 transfer 이벤트를 쓰세요.
전환 한 건마다 시작 → 연결 → 종료 순으로 통지됩니다.
transfer 는 기본 이벤트에 포함되지 않습니다. 받으려면 기본 이벤트와 함께 직접 나열해야 합니다.
initiated ringing answered completed transfer