GET /api/v1/voice/calls/{id}는 통화의 상태, 통화 시간, 차감된 크레딧, 요약, 분석, 대화 기록을 돌려줍니다. 통화 목록은 GET /api/v1/voice/calls?agent_id=&status=&channel=&user_id=&page=로 가져옵니다(user_id: 웹 통화 토큰에서 온, 그 사람에 대한 내 쪽 ID). turns는 통화의 턴별 디버그 로그로, 발신자가 말을 마친 때부터 답을 듣기까지 시간이 어디에 쓰였는지 밀리초로 보여 줍니다. waitMs(발화 끝), sttMs(인식), llmMs(모델 첫 단어, 함수 호출마다 하나씩 추가), ttsMs(음성 첫 소리), firstAudioMs(답을 들은 시점)와 함께 호출된 함수, 끼어들기, 오류가 들어 있습니다. 통화 페이지에도 표시됩니다.
recording_enabled를 켜면 각 통화가 2채널 WAV로 녹음됩니다. 왼쪽은 발신자, 오른쪽은 에이전트이고, 샘플링 레이트는 통화와 같습니다. recording_consent: "announce"이면 에이전트가 먼저 녹음한다고 알리고, "ask"이면 물어보고 발신자가 동의할 때만 녹음을 보관합니다(답이 없으면 거부로 봅니다). "none"이면 아무 말도 하지 않습니다. 나와 발신자가 있는 곳의 법이 무엇을 요구하는지 확인하세요.
녹음은 EvaSay 저장소 또는 연동 → Webhook 및 알림 → 녹음 저장소에서 설정한 자체 S3 호환 버킷(AWS S3, Cloudflare R2, Google Cloud Storage, Supabase, MinIO)에 보관됩니다. 통화를 처리하는 Worker가 파일을 버킷에 직접 올립니다. 녹음이 저장되면 GET /api/v1/voice/calls/{id}가 1시간 동안 유효한 recordingUrl과 recording.status(recording, stored, declined 또는 failed)를 돌려줍니다.
DELETE /api/v1/voice/calls/{id}는 종료된 통화를 녹취록, 녹음(EvaSay 저장소 또는 고객 버킷), 분석, Webhook 전송 기록과 함께 삭제합니다. 사용한 Credits는 크레딧 내역에 남습니다. 아직 삭제할 수 없는 통화는 409(code는 call_not_deletable_yet)를 반환합니다. 통화가 진행 중이거나 방금 끝났거나, 정산 중이거나, 녹음이 업로드 중이거나, 잔액으로 결제하지 못한 Credits가 있는 경우입니다(먼저 Credits를 충전하세요).
본인이 데이터 삭제를 요청하면 POST /api/v1/voice/calls/delete-by-caller를 사용합니다. { "phone_number": "+14155550123" }를 보내면 이 번호의 모든 통화(수신은 발신 번호, 발신은 수신 번호 기준)가, { "user_id": "..." }를 보내면 토큰에 이 user_id가 있는 모든 웹 통화가 삭제됩니다. 응답은 { "deleted": 12, "kept_back": { "settling": 1 }, "more": false }입니다. 요청당 최대 200건이므로 more가 true인 동안 다시 호출하고, kept_back의 통화는 나중에 다시 삭제하세요. 번호가 수신 거부 목록에 있으면 목록에는 남습니다. 대시보드의 통화 → 발신자 데이터 삭제에서도 같은 작업을 할 수 있습니다.