ThunderPhone 2.0을 출시했습니다.셀프서비스로, 분당 2¢부터.출시 소식 보기

Developer cookbook

자체 번호 사용(VoIP, API)

Twilio, Telnyx, SignalWire, Vonage, Plivo 및 기타 모든 SIP 트렁크를 SIP로 연결하고, 이미 보유한 전화번호를 가져와 ThunderPhone 에이전트가 해당 번호로 전화를 받고 발신하도록 설정합니다.

승인된 ThunderPhone 번호로 발신 전화를 걸고 캠페인을 실행할 수 있습니다. 자체 VoIP 제공업체를 통해 보유한 번호를 사용하려면, 이 가이드의 연결 흐름을 따르세요: 자격 증명 테스트 → 연결 생성 → 번호 가져오기 → 확인.

지원 제공업체

제공업체provider ID참고 사항
Twiliotwilio계정 SID + 인증 토큰; Twilio 계정 또는 하위 계정당 연결 1개( Twilio 하위 계정 참조)
TelnyxtelnyxAPI 키; 가이드 온보딩 사용 가능(setup_method: guided_telnyx)
SignalWiresignalwire기본 제공업체 연결 없음; SignalWire SIP 프리셋으로 manual로 연결합니다
Vonagevonage기본 제공업체 연결 없음; Vonage SIP 프리셋으로 manual로 연결합니다
수동 SIPmanualSignalWire, Vonage 및 Plivo를 포함한 모든 SIP 트렁크입니다. 대시보드에서 해당 제공업체 타일 중 하나로 시작하더라도 연결은 여전히 manual이며 선택 사항은 sip_config.preset에 저장됩니다(signalwire, vonage 또는 plivo)

1. 자격 증명 테스트

영구 저장되는 VoIP 연결을 생성하기 전에 제공업체 자격 증명을 확인하여 작동하는지 검증하세요. 이 요청은 생성 단계에 전달할 verification_evidence_id를 반환하므로, 테스트에 대해 자격 증명 비용이 중복 청구되지 않습니다.

curl -X POST https://api.thunderphone.com/v1/voip-connections/test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider":    "telnyx",
    "credentials": { "apiKey": "KEY...", "connectionId": "123456" },
    "sip_config":  { "domain": "acme.sip.telnyx.com" }
  }'
Response
{
  "status": "pass",
  "verification_evidence_id": "b9a2...",
  "suggested_connection_name": "Telnyx: Acme Main (+15550001234)",
  "checks": {
    "credentials_valid": true,
    "inbound_reachable": true,
    "outbound_authorized": true
  }
}

검사 항목 중 하나라도 실패하면 응답 status는 fail이 되고 checks에 어느 단계에서 실패했는지가 표시됩니다. 제공업체 측 구성(트렁크 할당, IP 허용 목록, 발신 권한)을 수정한 후 다시 시도하세요.

2. 연결 생성

방금 받은 verification_evidence_id를 전달합니다.

curl -X POST https://api.thunderphone.com/v1/voip-connections \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name":         "Acme Telnyx Main",
    "provider":     "telnyx",
    "setup_method": "api_key",
    "credentials":  { "apiKey": "KEY...", "connectionId": "123456" },
    "sip_config":   { "domain": "acme.sip.telnyx.com" },
    "verification_evidence_id": "b9a2..."
  }'

응답은 status="connected" 상태의 VoipConnection 객체입니다. 자격 증명은 서버 측에 저장되며, 이후 GET 요청에서 일반 텍스트로 반환되지 않습니다. 교체하려면 새로 test를 실행하고 새 증거와 함께 PATCH 요청을 보냅니다.

Twilio 하위 계정

Twilio 연결은 보유한 Account SID 및 Auth Token에 해당하는 단일 Twilio 계정에 연결됩니다. Twilio는 각 하위 계정 내에 전화번호와 SIP 트렁크를 유지하므로 상위 계정으로 만든 연결은 상위 계정 자체의 번호만 볼 수 있으며, 기존 연결을 나중에 다른 하위 계정으로 전환할 수 없습니다.

하위 계정에 있는 번호에 연결하려면 하위 계정마다 연결을 하나씩 생성합니다. 대시보드에서 이를 자동으로 처리합니다. 활성 하위 계정이 있는 상위 계정을 연결하면 설정 대화 상자에 하위 계정 목록이 표시되고, 원하는 계정을 선택하면 ThunderPhone이 각 계정에 연결과 SIP 트렁크를 생성합니다. API에서도 동일한 흐름을 사용할 수 있습니다.

# Discover active subaccounts visible to the parent credentials
curl -X POST https://api.thunderphone.com/v1/voip-connections/twilio/subaccounts \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"credentials": {"accountSid": "ACparent...", "authToken": "..."}}'
Response
{
  "discovery_id": "7c1e...",
  "parent": { "sid": "ACparent...", "friendly_name": "Acme" },
  "subaccounts": [
    { "sid": "ACsupport...", "friendly_name": "Acme Support", "already_connected": false, "connection_id": null },
    { "sid": "ACsales...",   "friendly_name": "Acme Sales",   "already_connected": true,  "connection_id": 5 }
  ]
}
# Create a connection for each selected subaccount
curl -X POST https://api.thunderphone.com/v1/voip-connections/twilio/subaccounts/connect \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"discovery_id": "7c1e...", "subaccount_sids": ["ACsupport..."]}'

응답에는 각 하위 계정별로 한 행이 포함되며, status는 created, skipped(이미 연결됨), failed 중 하나이고 조치할 수 있는 error가 함께 제공됩니다. 행은 서로 독립적이므로 한 하위 계정에서 실패해도 다른 하위 계정이 차단되지 않습니다. 또한 discovery_id는 30분 동안 유효하므로 실패한 행을 다시 시도하면 됩니다. 하위 계정 토큰은 검색 시점에 Twilio에서 읽어 새 연결에 저장되며, API를 통해 반환되지 않습니다. 이후 각 새 연결은 수동으로 만든 연결과 동일하게 번호를 가져오고 검증합니다. 각 새 연결의 SIP 트렁크에서도 통화 전달을 활성화하려면 "enable_transfers": true를 추가합니다. 이 과정에서 실패하면 해당 연결의 test_result.transfer_enable_error에 보고되며 행 자체는 실패 처리되지 않습니다.

3. 번호 나열 및 가져오기

자격 증명에서 볼 수 있고 아직 ThunderPhone 조직에 없는 번호를 확인합니다.

curl https://api.thunderphone.com/v1/voip-connections/5/available-numbers \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

그런 다음 원하는 번호를 가져옵니다.

curl -X POST https://api.thunderphone.com/v1/voip-connections/5/import-numbers \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"numbers": ["+15550001234", "+15550009999"]}'

각 가져오기는 조직에서 number_type="voip" 및 status="provisioning"이 설정된 전화번호 리소스가 됩니다.

4. 가져온 각 번호 확인

가져오기는 번호를 사용 가능 상태로 등록하지만, 실제로 해당 번호를 통해 통화를 라우팅하려면 인증이 필요합니다. 제공업체 연결(Twilio, Telnyx)의 경우 제공업체 자격 증명과 SIP 도달 가능 여부를 다시 확인합니다. 수동 SIP 연결의 경우 먼저 루프백 자체 통화를 시도합니다. ThunderPhone이 해당 번호 에서, SIP 트렁크를 통해 짧은 확인 전화를 걸어 같은 번호로 다시 연결합니다. 이 방법으로 수신 경로를 인증하지 못하면, 해당 번호 에서, SIP 트렁크를 통해, ThunderPhone 번호 로 짧은 확인 전화를 거는 방식으로 대체합니다. 이러한 테스트는 트렁크의 사용자 이름, 비밀번호, 전송 방식, 발신 라우팅 및 수신 전달을 확인합니다. 통신사는 이러한 통화를 다른 통화와 동일하게 청구합니다.

curl -X POST https://api.thunderphone.com/v1/phone-numbers/{id}/verify-voip \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

성공하면 voip_verification_status가 verified로 변경되고 번호가 status="active" 상태가 됩니다. 자체 Telnyx 계정의 번호는 테스트 통화에 실패하거나 아직 발신이 설정되지 않았더라도 수신 통화를 계속 처리합니다. 이 경우 voip_verification_status가 unverified로 설정된 status="active" 상태가 되며, 응답에서 그 이유를 설명합니다. 실패하면 응답에 실패한 항목이 명시됩니다. 수동 트렁크의 경우 이는 이동통신사의 SIP 응답입니다. 예를 들어 "ThunderPhone의 자격 증명을 거부했습니다(SIP 401)" 또는 *"통화를 라우팅할 수 없습니다(SIP 404)"*와 같습니다. 문제를 해결한 후(자격 증명, 허용된 소스 IP, 제공업체 대시보드에서 누락된 트렁크 할당) 다시 호출합니다.

허용 목록에 등록된 수동 SIP 연결의 경우, 해당 허용된 소스 IP가 실제 수신 전화를 차단한다면 수신 통화 테스트도 실패합니다.

5. 에이전트 할당 및 통화 수신

번호가 확인되면 ThunderPhone 번호와 동일한 방식으로 인바운드/아웃바운드 에이전트를 할당합니다. 인바운드 통화 처리 및 아웃바운드 통화 연결을 참조하세요.

자격 증명 교체

제공업체 키가 교체되면 테스트 후 업데이트 흐름을 다시 실행합니다.

# 1. Test the new credentials
curl -X POST https://api.thunderphone.com/v1/voip-connections/test ...
 
# 2. PATCH the connection with the new evidence
curl -X PATCH https://api.thunderphone.com/v1/voip-connections/{id} \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "credentials": { "apiKey": "NEW_KEY..." },
    "verification_evidence_id": "fresh-evidence-id"
  }'

연결은 그대로 유지되므로 번호를 다시 가져올 필요가 없습니다.


다음 단계