Skip to main content
Demo numbers are fine for prototyping, but production traffic should use numbers you own through your own VoIP provider. This guide walks you through the three-step flow: test credentials → create connection → import numbers → verify.

Supported providers

Providerprovider idNotes
TwiliotwilioAPI key + secret
TelnyxtelnyxAPI key; guided onboarding available (setup_method: guided_telnyx)
SignalWiresignalwireProject id + API token
VonagevonageAPI key + secret
Manual SIPmanualAny SIP trunk — bring your own config

1. Test credentials

Before you create a persisted VoIP connection, probe the provider credentials to confirm they work. This returns a verification_evidence_id that you pass to the create step so the credentials aren’t double-charged for testing.
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
  }
}
If any check fails, response status will be fail and checks will show which step blew up. Fix the provider-side config (trunk assignment, IP allowlist, outbound authorization) and retry.

2. Create the connection

Pass the verification_evidence_id you just got:
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..."
  }'
The response is a VoipConnection object in status="connected". Credentials are stored server-side and never returned in plain text by subsequent GETs — to rotate, run a fresh test and PATCH with the new evidence.

3. List and import numbers

Inspect the numbers visible to your credentials that aren’t already in a ThunderPhone org:
curl https://api.thunderphone.com/v1/voip-connections/5/available-numbers \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
Then import the ones you want:
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"]}'
Each import becomes a phone number resource in your org with source="voip" and status="provisioning".

4. Verify each imported number

Importing registers the number as available; actually routing calls through it needs a round-trip verification (inbound dial-in check + outbound authorization probe).
curl -X POST https://api.thunderphone.com/v1/phone-numbers/{id}/verify-voip \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
On success, voip_verification_status flips to verified and the number enters status="active". On failure, the response spells out what failed — fix it (often a missing trunk assignment in the provider dashboard) and call again.

5. Assign agents and take a call

With the number verified, you assign inbound / outbound agents the same way as a demo number. See Handle inbound calls and Place outbound calls.

Rotating credentials

When a provider key rotates, re-run the test-then-update flow:
# 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"
  }'
The connection stays in place — no need to re-import numbers.

Next steps

VoIP connections reference

Every field on the connection, evidence, and import responses.

Phone numbers reference

Assign agents, transfer between orgs, release numbers.

Place outbound calls

Now that you own the number, start placing outbound.