Skip to main content

Telephony Setup

Connect real phone numbers to your Arkenos voice agents using Twilio and LiveKit SIP. Arkenos auto-provisions most of the SIP infrastructure — you just need accounts and credentials.
Telephony is optional. Browser-based voice testing via the Preview page works without any Twilio or SIP setup.

How It Works

Inbound:  Caller --> Twilio --> Elastic SIP Trunk --> LiveKit SIP --> Arkenos Agent
Outbound: Dashboard --> LiveKit SIP --> Twilio Outbound Trunk --> Phone
  • Inbound: Someone dials your Twilio number → Twilio routes via Elastic SIP Trunk to LiveKit → LiveKit dispatches the agent → agent looks up the called number and loads the right config
  • Outbound: You click “Call” in the dashboard → backend creates a LiveKit room → LiveKit dials out through Twilio → agent joins the conversation
One agent worker handles all phone numbers — it dynamically loads the right personality, voice, and instructions based on which number was called.

What’s Automated

When you buy or assign a number through the dashboard/API, Arkenos automatically:
ResourceAuto-Created
LiveKit Inbound SIP TrunkYes — “Arkenos Inbound”
LiveKit Dispatch RuleYes — routes to arkenos-agent
LiveKit Outbound SIP TrunkYes — “Arkenos Outbound” (on first outbound call)
Twilio Elastic SIP TrunkYes — “Arkenos Inbound” with LiveKit origination
Twilio ↔ Number associationYes — links your number to the SIP trunk
Twilio termination credentialsYes — for outbound calls via LiveKit
You don’t need to manually create TwiML Bins, SIP trunks, dispatch rules, or credential lists.

Setup (3 Steps)

Step 1: Create Accounts

You need two accounts:
  1. Twilio — free trial works (trial can only call verified numbers)
  2. LiveKit Cloud — free tier available
Twilio trial accounts can only make outbound calls to phone numbers you’ve verified. Go to Twilio Console → Phone Numbers → Verified Caller IDs to add your number. Also enable Geographic Permissions for the countries you want to call.

Step 2: Add API Keys via Dashboard

Open the Arkenos DashboardAPI Keys (under Build in the sidebar) and configure:
  1. LiveKit — API Key, API Secret, Server URL (from LiveKit Cloud)
  2. Twilio — Account SID, Auth Token (from Twilio Console)
Use the Test Connection button on each card to verify your credentials.
All keys are encrypted and stored in the database. No .env files needed for provider credentials. The agent service auto-fetches keys from the backend on startup.

Step 3: Buy a Number and Assign to an Agent

Start the backend, then use the dashboard or API: Option A: Via Dashboard
  1. Open the Arkenos DashboardAgents → select your agent
  2. Go to the Phone tab → Search for available numbers
  3. Buy a number — it’s automatically provisioned and assigned
Option B: Via API
# Search for available numbers
curl "http://localhost:8000/api/telephony/numbers/search?area_code=415&country=US"

# Buy and assign to an agent (auto-provisions all SIP infrastructure)
curl -X POST http://localhost:8000/api/telephony/numbers/buy \
  -H "Content-Type: application/json" \
  -H "x-user-id: your-user-id" \
  -d '{"phone_number": "+14155551234", "agent_id": "your-agent-uuid"}'
That’s it. The backend will automatically:
  1. Purchase the number on Twilio
  2. Create/reuse the LiveKit inbound SIP trunk
  3. Create/reuse the LiveKit dispatch rule
  4. Create/reuse the Twilio Elastic SIP trunk with LiveKit origination
  5. Associate the number with the trunk

Test It

Inbound Call

  1. Make sure the backend and agent services are running
  2. Call your Twilio number from any phone
  3. You should hear the agent’s greeting within a few seconds
  4. Check the agent terminal for logs:
    SIP participant detected — trunk phone number: +14155551234
    Resolved SIP call to agent: <agent-id>
    Starting session with system_prompt...
    

Outbound Call

  1. Open the dashboard → select an agent with a phone number
  2. Click Make a Call → enter a destination number → Call
  3. The backend auto-provisions the outbound trunk on the first call
  4. Your phone should ring within a few seconds
Twilio trial accounts can only place outbound calls to verified numbers. Add the destination number at Twilio Console → Phone Numbers → Verified Caller IDs.

Managing Numbers

Assign an Existing Twilio Number

If you already own a Twilio number and want to use it with Arkenos: Via Dashboard: Go to Agents → select agent → Phone tab → enter the number → Assign. Then click Test & Setup Pipeline to verify and provision the full SIP routing. Via API:
curl -X POST http://localhost:8000/api/telephony/numbers/assign \
  -H "Content-Type: application/json" \
  -H "x-user-id: your-user-id" \
  -d '{"phone_number": "+14155551234", "agent_id": "your-agent-uuid"}'

# Then provision the SIP pipeline:
curl -X POST http://localhost:8000/api/telephony/numbers/provision \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "your-agent-uuid"}'
Numbers bought through the dashboard are auto-provisioned. The Test & Setup Pipeline button is mainly needed when assigning numbers purchased directly from Twilio. If the Twilio SIP Trunk step shows a warning, clicking Test & Setup Pipeline again will attempt to resolve the Twilio SID automatically and complete the association.

Release a Number

curl -X POST http://localhost:8000/api/telephony/numbers/release \
  -H "Content-Type: application/json" \
  -H "x-user-id: your-user-id" \
  -d '{"agent_id": "your-agent-uuid"}'
This unassigns the number from the agent, removes it from LiveKit SIP routing, and disassociates it from the Twilio Elastic SIP Trunk. The number is not deleted from your Twilio account — you keep ownership and can re-assign it later.

Retry Failed Provisioning

If a number was bought but SIP provisioning failed:
curl -X POST http://localhost:8000/api/telephony/numbers/provision \
  -H "Content-Type: application/json" \
  -H "x-user-id: your-user-id" \
  -d '{"agent_id": "your-agent-uuid"}'

Troubleshooting

Most common cause: The agent service isn’t running.
  1. Start the agent: cd agent && python agent.py dev
  2. Verify in LiveKit Cloud → Telephony → Dispatch Rules that a rule exists with arkenos-agent
  3. Check the agent terminal for errors (missing API keys, etc.)
The agent is crashing on startup. Check the agent terminal for errors:
  • Missing API keys: AssemblyAI, Google (Gemini), or Resemble AI key not configured at API Keys
  • TTS credits exhausted: Check your Resemble AI balance at app.resemble.ai/hub/billing
  • Key fetch failed: Check the agent terminal for “Could not fetch keys from backend” — ensure the backend is running
Twilio isn’t routing to LiveKit:
  1. Go to Twilio Console → Elastic SIP Trunking — verify “Arkenos Inbound” trunk exists
  2. Check the trunk has an Origination URI pointing to LiveKit (e.g. sip:2w0eusjtqsa.sip.livekit.cloud)
  3. Check your phone number is associated with the trunk (under Phone Numbers tab)
  4. Check Twilio → Calls Log to see if the call attempt was received
  5. If the trunk wasn’t auto-created, try the retry endpoint: POST /api/telephony/numbers/provision
The outbound SIP trunk may not be configured correctly:
  1. Check Twilio Console → Elastic SIP Trunking — verify the trunk has a Termination SIP URI set
  2. Check LiveKit Cloud → Telephony → SIP Trunks — verify “Arkenos Outbound” exists with the correct Twilio termination address
  3. Check backend logs for Failed to provision outbound trunk errors
  4. Twilio trial accounts: The destination number must be verified at Twilio Console → Verified Caller IDs
  5. Geographic permissions: Enable the destination country at Twilio Console → Voice → Geographic Permissions
For inbound calls: The phone number isn’t assigned to an agent in the database. Go to DashboardAgentsPhone tab → assign the number.For outbound calls: The room metadata might be missing the agent ID. Check that you’re using the latest backend code — the outbound call endpoint must include metadata={"agentId": "..."} when creating the LiveKit room.
  • Check backend logs for No agent found for phone +1234... messages
  • Verify the number is in E.164 format (e.g. +14155551234)
If the buy succeeded but SIP setup failed:
  1. Check the backend logs for warning messages about provisioning
  2. Use the retry endpoint: POST /api/telephony/numbers/provision with {"agent_id": "..."}
  3. This re-runs the full provisioning chain without re-purchasing the number

Architecture Details

Auto-Provisioned Resources

All SIP resources are created with a reuse-first strategy — the system checks for existing resources by name before creating new ones:
ResourceNamePurpose
LiveKit Inbound Trunk”Arkenos Inbound”Receives SIP calls from Twilio
LiveKit Dispatch Rule”Arkenos Dispatch”Routes calls to arkenos-agent worker
LiveKit Outbound Trunk”Arkenos Outbound”Sends SIP calls to Twilio
Twilio Elastic SIP Trunk”Arkenos Inbound”Routes calls between Twilio and LiveKit
Twilio Credential List”Arkenos LiveKit”Authenticates LiveKit → Twilio for outbound

How the SIP Domain is Resolved

The SIP domain is auto-derived from your LiveKit Server URL:
LiveKit URL: wss://2w0eusjtqsa.livekit.cloud
  --> SIP domain: 2w0eusjtqsa.sip.livekit.cloud
No manual configuration needed. If your LiveKit project uses a custom domain, you can override it by saving twilio_sip_domain via the settings API.

Provisioning Code

The provisioning logic lives in backend/app/services/telephony_provisioning.py. Key functions:
  • ensure_inbound_trunk() — Creates/reuses LiveKit inbound trunk
  • ensure_dispatch_rule() — Creates/reuses dispatch rule
  • ensure_outbound_trunk() — Creates/reuses outbound trunk + Twilio credentials
  • ensure_twilio_elastic_trunk() — Creates/reuses Twilio Elastic SIP Trunk