Skip to main content
Sayna treats SIP support as a fully optional module. When the sip block is absent, no trunks are provisioned, webhook forwarding is skipped, and the runtime avoids emitting SIP-specific logs. Configure the section below only when you need SIP-enabled LiveKit rooms.
LiveKit SIP support requires valid LIVEKIT_API_KEY and LIVEKIT_API_SECRET values. Provisioning is idempotent—restarts never duplicate trunks or dispatch rules.

Configuration methods

YAML example

sip:
  room_prefix: "sip-"
  allowed_addresses:
    - "192.168.1.0/24"
    - "10.0.0.1"
  hooks:
    - host: "example.com"
      url: "https://webhook.example.com/events"
    - host: "another.com"
      url: "https://webhook2.example.com/events"

Environment variables

VariableRequiredDescription
SIP_ROOM_PREFIXYesPrefix every SIP-related LiveKit room must start with (alphanumeric, -, _).
SIP_ALLOWED_ADDRESSESNoComma-separated IPv4 addresses/CIDRs. Whitespace is trimmed.
SIP_HOOKS_JSONNoJSON array of { "host": "example.com", "url": "https://..." } objects. HTTPS required.
export SIP_ROOM_PREFIX="sip-"
export SIP_ALLOWED_ADDRESSES="192.168.1.0/24,10.0.0.1"
export SIP_HOOKS_JSON='[{"host":"example.com","url":"https://webhook.example.com/events"}]'

Precedence

Environment variables > YAML file > (feature disabled)
If a value is supplied via env vars it replaces the YAML counterpart entirely (lists are not merged).

Validation rules

Room prefix

  • Cannot be empty
  • Only alphanumeric, -, _
  • Examples: sip-, room_42

Allowed addresses

  • List cannot be empty when SIP block exists
  • Each entry must resemble IPv4 or CIDR (X.X.X.X/Y)
  • IPv6 not supported yet

Hooks

  • Hostnames must be unique (case-insensitive)
  • URLs must start with https://
  • Rejects insecure http:// hooks
Sayna validates the block at startup and fails fast with descriptive errors so you never run half-configured SIP resources.

Auto-provisioning workflow

When SIP config and LiveKit credentials are present, Sayna provisions everything automatically during startup.
1

Trunk creation

Creates sayna-{room_prefix}-trunk with your allowed_addresses list.
2

Dispatch rule

Creates sayna-{room_prefix}-dispatch that routes SIP calls into LiveKit rooms matching the prefix (max 3 participants by default).
3

Idempotent guards

Existing resources are reused; provisioning failures abort startup with clear logs so you can fix credentials or LiveKit connectivity issues.
Required credentials
  • LIVEKIT_API_KEY
  • LIVEKIT_API_SECRET
  • Valid sip block or env vars
Observability
INFO SIP configuration detected, provisioning LiveKit SIP trunk and dispatch rules
INFO Successfully provisioned SIP resources: trunk=sayna-sip--trunk, dispatch=sayna-sip--dispatch
Missing credentials simply log an info and skip provisioning; errors panic with the trunk/dispatch names for easier debugging. Verify resources via the LiveKit UI under SIP → Inbound Trunks / Dispatch Rules.

Runtime behavior

Room prefix matching

Any LiveKit room whose name begins with room_prefix is treated as SIP. This heuristic drives routing logic, logging, and webhook forwarding.

IP filtering

allowed_addresses becomes the allowlist enforced by LiveKit. Use it to restrict inbound SIP traffic to trusted carriers or local networks.

Webhook forwarding

When LiveKit delivers webhooks, Sayna optionally forwards the exact JSON payload to downstream HTTPS hooks based on the SIP To header:
  1. Inspect participant.attributes["sip.h.to"] (populated by LiveKit SIP).
  2. Parse the host portion (e.g., sip:[email protected]sip1.example.com).
  3. Match the host to entries in hooks (case-insensitive).
  4. Post the payload to hook.url using the shared ReqManager so pooling/limits match the rest of the platform.
  5. If no hook matches, log the omission but still respond 200 OK to LiveKit.
Forwarding runs asynchronously so LiveKit acknowledgements stay fast. With no hooks configured, the handler no-ops.

Runtime hook management

You can inspect and update the forwarding table without restarting the server:
  • GET /sip/hooks returns the cached list of { host, url } entries.
  • POST /sip/hooks replaces hooks with matching hosts (case-insensitive) and adds new ones, then persists the result. Runtime additions reuse the global hook secret; per-hook secrets are not stored.
Both endpoints respect AUTH_REQUIRED=true if you enforce auth globally. Always use unique hosts and HTTPS URLs or the request will be rejected.

Reference configurations

Single carrier
sip:
  room_prefix: "sip-"
  allowed_addresses:
    - "203.0.113.0/24"
  hooks:
    - host: "sip-provider.example.com"
      url: "https://backend.myapp.com/sip/events"
Multiple carriers
sip:
  room_prefix: "sip-"
  allowed_addresses:
    - "203.0.113.0/24"
    - "198.51.100.0/24"
  hooks:
    - host: "provider-a.example.com"
      url: "https://backend.myapp.com/sip/provider-a"
    - host: "provider-b.example.com"
      url: "https://backend.myapp.com/sip/provider-b"
Local testing
sip:
  room_prefix: "test-sip-"
  allowed_addresses:
    - "127.0.0.1"
    - "192.168.1.0/24"
  hooks:
    - host: "localhost"
      url: "https://localhost:8443/webhooks"

Accessing config in code

use sayna::config::ServerConfig;

fn main() -> anyhow::Result<()> {
    let config = ServerConfig::from_env()?;

    if let Some(sip) = &config.sip {
        tracing::info!(prefix = %sip.room_prefix, count = sip.hooks.len(), "SIP enabled");
        for hook in &sip.hooks {
            tracing::debug!(host = %hook.host, url = %hook.url, "Configured SIP hook");
        }
    } else {
        tracing::info!("SIP disabled");
    }

    Ok(())
}

Troubleshooting

ErrorCauseFix
SIP room_prefix is required when SIP configuration is presentAllowed addresses or hooks were specified without a prefix.Set SIP_ROOM_PREFIX or the YAML equivalent.
SIP hook URL must be HTTPSHook used http://.Update to https:// for every entry.
Duplicate SIP hook hostSame host appears twice (case-insensitive).Ensure each host is unique.
SIP allowed_address '...' does not look validInvalid IPv4/CIDR string.Replace with real IPv4 or x.x.x.x/y CIDR.

Future enhancements

Planned improvements include IPv6 allowlists, configurable webhook retry policies, wildcard host matching, payload signing, and per-hook credentials. Track release notes for updates.