Live-Erkenntnisse 2026-05-13

sipgate basic / team „SIP-Konto” ist NICHT LiveKit-trunk-tauglich. Sipgates SIP-Konten im basic/team-Tarif sind klassische Endgeraet-Accounts (Client REGISTERed sich, sipgate INVITEt das Geraet bei Anruf). LiveKit Cloud Inbound erwartet hingegen das Trunk-Pattern (INVITE landet direkt am LiveKit-FQDN, kein REGISTER-Hop). Resultat: SIP-Konto-Credentials in den LiveKit-Inbound-Trunk zu legen schlaegt fehl — LiveKit kann sich nicht bei sipgate registrieren, und sipgate schickt ohne registrierten Client keine Calls an LiveKit. Befund verifiziert beim Versuch, Marvins bestehende sipgate-Nummern (0251er + 01579er) anzubinden.

Pfade die sipgate-basic-tauglich machen wuerden:

  • sipgate trunking 2.0 dazubuchen (eigener Tarif, paar Tage KYC, ~9.95 EUR/Mo plus neue Geo-Nummer; bestehende Nummer portierbar BNetzA 2-4 Wochen)
  • Eigene SIP-Proxy hosten (Asterisk/FreeSWITCH in Docker), die bei sipgate REGISTERed und INVITEs an LiveKit forwarded — 1-2 Tage Engineering, aber DSGVO-clean

Pragmatische Alternative fuer POC: Telnyx. API-first, vollautomatisch von Claude aus konfigurierbar (Account-Sign-up + Funding bleibt manuell), US-Nummern 1 upfront + $1/Mo. Konkretes Setup siehe Abschnitt „Schritt-fuer-Schritt mit Telnyx (verifiziert 2026-05-13)” unten.

Twilio-Account-Recovery: Marvins bestehender Twilio-Account haengt an einer alten Handynummer ohne Recovery-Code. Recovery via Support-Ticket dauert Stunden bis Tage. Fuer heute-Abend-Pfade blockt das den Twilio-Weg.

Phone-Anbindung — SIP-Trunk fuer den LiveKit-Worker

Vom Browser-POC zu „ruf hier an und sprich mit dem Bot”. Der bestehende Worker (agent.py) muss nicht angefasst werden — LiveKit Cloud uebernimmt Sample-Rate-Conversion (SIP 8 kHz ↔ Worker 48 kHz). Wir brauchen nur drei Dinge:

  1. DE-Nummer + SIP-Trunk bei einem Telco-Provider
  2. Inbound Trunk in LiveKit registrieren (Provider-IPs + Auth)
  3. Dispatch Rule die eingehende Calls auf einen Room routet — der Worker matched dort genauso wie heute beim Browser-Call

Vendor-Optionen fuer die Nummer

Twilio Elastic SIP TrunkingTelnyx SIP Trunkingsipgate Trunking Basic
DE-Geo-Nummer/Monat~$1.15~$1.00ab 9.95 EUR (Paket)
Eingehende Min$0.022$0.008inklusiv
AuthIP-Whitelist + DigestIP-Whitelist + DigestDigest
LiveKit-Dokuoffiziell verifiziertoffiziell verifiziertnicht offiziell, generisch SIP
DPA / AVVStandard-DPA (US, EU-SCC)DPA + EU-Region-RoutingDPA, Hosting DE
Free-Tier$15 Trial-Credit$2 Trial-Creditnein
OnboardingSelfservice, sofort liveSelfservice + KYC Email-BestaetigungVertrag + KYC, paar Tage

Empfehlung:

  • Twilio fuer den ersten POC-Anruf — $15 Trial reicht fuer 600+ Min Test, beste LiveKit-Doku, in 30 Min live. Pragmatisch wenn wir morgen mit Aylem-Inhaber demoen wollen.
  • sipgate fuer Aylem-Live-Betrieb — wenn der Bot beim Restaurant fest am Hauptanschluss haengt, ist DE-Hosting + EUR-Tarif + voll-DSGVO sauberer. Wechsel ist 5-Minuten-Konfig-Aenderung auf der LiveKit-Seite, kein Code-Change.

Telnyx ist die Mitte — guenstiger pro Minute als Twilio, EU-Routing, aber kein DE-Hosting.

Schritt-fuer-Schritt mit Twilio (Trial-Setup)

1. Twilio-Account + DE-Nummer

  • Anmelden: https://www.twilio.com/try-twilio (Trial = $15 Credit)
  • Console: https://console.twilio.com
  • Nummer kaufen: Console → Phone Numbers → Buy a Number → Country = Germany, Capabilities = Voice. Lokale Vorwahl waehlen (z.B. 02381 fuer Hamm gibt es selten in Twilio, sonst 030/Berlin oder eine DE-Mobilnummer mit +49 15).
  • Notiere die Nummer im E.164-Format, z.B. +4915123456789.

2. SIP-Trunk bei Twilio anlegen

  • Console → Elastic SIP Trunking → Trunks → Create Trunk
  • Friendly Name: aylem-livekit
  • Sektion Termination (egal fuer reines Inbound — leer lassen)
  • Sektion Origination → Add Origination URI:
    • URI: sip:<dein-livekit-domain>.sip.livekit.cloud (LiveKit Cloud zeigt die SIP-URI an unter Project Settings → SIP)
    • Priority 10, Weight 10, Enabled
  • Sektion Numbers → Add Existing → die gekaufte Nummer assignen
  • Sektion Authentication:
    • Option A (einfach): Acl = LiveKit-Cloud-IPs erlauben (LiveKit-Doku listet die Inbound-Source-IPs unter https://docs.livekit.io/sip/cloud-provider/)
    • Option B (sicherer): Credentials = Digest-User+Passwort generieren, in LiveKit-Trunk hinterlegen
  • Save

3. Inbound Trunk in LiveKit anlegen

LiveKit Cloud Console oeffnen: https://cloud.livekit.io → Project waehlen → SIP → Inbound Trunks → Create Trunk

Oder per CLI (sauberer fuer Doku):

# lk = livekit-cli, install via: brew install livekit/tap/livekit-cli
lk sip inbound create --request - <<'JSON'
{
  "trunk": {
    "name": "twilio-aylem",
    "numbers": ["+4915123456789"],
    "auth_username": "livekit",
    "auth_password": "<digest-password-aus-twilio>"
  }
}
JSON

Antwort enthaelt sip_trunk_id (Format ST_xxx). Notieren.

4. Dispatch Rule fuer den Worker

lk sip dispatch create --request - <<'JSON'
{
  "trunk_ids": ["ST_xxx"],
  "rule": {
    "dispatch_rule_individual": {
      "room_prefix": "aylem-phone-"
    }
  },
  "hide_phone_number": false
}
JSON

dispatch_rule_individual legt pro Anruf einen Room mit Prefix aylem-phone- an — Worker matched automatisch, weil er auf alle Rooms im Project hoert (default agent dispatch). Wenn wir Multi-Tenant brauchen, koennen wir spaeter verschiedene Dispatch-Rules pro Trunk anlegen.

5. Test-Anruf

  • Worker lokal laufen lassen: python agent.py dev (wie bisher)
  • Beliebiges Handy → +4915123456789 anrufen
  • Erwartung: Tuet → Greeting der Aylem-Voice innerhalb 1-2s → freier Dialog

Twilio-Console hat unter Monitor → Logs → Voice eine Liste der Anrufe inkl. SIP-Status — wenn was nicht klappt, zeigt das den Failure-Reason.

Latenz-Erwartung

Beim Phone-Pfad addiert sich die PSTN-Latenz (~50-150 ms vom Handy bis Twilio) oben drauf. Der heutige Browser-E2E von 1-1.5s sollte aufs Phone ~1.5-2s werden. Wenn das im Test laenger als 3s wird:

  • min_endpointing_delay in agent.py erhoehen (0.2 → 0.4) — verhindert dass der Worker schon antwortet waehrend der Anrufer noch nachdenkt
  • Bedrock-Region im SDK pruefen — eu-central-1 ist richtig fuer Hamm-Calls; bei Provider-Hops auch sicher dass der LiveKit-Cloud-Endpoint EU ist
  • Cartesia voice_engine ggf. auf phone-Profile umstellen (Sonic 2 hat eine separate Phone-optimierte Inferenz)

Wenn du auf sipgate wechseln willst

Nach Twilio-Demo, fuer den Aylem-Live-Betrieb:

  1. sipgate Trunking-Account: https://app.sipgatebasic.de → Tarif „sipgate trunking basic” buchen (9.95 EUR/Mo, inkl. eine Geo-DE-Nummer)
  2. Im sipgate Webclient: Telefonanlage → SIP-Konten → Neu → Auth-Username + Passwort generieren
  3. sipgate SIP-Server = sipconnect.sipgate.de
  4. In Twilio: Trunk pausieren (oder Nummer rausnehmen)
  5. In LiveKit: einen neuen Inbound Trunk mit den sipgate-Credentials anlegen, Dispatch Rule auf die neue Trunk-ID umschwenken (oder beide Trunks im trunk_ids-Array lassen — dann gehen Anrufe von beiden Nummern an den gleichen Worker)
  6. Nummer portieren (optional, dauert 2-4 Wochen bei der BNetzA-Mitschleppe) oder neue Nummer claimen

Kosten-Schaetzung Aylem-Live (sipgate, 30 Min/Tag)

PostenMonat
sipgate trunking basic + 1 Nummer9.95 EUR
LiveKit Cloud (30 Min/Tag = 900 Min/Mo, Free-Tier deckt 10k Min)0 EUR
Deepgram nova-3 (900 Min × $0.0043/Min)~$4
Bedrock Claude Haiku 4.5 EU (~20 Turns/Call × 30 Calls/Tag = ~600 Turns/Tag × 30 = 18k Turns/Mo × ~$0.0003)~$5
Cartesia Sonic 2 (900 Min × $0.025/Min nach Free-Credit)~$22
Summe~30 EUR (zzgl. Gespraechsminuten ab Trunk-Tarif)

Bei hoeherem Volumen: Cartesia ist der teuerste Posten und der einzige der linear mit Anrufdauer skaliert. Alternative-TTS-Optionen siehe ADR llm-hosting-eu-optionen (falls dort schon aufgeschrieben — sonst beim Vendor-Wechsel ergaenzen).

Open Loops nach diesem Setup

  • Outbound-Calls (Bot ruft an, z.B. Bestaetigungs-Call beim Restaurant nach Reservierung) — LiveKit kann das auch, anderer SIP-Trunk-Modus
  • Call-Recording fuer Eval (DSGVO §9 — Anrufer-Ansage am Anfang Pflicht)
  • Number-Pool fuer Multi-Tenant — pro Kunde eigene Nummer, gleicher Worker
  • AWS-Hosting des Workers (Fargate eu-central-1) statt Mac in Hamm — die Hop-Latenz vom heimischen DSL ist ein realer Faktor

Schritt-fuer-Schritt mit Telnyx (verifiziert 2026-05-13)

Live durchgefuehrt — Setup steht im Vault unter .env.local. Credentials NICHT committen, sind dort lokal mit TELNYX_*-Praefix abgelegt.

1. Telnyx-Account + API-Key (manuell)

2. FQDN-Connection anlegen (oder bestehende umkonfigurieren)

Trial erlaubt nur eine FQDN-Connection pro Account — beim Sign-up wird typisch schon eine „TEST”-Connection angelegt. Wir nehmen die wieder.

# Existing Connections listen
curl -s -H "Authorization: Bearer $TELNYX_API_KEY" \
  https://api.telnyx.com/v2/connections | jq
 
# Connection auf TCP + LiveKit-tauglich umbenennen
curl -X PATCH -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.telnyx.com/v2/fqdn_connections/$TELNYX_FQDN_CONNECTION_ID" \
  -d '{"connection_name":"aylem-livekit","transport_protocol":"TCP","active":true}'

3. LiveKit-FQDN dazuhaengen

curl -X POST -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  https://api.telnyx.com/v2/fqdns \
  -d '{
    "connection_id":"'$TELNYX_FQDN_CONNECTION_ID'",
    "fqdn":"<dein-livekit-subdomain>.sip.livekit.cloud",
    "port":5060,
    "dns_record_type":"a"
  }'

LiveKit-Subdomain steht im Cloud-Dashboard unter Project Settings → SIP (z.B. test-t1lmm63r.sip.livekit.cloud).

4. Nummer kaufen oder bestehende assignen

# Verfuegbare Nummern listen
curl -s -H "Authorization: Bearer $TELNYX_API_KEY" \
  "https://api.telnyx.com/v2/available_phone_numbers?filter%5Bcountry_code%5D=DE&filter%5Blimit%5D=10" | jq
 
# Nummer kaufen (Trial-Limit: 1 number_order — bei Sign-up wird oft schon
# eine zugewiesen, dann nur ASSIGNen statt kaufen)
curl -X POST -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  https://api.telnyx.com/v2/number_orders \
  -d '{"phone_numbers":[{"phone_number":"+49209..."}],
       "connection_id":"'$TELNYX_FQDN_CONNECTION_ID'"}'
 
# Bestehende Nummer dem Trunk assignen (wenn schon im Account)
curl -X PATCH -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  "https://api.telnyx.com/v2/phone_numbers/$NUMBER_ID" \
  -d '{"connection_id":"'$TELNYX_FQDN_CONNECTION_ID'"}'

5. LiveKit-Seite (analog Twilio)

cd intern/projekte/telefon-assistent-aws/livekit-agent && set -a && source .env.local && set +a
 
# Inbound Trunk mit der Telnyx-Nummer
lk sip inbound create --name "telnyx-aylem" --numbers "+49209..."
# returnt SIPTrunkID ST_xxx
 
# Dispatch Rule fuer Worker-Routing
lk sip dispatch create --name "aylem-phone-dispatch" \
  --trunks "ST_xxx" --individual "aylem-phone-"

6. Worker starten + Test

.venv/bin/python agent.py dev > /tmp/livekit-worker.log 2>&1 &
# warten bis "registered worker  region: ..." im Log

Anrufen, Bot meldet sich. Bei Live-Test 2026-05-13 wurde Setup-Schritte 1-5 erfolgreich verifiziert, der finale Test-Anruf wurde aus Kostengruenden verschoben (US-Nummer +1 838 206 8690 → Anruf aus DE bedeutet Mobilfunk-Auslandsgebuehr ~30 Cent/Min beim Mobilfunkanbieter).

Auth-Modell-Hinweis

LiveKit Inbound Trunks haben Felder auth_username + auth_passwordaber nur fuer den umgekehrten Fall (Provider authentifiziert sich bei LiveKit). Bei Telnyx-FQDN-Connections wird per FQDN-Routing direkt geINVITEt, keine Auth-Credentials noetig. Fuer Production-Hardening: allowed_addresses mit Telnyx-Source-IPs auf dem LiveKit-Trunk hinterlegen (verhindert dass beliebige IPs Calls auf die Nummer schicken).

Open Loops nach diesem Setup

  • Outbound-Calls (Bot ruft an, z.B. Bestaetigungs-Call beim Restaurant nach Reservierung) — LiveKit kann das auch, anderer SIP-Trunk-Modus
  • Call-Recording fuer Eval (DSGVO §9 — Anrufer-Ansage am Anfang Pflicht)
  • Number-Pool fuer Multi-Tenant — pro Kunde eigene Nummer, gleicher Worker
  • AWS-Hosting des Workers (Fargate eu-central-1) statt Mac in Hamm — die Hop-Latenz vom heimischen DSL ist ein realer Faktor
  • DE-Nummer bei Telnyx kaufen (2 Setup + $1/Mo) — heute fehlte das Funding fuer Marvin DE-tauglich, US-Nummer war kostenlos aber Anrufkosten am Handy hoch
  • allowed_addresses auf LiveKit-Trunk mit Telnyx-Source-IPs (Security-Hardening)

Cross-Refs