T
Telephony SOPKnowledge Base
Search
← All topics

LiveKit BYO SIP Trunk — Inbound and Outbound with SignalWire

runnable

Bridge SignalWire PSTN to LiveKit Agents via BYO SIP. Inbound: PSTN→SignalWire DID→SWML connect→LiveKit SIP domain. Outbound: LiveKit→SignalWire SIP Address→PSTN with TLS transport. Includes exact SWML, recording option, and the app-password requirement.

signalwirelivekitbyo-trunksipvoice-aiintegration
Agent trigger phrases: LiveKit SignalWire BYO SIP · LiveKit inbound trunk · LiveKit outbound trunk SignalWire · LiveKit SIP domain · LiveKit transport TLS 3 · LiveKit app password

LiveKit BYO SIP Trunk on SignalWire

LiveKit's Agents framework runs the AI conversation; SignalWire handles PSTN bridging. Same shape as the VAPI BYO setup — the differences are transport (LiveKit inbound needs ;transport=tcp, outbound trunk needs TLS) and the destination SIP domain.

LiveKit Inbound — PSTN → LiveKit

Flow:

  1. Caller dials a SignalWire DID.
  2. SignalWire executes the SWML.
  3. connect bridges to LiveKit's SIP domain.
  4. LiveKit's agent pipeline handles the call.

SWML

version: 1.0.0
sections:
  main:
    - connect:
        to: sip:%{call.to}@your-unique-SIP-domain-from-Livekit.com;transport=tcp

;transport=tcp is required for LiveKit inbound. Without it, calls may fail or behave unpredictably.

Optional — record the call

version: 1.0.0
sections:
  main:
    - record_call:
        stereo: true
        format: mp3
    - connect:
        to: sip:%{call.to}@your-unique-SIP-domain-from-Livekit.com;transport=tcp

Recordings appear in the SignalWire Dashboard Logs tab.

Setup steps

1. Create the SWML in SignalWire with your LiveKit SIP domain substituted in.

2. Assign the SWML to the DID that receives inbound calls.

3. Configure LiveKit's inbound SIP trunk:

  • Create an inbound SIP trunk in LiveKit.
  • Add your SignalWire phone number(s) in E.164 format.
  • Save.

LiveKit Outbound — LiveKit → PSTN

Flow:

  1. LiveKit initiates a SIP call to a SignalWire SIP Address.
  2. SignalWire executes the SWML at that SIP Address.
  3. SWML connect bridges to PSTN.
  4. Callee sees the call from your SignalWire DID.

SWML

version: 1.0.0
sections:
  main:
    - connect:
        answer_on_bridge: true
        from: "+1XXXXXXXXXX"
        to: "%{call.to.replace(/^sip:/i, '').replace(/@.*/, '')}"

The to expression strips sip: prefix and @domain suffix. answer_on_bridge: true is required.

Optional — outbound with recording (sub-SWML via confirm)

# record-helper.yaml
version: 1.0.0
sections:
  main:
    - record_call: { stereo: true, format: mp3 }

# main.yaml (assigned to the SIP Address)
version: 1.0.0
sections:
  main:
    - connect:
        answer_on_bridge: true
        from: "+1XXXXXXXXXX"
        to: "%{call.to.replace(/^sip:/i, '').replace(/@.*/, '')}"
        confirm: https://your.api/record-helper.yaml

Setup steps

1. Create the SWML in SignalWire with your outbound caller ID.

2. Create a SIP Address in SignalWire:

  • SIP → SIP Addresses → New.
  • Assign the SWML script.
  • Note the SIP domain (e.g., your-space.sip.signalwire.com).

3. Request the app password from SignalWire Support. Not available in the portal UI. Required for LiveKit's outbound trunk auth.

4. Create the LiveKit outbound SIP trunk:

| Field | Value | |---|---| | Address | Your SignalWire SIP domain | | Numbers | Your SignalWire DID(s) | | Auth Username | Your SignalWire phone number (E.164) | | Auth Password | App password from Support | | Transport | 3 (TLS — required) |

5. Initiate calls using LiveKit's API — create a SIP Participant, which triggers an outbound call through the trunk.

SignalWire IPs

When registering SignalWire as a BYO inbound trunk in LiveKit, all SignalWire SIP IPs should be allowed:

dig sip.signalwire.com

LiveKit's inbound trunk lets you list multiple addresses. Re-check periodically.

Troubleshooting

LiveKit inbound calls failing

  • [ ] LiveKit SIP domain is correct in the SWML.
  • [ ] ;transport=tcp appended to the SIP URI.
  • [ ] SWML assigned to the SignalWire DID (not a SIP Address).
  • [ ] SignalWire IPs allowed in LiveKit inbound trunk.
  • [ ] SignalWire Logs tab shows SWML execution.

LiveKit outbound auth errors

  • [ ] App password obtained from SignalWire Support.
  • [ ] Auth username is the E.164 phone number, not a string.
  • [ ] SIP domain matches the SignalWire SIP Address exactly.
  • [ ] Transport set to TLS (3).
  • [ ] SWML assigned to the SIP Address (not a phone number).
  • [ ] answer_on_bridge: true in the SWML.

Anti-patterns

  • Omitting ;transport=tcp on the LiveKit inbound SIP URI — silently fails.
  • Skipping TLS (transport 3) on the LiveKit outbound trunk — auth fails.
  • Using an alphanumeric auth username instead of the E.164 number.
  • Generating the app password locally — must come from SignalWire Support.
  • Assigning outbound SWML to a phone number — must be on a SIP Address.

See also