{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-docs/est/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["partial","admonition"]},"product":"Elastic SIP Trunking","type":"markdown"},"seo":{"title":"LiveKit integration guide | Elastic SIP Trunking API | Sinch","siteUrl":"https://developers.sinch.com","llmstxt":{"title":"Sinch Developer Documentation","description":"LLMs.txt containing a map of all the documentation files for Sinch.","sections":[{"title":"SMS API","description":"The SMS API allows you to send and receive SMS messages with a few easy steps. You can also send bulk SMS messages to multiple customers using the Sinch SMS service.","includeFiles":["docs/sms/**/*.md","docs/sms/**/*.yaml"],"excludeFiles":["docs/sms/index.md"]},{"title":"Numbers API","description":"The Numbers API enables you to search for, view, and activate numbers. It's considered a precursor to other APIs in the Sinch product family. The numbers API can be used in tandem with any of our APIs that perform messaging or calling.","includeFiles":["docs/numbers/**/*.md","docs/numbers/**/*.yaml"],"excludeFiles":["docs/numbers/index.md"]},{"title":"Conversation API","description":"Send and receive messages globally on many popular channels with ease and confidence when using Sinch's Conversation API. Conversation API is the preferred API for sending mobile messages on SMS and other social channels with Sinch. It is a simple API with unified error messages, consistent request payloads, and common webhook payloads that are channel-agnostic.","includeFiles":["docs/conversation/**/*.md","docs/conversation/**/*.yaml"],"excludeFiles":["docs/conversation/index.md"]},{"title":"Voice API","description":"The Voice API works as a big telephony switch. The Voice API handles incoming phone calls (also known as incoming call “legs”), sets up outgoing phone calls (or outgoing call “legs”), and bridges the two. The incoming call leg may come in over a data connection (from a smartphone or web application using the Sinch SDKs) or through a local phone number (from the PSTN network). Similarly, the outgoing call leg can be over data (to another smartphone or web application using the Sinch SDKs) or the PSTN network.","includeFiles":["docs/voice/**/*.md","docs/voice/**/*.yaml"],"excludeFiles":["docs/voice/index.md"]},{"title":"Verification API","description":"The Verification API is a platform for phone number verification. It consists of the API and different software development kits (the Sinch SDKs) that you integrate with your smartphone or web application and cloud based back-end services. Together they enable SMS, Flashcall, Phone Call and Data verification in your application.","includeFiles":["docs/verification/**/*.md","docs/verification/**/*.yaml"],"excludeFiles":["docs/verification/index.md"]},{"title":"Provisioning API","description":"Provisioning API allows you to programmatically set up your senders, accounts and templates on your favorite messaging platforms on the Conversation API. For now, you can create your first WhatsApp channel through Meta's Embedded sign up, you can configure your first SMS App and configure your webhooks. As development continues, we will be adding the most commonly used channels.","includeFiles":["docs/provisioning-api/**/*.md","docs/provisioning-api/**/*.json"],"excludeFiles":["docs/provisioning-api/index.md"]},{"title":"Elastic SIP Trunking API","description":"With Elastic SIP Trunking you can create and manage your SIP trunks and phone numbers programmatically.","includeFiles":["docs/est/**/*.md","docs/est/**/*.yaml"],"excludeFiles":["docs/est/index.md"]},{"title":"Fax API","description":"Send and receive HIPAA compliant faxes on our modern fax platform using our developer-friendly API.","includeFiles":["docs/fax/**/*.md","docs/fax/**/*.yaml"],"excludeFiles":["docs/fax/index.md"]},{"title":"In-app Voice and Video SDK","description":"The In-app Voice and Video SDK enables you to add voice and video calling capabilities directly into your mobile or web application using the Sinch SDKs.","includeFiles":["docs/in-app-calling/**/*.md"],"excludeFiles":["docs/in-app-calling/index.md"]}],"hide":false,"excludeFiles":[]},"description":"Learn how to integrate your Elastic SIP Trunks with LiveKit."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"integrating-elastic-sip-trunking-with-livekit","__idx":0},"children":["Integrating Elastic SIP Trunking with LiveKit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This guide explains how to connect self-hosted LiveKit to Sinch Elastic SIP Trunking (EST) for inbound and outbound calling."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This guide assumes you have the following:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Static inbound routing from Elastic SIP Trunking to LiveKit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["ACL-based or digest-based authentication for outbound calling from LiveKit to Elastic SIP Trunking."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"before-you-start","__idx":1},"children":["Before you start"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before you begin setting up your Sinch Elastic SIP trunk make sure you have done the following:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Sign up for a free account at https://www.sinch.com/ and request access for Elastic SIP Trunking. Need help? Click ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://community.sinch.com/t5/Customer-Dashboard/How-to-sign-up-for-your-free-Sinch-account/ta-p/8058"},"children":["here"]}," for instructions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If you have not already done so, configure and create your Elastic SIP trunk. Instructions on how to do this can be found ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://community.sinch.com/t5/Elastic-SIP-Trunking/Getting-started-with-Elastic-SIP-Trunking/ta-p/11380"},"children":["here"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure you note the fully qualified domain name (FQDN) that was created on your SIP Trunk. You will need this while setting up your IP-PBX or SIP Application."]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["You have a phone number assigned to your SIP Trunk."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["You have CLI access to the LiveKit host."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["lk"]}," CLI is installed."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After setting up your Elastic SIP Trunk infrastructure, you can validate it using these ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/est/test-plan"},"children":["steps"]},". For first-time validation, a public Linux host is recommended because it usually reduces local firewall, NAT, and RTP troubleshooting issues."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After changing EST ACLs, endpoints, or similar routing settings, wait at least 60 seconds before retesting."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Open these ports on the LiveKit host:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5060/UDP"]}," for SIP signaling"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["10000-20000/UDP"]}," for SIP RTP"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["7880/TCP"]}," for the LiveKit API and WebSocket"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["7881/TCP"]}," for LiveKit TCP ICE fallback"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["50000-60000/UDP"]}," for LiveKit media"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you plan to use TLS later, also expose ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5061/TCP"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"what-this-validates","__idx":2},"children":["What this validates"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The quick start validates three milestones:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["EST can deliver inbound SIP calls to self-hosted LiveKit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["LiveKit can place outbound SIP calls to EST."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["After SIP is working, LiveKit can dispatch an agent into the inbound room and return audio to the caller."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Treat these as separate stages. Do not start with agent debugging."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"quick-start","__idx":3},"children":["Quick start"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use this section for the fastest path to a working inbound and outbound test."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-configure-sinch-est","__idx":4},"children":["1. Configure Sinch EST"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["On the Sinch EST side:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create or reuse an EST trunk."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Assign a DID to that trunk."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["In the Sinch Build dashboard, add a static endpoint under the trunk's inbound settings that points to your LiveKit SIP listener."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Add an ACL that allows your LiveKit public IP for outbound calls from LiveKit to EST."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Example EST values:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["trunk domain"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_EST_TRUNK_DOMAIN"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["static endpoint target"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_LIVEKIT_PUBLIC_HOST:5060/UDP"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["assigned DID"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_EST_DID"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["ACL entry"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_LIVEKIT_PUBLIC_IP/32"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-configure-livekit-cli-access","__idx":5},"children":["2. Configure LiveKit CLI access"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"export LIVEKIT_URL=http://YOUR_LIVEKIT_HOST:7880\nexport LIVEKIT_API_KEY=devkey\nexport LIVEKIT_API_SECRET=devsecretdevsecretdevsecretdevsec\n\nlk room list\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["lk room list"]}," returns successfully, your CLI access is working."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Note:"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Current LiveKit releases reject very short sample API secrets, so use a sufficiently long secret."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-create-livekit-inbound-routing","__idx":6},"children":["3. Create LiveKit inbound routing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create the LiveKit inbound trunk for your EST DID:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"lk sip inbound create \\\n  --name sinch-est-inbound \\\n  --numbers YOUR_EST_DID\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Save the returned ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SIPTrunkID"]}," as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_INBOUND_TRUNK_ID"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a dispatch rule that creates a room for each inbound caller:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"lk sip dispatch create \\\n  --name sinch-est-caller-dispatch \\\n  --trunks YOUR_INBOUND_TRUNK_ID \\\n  --caller est-inbound- \\\n  --randomize\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected room pattern:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"text","header":{"controls":{"copy":{}}},"source":"est-inbound-_<caller>_<random>\n","lang":"text"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-test-inbound-calling","__idx":7},"children":["4. Test inbound calling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_EST_DID"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected result:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["EST delivered the INVITE to LiveKit SIP"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["LiveKit matched the inbound trunk"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["LiveKit matched the dispatch rule"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["LiveKit created a room"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the SIP caller joined as a LiveKit participant"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Useful success indicators:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SIP participant joined room"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Waiting for track subscription(s)"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you see those messages, inbound SIP is working even if no agent is attached yet."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5-create-livekit-outbound-routing","__idx":8},"children":["5. Create LiveKit outbound routing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example assumes IP-based ACL authentication on the EST side."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you are using digest authentication instead, configure the EST trunk for digest auth and create the LiveKit outbound trunk to match that method."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"lk sip outbound create \\\n  --name sinch-est-outbound \\\n  --address YOUR_EST_TRUNK_DOMAIN \\\n  --transport UDP \\\n  --numbers YOUR_EST_CALLER_ID\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Save the returned ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SIPTrunkID"]}," as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_OUTBOUND_TRUNK_ID"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6-test-outbound-calling","__idx":9},"children":["6. Test outbound calling"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"lk sip participant create \\\n  --room est-outbound-test \\\n  --identity outbound-test \\\n  --trunk YOUR_OUTBOUND_TRUNK_ID \\\n  --number YOUR_EST_CALLER_ID \\\n  --call YOUR_TEST_DESTINATION \\\n  --wait \\\n  --timeout 45s\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected result:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["EST accepted the outbound INVITE"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["LiveKit established the SIP call"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["RTP flowed successfully"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Useful success indicators:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Outbound SIP call established"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["accepting RTP stream"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-est-maps-to-livekit","__idx":10},"children":["How EST maps to LiveKit"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Inbound/Orgination"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["EST trunk + DID + static endpoint -> LiveKit inbound trunk + SIP dispatch rule"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Outbound/Termination"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["EST trunk domain + ACL or digest auth -> LiveKit outbound trunk + SIP participant create request"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":11},"children":["Next steps"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After you have confirmed a working system, the following next steps can extend your solution."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"optional-agent-test","__idx":12},"children":["Optional agent test"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add an agent after plain SIP inbound and outbound tests pass."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"recommended-pattern","__idx":13},"children":["Recommended pattern"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Attach the agent through ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["roomConfig.agents"]}," on the SIP dispatch rule."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This is the cleanest pattern for inbound telephony because the room is created by the SIP dispatch rule and the agent is dispatched immediately when the room is created."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"simple-gemini-smoke-test","__idx":14},"children":["Simple Gemini smoke test"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Gemini is a convenient optional smoke test because getting a key is relatively easy and basic testing is low-friction, but other models can easily substitute."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"minimal-gemini-example","__idx":15},"children":["Minimal Gemini example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Example runtime env file:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"env","header":{"controls":{"copy":{}}},"source":"LIVEKIT_URL=ws://YOUR_LIVEKIT_HOST:7880\nLIVEKIT_API_KEY=devkey\nLIVEKIT_API_SECRET=devsecretdevsecretdevsecretdevsec\nGOOGLE_API_KEY=YOUR_GOOGLE_API_KEY\n","lang":"env"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Example dependency set:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"text","header":{"controls":{"copy":{}}},"source":"livekit-agents[google]~=1.5\npython-dotenv>=1.0,<2.0\n","lang":"text"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Minimal agent shape used during validation:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"from livekit import agents\nfrom livekit.agents import Agent, AgentServer, AgentSession, JobContext\nfrom livekit.plugins import google\n\n\nclass InboundAssistant(Agent):\n    def __init__(self) -> None:\n        super().__init__(instructions=\"You are a concise phone assistant.\")\n\n\nserver = AgentServer()\n\n\n@server.rtc_session(agent_name=\"inbound-agent\")\nasync def inbound_agent(ctx: JobContext) -> None:\n    session = AgentSession(\n        llm=google.realtime.RealtimeModel(\n            model=\"gemini-2.5-flash-native-audio-preview-12-2025\",\n            voice=\"Puck\",\n            instructions=\"Greet the caller and confirm audio is working.\",\n        ),\n    )\n    await session.start(room=ctx.room, agent=InboundAssistant())\n    await session.generate_reply(\n        instructions=\"Answer the call and ask whether the caller can hear you.\"\n    )\n\n\nif __name__ == \"__main__\":\n    agents.cli.run_app(server)\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Conceptual dispatch update:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"roomConfig\": {\n    \"agents\": [\n      {\n        \"agentName\": \"inbound-agent\"\n      }\n    ]\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected result:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the agent worker registered successfully"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the inbound SIP call triggered an agent job"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the agent joined the room"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the SIP side subscribed to the agent audio track"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the caller heard the agent and the agent responded"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"optional-tls-and-srtp","__idx":16},"children":["Optional TLS and SRTP"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Treat TLS and SRTP as an optional step after the basic UDP flow is working."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For EST, TLS and SRTP go together. If you switch this integration to TLS, configure it as a TLS plus SRTP setup rather than enabling TLS signaling alone."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["At a minimum, confirm:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["your LiveKit SIP listener is configured for TLS"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["EST is pointing its inbound static endpoint to your TLS listener, typically ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["YOUR_LIVEKIT_PUBLIC_HOST:5061/TLS"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["your certificate configuration is valid"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["your LiveKit inbound and outbound SIP trunk configuration requires media encryption so SRTP is used"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["your outbound LiveKit trunk transport matches the EST-side TLS configuration"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If signaling connects over TLS but media does not establish, re-check the media-encryption settings on both LiveKit SIP trunks before troubleshooting deeper."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"optional-sip-refer-transfer","__idx":17},"children":["Optional SIP REFER transfer"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["LiveKit cold transfer integrates with EST via SIP ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["REFER"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you plan to use cold transfers, see:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://community.sinch.com/t5/Elastic-SIP-Trunking/How-do-I-use-call-transfers-with-SIP-REFER/ta-p/19346"},"children":["SIP REFER"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://docs.livekit.io/telephony/features/transfers/cold/"},"children":["https://docs.livekit.io/telephony/features/transfers/cold/"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"troubleshooting","__idx":18},"children":["Troubleshooting"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following sections provide troubleshooting tips for issues you may encounter."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"no-inbound-invite-reaches-livekit","__idx":19},"children":["No inbound INVITE reaches LiveKit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The EST static endpoint IP or FQDN."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5060/UDP"]}," reachability."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Whether the public host IP changed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Whether EST is pointing to the intended trunk endpoint."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-room-is-never-created","__idx":20},"children":["The room is never created"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The LiveKit inbound trunk contains the called DID."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The SIP dispatch rule references the correct LiveKit trunk ID."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The dispatch rule type matches your intended routing pattern."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-room-is-created-but-there-is-no-audio","__idx":21},"children":["The room is created but there is no audio"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If no agent is attached, this is expected."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If an agent is attached, check for:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["received job request"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The agent joining the room."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["track subscribed"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mixing track"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["accepting RTP stream"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-room-is-created-but-the-agent-never-receives-a-job","__idx":22},"children":["The room is created but the agent never receives a job"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The dispatch rule includes the intended agent in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["roomConfig.agents"]}," if you are using named dispatch."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The running worker is registered with the same agent name expected by the dispatch rule."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["You do not have a mismatch between named dispatch and automatic dispatch modes."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Typical symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Rooms are created successfully."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["SIP logs show the call was routed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Agent logs never show ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["received job request"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Callers hear silence or the call times out."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-agent-does-not-start-or-exits-immediately","__idx":23},"children":["The agent does not start or exits immediately"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["LIVEKIT_URL"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["LIVEKIT_API_KEY"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["LIVEKIT_API_SECRET"]}," are set correctly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Any provider key such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GOOGLE_API_KEY"]}," is set if you are using that provider."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["LiveKit is reachable before starting the agent."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The agent process is not failing on startup with a missing environment variable or connection error."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Typical symptom:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Errors similar to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ws_url is required"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The agent starts, then exits immediately."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"port-8081-is-already-in-use","__idx":24},"children":["Port ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["8081"]}," is already in use"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Many LiveKit agent examples expose an HTTP listener on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["8081"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If startup fails with an address-in-use error, stop the old agent process and restart the intended one."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"outbound-call-fails","__idx":25},"children":["Outbound call fails"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The EST authentication method"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Whether your EST trunk is using IP-based ACL auth or digest auth."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The EST ACL contents if using IP-based auth."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The outbound trunk address and transport."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Caller ID formatting in E.164."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Whether EST accepts that caller ID on the trunk."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If UDP appears to be blocked or unreliable, try TCP as a troubleshooting step."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"one-way-audio","__idx":26},"children":["One-way audio"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["10000-20000/UDP"]}," for SIP RTP"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["50000-60000/UDP"]}," for LiveKit media"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Host NAT and firewall behavior."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Whether ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["use_external_ip: true"]}," is set where needed."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"cli-output-looks-misleading","__idx":27},"children":["CLI output looks misleading"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["During testing, some ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["lk sip ... list"]}," output was less reliable than isolated commands and raw ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["--curl"]}," verification."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If output looks wrong:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Rerun the command by itself."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["lk --curl ..."]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Inspect service logs directly."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"repeated-health-check-or-monitoring-calls-affect-agent-availability","__idx":28},"children":["Repeated health-check or monitoring calls affect agent availability"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you see repeated inbound SIP activity without real callers, monitoring or health-check traffic may be creating rooms and consuming worker capacity."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Typical symptoms:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Agent workers appear busy before a real call arrives."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Real callers hit ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["no agents available"]}," behavior."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["SIP logs show repeated incomplete inbound calls."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If this happens, review worker capacity settings and confirm which inbound calls are real traffic versus monitoring traffic."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"useful-logs","__idx":29},"children":["Useful logs"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For Docker-based self-hosting:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"docker logs livekit-sip-1\ndocker logs livekit-livekit-1\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Useful success indicators:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SIP participant joined room"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Outbound SIP call established"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["track subscribed"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mixing track"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["accepting RTP stream"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["received job request"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["registered worker"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"deployment-reference","__idx":30},"children":["Deployment reference"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the following examples as a minimal self-hosted reference deployment."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"example-livekityaml","__idx":31},"children":["Example ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["livekit.yaml"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"port: 7880\nbind_addresses:\n  - \"0.0.0.0\"\n\nrtc:\n  tcp_port: 7881\n  port_range_start: 50000\n  port_range_end: 60000\n  use_external_ip: true\n\nredis:\n  address: 127.0.0.1:6379\n\nkeys:\n  devkey: devsecretdevsecretdevsecretdevsec\n","lang":"yaml"},"children":[]}]},"headings":[{"value":"Integrating Elastic SIP Trunking with LiveKit","id":"integrating-elastic-sip-trunking-with-livekit","depth":1},{"value":"Before you start","id":"before-you-start","depth":2},{"value":"What this validates","id":"what-this-validates","depth":3},{"value":"Quick start","id":"quick-start","depth":2},{"value":"1. Configure Sinch EST","id":"1-configure-sinch-est","depth":3},{"value":"2. Configure LiveKit CLI access","id":"2-configure-livekit-cli-access","depth":3},{"value":"3. Create LiveKit inbound routing","id":"3-create-livekit-inbound-routing","depth":3},{"value":"4. Test inbound calling","id":"4-test-inbound-calling","depth":3},{"value":"5. Create LiveKit outbound routing","id":"5-create-livekit-outbound-routing","depth":3},{"value":"6. Test outbound calling","id":"6-test-outbound-calling","depth":3},{"value":"How EST maps to LiveKit","id":"how-est-maps-to-livekit","depth":2},{"value":"Next steps","id":"next-steps","depth":2},{"value":"Optional agent test","id":"optional-agent-test","depth":3},{"value":"Recommended pattern","id":"recommended-pattern","depth":4},{"value":"Simple Gemini smoke test","id":"simple-gemini-smoke-test","depth":4},{"value":"Minimal Gemini example","id":"minimal-gemini-example","depth":4},{"value":"Optional TLS and SRTP","id":"optional-tls-and-srtp","depth":3},{"value":"Optional SIP REFER transfer","id":"optional-sip-refer-transfer","depth":3},{"value":"Troubleshooting","id":"troubleshooting","depth":2},{"value":"No inbound INVITE reaches LiveKit","id":"no-inbound-invite-reaches-livekit","depth":3},{"value":"The room is never created","id":"the-room-is-never-created","depth":3},{"value":"The room is created but there is no audio","id":"the-room-is-created-but-there-is-no-audio","depth":3},{"value":"The room is created but the agent never receives a job","id":"the-room-is-created-but-the-agent-never-receives-a-job","depth":3},{"value":"The agent does not start or exits immediately","id":"the-agent-does-not-start-or-exits-immediately","depth":3},{"value":"Port 8081 is already in use","id":"port-8081-is-already-in-use","depth":3},{"value":"Outbound call fails","id":"outbound-call-fails","depth":3},{"value":"One-way audio","id":"one-way-audio","depth":3},{"value":"CLI output looks misleading","id":"cli-output-looks-misleading","depth":3},{"value":"Repeated health-check or monitoring calls affect agent availability","id":"repeated-health-check-or-monitoring-calls-affect-agent-availability","depth":3},{"value":"Useful logs","id":"useful-logs","depth":3},{"value":"Deployment reference","id":"deployment-reference","depth":2},{"value":"Example livekit.yaml","id":"example-livekityaml","depth":3}],"frontmatter":{"seo":{"title":"LiveKit integration guide | Elastic SIP Trunking API | Sinch","description":"Learn how to integrate your Elastic SIP Trunks with LiveKit."}},"lastModified":"2026-05-05T04:03:38.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/est/integration-guides/livekit","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}