{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-docs/voice-2.0/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Integrate an ElevenLabs AI Agent via SIP","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":"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":"Voice API v2","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-2.0/**/*.md","docs/voice-2.0/**/*.yaml"],"excludeFiles":["docs/voice-2.0/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"]},{"title":"Number Lookup API","description":"The Number Lookup API is designed to provide in-depth information about phone numbers, helping enterprises enhance their communication strategies and prevent fraud. By identifying the type of phone line (for example, mobile, landline, VoIP) and the associated carrier, the API allows businesses to optimize routing, reduce unnecessary costs, and improve customer engagement.","includeFiles":["docs/number-lookup-api-v2/**/*.md","docs/number-lookup-api-v2/**/*.yaml"],"excludeFiles":["docs/number-lookup-api-v2/index.md"]},{"title":"Functions","description":"Serverless compute for voice and messaging. Deploy your code and Sinch routes live calls and messages to it — no infrastructure to run.","includeFiles":["docs/functions/functions/**/*.md","docs/functions/concepts/**/*.md","docs/functions/reference/**/*.md"],"excludeFiles":["docs/functions/functions/index.md"]},{"title":"CLI","description":"One command line for every Sinch API and the full Functions lifecycle — scaffold, run locally, deploy, and manage.","includeFiles":["docs/functions/cli/**/*.md"],"excludeFiles":["docs/functions/cli/index.md"]}]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"integrate-an-elevenlabs-ai-agent-via-sip","__idx":0},"children":["Integrate an ElevenLabs AI Agent via SIP"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This tutorial connects a Sinch voice call to an ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://elevenlabs.io"},"children":["ElevenLabs"]}," Conversational AI agent over SIP. Unlike the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/elevenlabs"},"children":["bridge-based integration"]},", there is no relay server to deploy: Sinch dials the ElevenLabs SIP endpoint directly, and the two platforms exchange audio natively over the SIP session. The call flow is expressed entirely in SVAML, either as a static service behavior (inbound) or as a one-shot ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /v2/projects/{projectId}/calls"]}," payload (outbound)."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Four scenarios are covered, all using the same underlying pattern of bridging two call legs:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PSTN-in to ElevenLabs"]}," : an external caller dials your Sinch number; Sinch answers and bridges to the ElevenLabs agent."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["SIP-in to ElevenLabs"]}," : an external caller reaches Sinch over a configured SIP trunk, same SVAML, different ingress."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PSTN-out to ElevenLabs"]}," : Sinch dials a phone number and, on answer, bridges the callee to the ElevenLabs agent."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["SIP-out to ElevenLabs"]}," : Sinch dials an external SIP endpoint and, on answer, bridges the callee to the ElevenLabs agent."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["When to use this vs the WebSocket bridge:"]}," Use SIP when you want ElevenLabs to own the entire voice pipeline (STT, LLM, TTS) with zero relay infrastructure on your side. Use the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/elevenlabs"},"children":["WebSocket bridge"]}," when you need to intercept or transform the raw audio frames between Sinch and ElevenLabs (for example, to inject custom audio, apply gain, or log PCM). If you only need to exchange plain text with your own backend and want Sinch to handle speech-to-text and TTS, use ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/voice-relay"},"children":["Voice Relay"]}," instead."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-success-looks-like","__idx":2},"children":["What success looks like"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Inbound:"]}," you call your Sinch number (or SIP URI), the call is answered immediately, and you hear the ElevenLabs agent's greeting. You hold a spoken conversation with the agent."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Outbound:"]}," you run a script, your phone (or SIP client) rings, you answer, and you hear the ElevenLabs agent. A spoken back-and-forth follows."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In both cases, the Sinch dashboard shows two call legs joined by a bridge, and the ElevenLabs dashboard shows agent activity for the session."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"prerequisites","__idx":3},"children":["Prerequisites"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://dashboard.sinch.com"},"children":["Sinch account"]}," with a project, API credentials (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["KEY_ID"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["KEY_SECRET"]},"), and a Sinch virtual number assigned to a service."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["An ElevenLabs account with a configured Conversational AI agent whose ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phone"]}," channel is enabled and whose SIP endpoint is known (typically ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sip:<number>@sip.rtc.elevenlabs.io:5060"]},"). See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#elevenlabs-sip-setup"},"children":["ElevenLabs SIP setup"]}," below."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["curl"]}," (and optionally ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["jq"]},") for the shell examples; ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["pip install requests"]}," for the Python examples."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"elevenlabs-sip-setup","__idx":4},"children":["ElevenLabs SIP setup"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before any of the scenarios below will work, configure the ElevenLabs side:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["In the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://elevenlabs.io"},"children":["ElevenLabs dashboard"]},", open your Conversational AI agent."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Telephony"]}," channel (sometimes labeled \"Phone Numbers\" or \"SIP\")."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Note the SIP endpoint ElevenLabs assigns. The conventional format is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sip:<your-sinch-number>@sip.rtc.elevenlabs.io:5060"]},", but verify the exact URI in the ElevenLabs dashboard or their current docs, as the domain and port may change."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure the agent's voice, system prompt, and first message in the ElevenLabs dashboard. Sinch only routes audio; it does not configure the agent."]}]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["ElevenLabs' SIP offering, endpoint format, and authentication requirements evolve independently. Treat the URI shown above as a starting point and verify it against ElevenLabs' current documentation."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"setup","__idx":5},"children":["Setup"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Export your credentials and scenario-specific variables into the shell you will run the examples from. Each scenario uses a subset of these variables."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"# ── Sinch credentials (all scenarios) ──\nexport PROJECT_ID=\"your-project-uuid\"\nexport KEY_ID=\"your-access-key-id\"\nexport KEY_SECRET=\"your-access-key-secret\"\nexport SINCH_NUMBER=\"+1XXXXXXXXXX\"\n\n# ── Inbound scenarios only ──\nexport SERVICE_ID=\"your-service-uuid\"\n\n# ── Outbound PSTN scenario ──\nexport DESTINATION_NUMBER=\"+1YYYYYYYYYY\"\n\n# ── Outbound SIP scenario ──\nexport DESTINATION_SIP=\"sip:user@their-domain.example\"\n\n# ── ElevenLabs SIP endpoint (all scenarios) ──\nexport ELEVENLABS_SIP_URI=\"sip:+1XXXXXXXXXX@sip.rtc.elevenlabs.io:5060\"\n\n# ── Optional tuning ──\nexport DIAL_TIMEOUT=30         # seconds to wait for answer\nexport MAX_CALL_DURATION=7200  # hard ceiling on answered call (seconds)\n","lang":"bash"},"children":[]},{"$$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":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Variable"},"children":["Variable"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required"},"children":["Required"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Where to get it"},"children":["Where to get it"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Notes"},"children":["Notes"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PROJECT_ID"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://dashboard.sinch.com"},"children":["Sinch Dashboard"]}," > your Voice project"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["KEY_ID"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dashboard > Access Keys"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["HTTP Basic username"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["KEY_SECRET"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dashboard > Access Keys (shown once at creation)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["HTTP Basic password"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SINCH_NUMBER"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dashboard > Numbers"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your Sinch number, E.164. Used as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["from"]}," and typically also as the user part of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ELEVENLABS_SIP_URI"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SERVICE_ID"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["inbound only"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dashboard > your Voice project > Services"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The service whose call behavior you want to set."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DESTINATION_NUMBER"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["PSTN-out only"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your own list"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["E.164 phone number to dial."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DESTINATION_SIP"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["SIP-out only"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your own list"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Full SIP URI of the external endpoint to dial."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ELEVENLABS_SIP_URI"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["ElevenLabs dashboard, Phone/SIP channel config"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Full SIP URI including port. Verify format in ElevenLabs docs."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DIAL_TIMEOUT"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["no"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["n/a"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Defaults to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["30"]}," in the examples."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MAX_CALL_DURATION"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["no"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["n/a"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Defaults to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["7200"]}," in the examples."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Authentication is HTTP Basic using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["KEY_ID:KEY_SECRET"]},". The API base URL is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://voice.api.sinch.com"]}," (regional hosts ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["us1"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eu1"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["br1"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sg1"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["au1"]}," are also available)."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"scenario-1-inbound-pstn-to-elevenlabs-agent","__idx":6},"children":["Scenario 1: Inbound PSTN to ElevenLabs agent"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An external caller dials your Sinch phone number. Sinch answers, bridges the caller leg, then dials the ElevenLabs SIP endpoint and bridges it into the same bridge. The caller talks to the agent."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PATCH /v2/projects/{projectId}/services/{serviceId}"]}," to set a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["static"]}," call behavior on the service so that every inbound call is handled the same way without a webhook."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-svaml","__idx":7},"children":["The SVAML"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"callBehavior\": {\n    \"type\": \"STATIC\",\n    \"static\": {\n      \"callName\": \"caller\",\n      \"commands\": [\n        { \"command\": \"answer\" },\n        { \"command\": \"bridgeCall\", \"bridgeName\": \"sip-bridge\" },\n        {\n          \"command\": \"dial\",\n          \"callName\": \"sip-agent\",\n          \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"<SINCH_NUMBER>\" } },\n          \"to\": {\n            \"type\": \"SIP\",\n            \"sip\": {\n              \"endpoint\": \"<ELEVENLABS_SIP_URI>\",\n              \"transport\": \"TCP\"\n            }\n          },\n          \"dialTimeoutDurationSeconds\": 30,\n          \"maxCallDurationSeconds\": 7200,\n          \"events\": {\n            \"onAnswer\": [\n              { \"command\": \"bridgeCall\", \"bridgeName\": \"sip-bridge\" }\n            ],\n            \"onHangup\": [\n              { \"command\": \"hangup\", \"callName\": \"caller\" }\n            ]\n          }\n        }\n      ],\n      \"events\": {\n        \"onHangup\": [\n          { \"command\": \"hangup\", \"callName\": \"sip-agent\" }\n        ]\n      }\n    }\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Key points:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callName: \"caller\""]}," labels the inbound leg. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callName: \"sip-agent\""]}," labels the ElevenLabs leg. Both join ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeName: \"sip-bridge\""]},", so audio flows bidirectionally."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transport: \"TCP\""]}," is required for the ElevenLabs SIP endpoint (at the time of writing)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The mutual ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onHangup"]}," handlers ensure that when either party hangs up, the other leg is also torn down."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"shell-curl","__idx":8},"children":["Shell (curl)"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"#!/bin/bash\nset -e\n\n: \"${PROJECT_ID:?ERROR: PROJECT_ID is not set.}\"\n: \"${KEY_ID:?ERROR: KEY_ID is not set.}\"\n: \"${KEY_SECRET:?ERROR: KEY_SECRET is not set.}\"\n: \"${SERVICE_ID:?ERROR: SERVICE_ID is not set.}\"\n: \"${SINCH_NUMBER:?ERROR: SINCH_NUMBER is not set.}\"\n: \"${ELEVENLABS_SIP_URI:?ERROR: ELEVENLABS_SIP_URI is not set.}\"\n\nDIAL_TIMEOUT=\"${DIAL_TIMEOUT:-30}\"\nMAX_CALL_DURATION=\"${MAX_CALL_DURATION:-7200}\"\n\necho \"Patching service ${SERVICE_ID} for inbound -> ElevenLabs SIP ...\"\n\nRESPONSE=$(curl -s -w \"\\n%{http_code}\" \\\n  -X PATCH \\\n  -u \"${KEY_ID}:${KEY_SECRET}\" \\\n  \"https://voice.api.sinch.com/v2/projects/${PROJECT_ID}/services/${SERVICE_ID}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d @- <<EOF\n{\n  \"callBehavior\": {\n    \"type\": \"STATIC\",\n    \"static\": {\n      \"callName\": \"caller\",\n      \"commands\": [\n        { \"command\": \"answer\" },\n        { \"command\": \"bridgeCall\", \"bridgeName\": \"sip-bridge\" },\n        {\n          \"command\": \"dial\",\n          \"callName\": \"sip-agent\",\n          \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"${SINCH_NUMBER}\" } },\n          \"to\": {\n            \"type\": \"SIP\",\n            \"sip\": {\n              \"endpoint\": \"${ELEVENLABS_SIP_URI}\",\n              \"transport\": \"TCP\"\n            }\n          },\n          \"dialTimeoutDurationSeconds\": ${DIAL_TIMEOUT},\n          \"maxCallDurationSeconds\": ${MAX_CALL_DURATION},\n          \"events\": {\n            \"onAnswer\": [\n              { \"command\": \"bridgeCall\", \"bridgeName\": \"sip-bridge\" }\n            ],\n            \"onHangup\": [\n              { \"command\": \"hangup\", \"callName\": \"caller\" }\n            ]\n          }\n        }\n      ],\n      \"events\": {\n        \"onHangup\": [\n          { \"command\": \"hangup\", \"callName\": \"sip-agent\" }\n        ]\n      }\n    }\n  }\n}\nEOF\n)\n\nHTTP_BODY=$(echo \"${RESPONSE}\" | head -n -1)\nHTTP_CODE=$(echo \"${RESPONSE}\" | tail -n 1)\n\nif [ \"${HTTP_CODE}\" -eq 200 ]; then\n  echo \"Service updated (HTTP ${HTTP_CODE}):\"\n  echo \"${HTTP_BODY}\" | (command -v jq > /dev/null && jq '.' || cat)\nelse\n  echo \"ERROR: API returned HTTP ${HTTP_CODE}:\" >&2\n  echo \"${HTTP_BODY}\" >&2\n  exit 1\nfi\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"python","__idx":9},"children":["Python"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Requirements: pip install requests\nimport json\nimport os\nimport sys\n\nimport requests\n\n\ndef env(name, default=None):\n    value = os.environ.get(name, default)\n    if not value:\n        print(f\"ERROR: {name} is not set. Run: export {name}=...\", file=sys.stderr)\n        sys.exit(1)\n    return value\n\n\nproject_id        = env(\"PROJECT_ID\")\nkey_id            = env(\"KEY_ID\")\nkey_secret        = env(\"KEY_SECRET\")\nservice_id        = env(\"SERVICE_ID\")\nsinch_number      = env(\"SINCH_NUMBER\")\nelevenlabs_sip    = env(\"ELEVENLABS_SIP_URI\")\ndial_timeout      = int(env(\"DIAL_TIMEOUT\", \"30\"))\nmax_call_duration = int(env(\"MAX_CALL_DURATION\", \"7200\"))\n\nurl = f\"https://voice.api.sinch.com/v2/projects/{project_id}/services/{service_id}\"\n\npayload = {\n    \"callBehavior\": {\n        \"type\": \"STATIC\",\n        \"static\": {\n            \"callName\": \"caller\",\n            \"commands\": [\n                {\"command\": \"answer\"},\n                {\"command\": \"bridgeCall\", \"bridgeName\": \"sip-bridge\"},\n                {\n                    \"command\": \"dial\",\n                    \"callName\": \"sip-agent\",\n                    \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": sinch_number}},\n                    \"to\": {\n                        \"type\": \"SIP\",\n                        \"sip\": {\n                            \"endpoint\": elevenlabs_sip,\n                            \"transport\": \"TCP\",\n                        },\n                    },\n                    \"dialTimeoutDurationSeconds\": dial_timeout,\n                    \"maxCallDurationSeconds\": max_call_duration,\n                    \"events\": {\n                        \"onAnswer\": [\n                            {\"command\": \"bridgeCall\", \"bridgeName\": \"sip-bridge\"}\n                        ],\n                        \"onHangup\": [\n                            {\"command\": \"hangup\", \"callName\": \"caller\"}\n                        ],\n                    },\n                },\n            ],\n            \"events\": {\n                \"onHangup\": [\n                    {\"command\": \"hangup\", \"callName\": \"sip-agent\"}\n                ]\n            },\n        },\n    }\n}\n\nprint(f\"Patching service {service_id} for inbound -> ElevenLabs SIP ...\")\n\nresp = requests.patch(url, json=payload, auth=(key_id, key_secret))\nif resp.status_code == 200:\n    print(f\"Service updated (HTTP {resp.status_code}):\")\n    print(json.dumps(resp.json(), indent=2))\nelse:\n    print(f\"ERROR: API returned HTTP {resp.status_code}:\", file=sys.stderr)\n    print(resp.text, file=sys.stderr)\n    sys.exit(1)\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once the PATCH succeeds, call your Sinch number from any phone. Sinch answers and bridges you to the ElevenLabs agent."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"scenario-2-inbound-sip-to-elevenlabs-agent","__idx":10},"children":["Scenario 2: Inbound SIP to ElevenLabs agent"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An external SIP client (softphone, PBX, or another SIP trunk) calls your Sinch SIP endpoint. The SVAML is ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["identical"]}," to Scenario 1; only the ingress path differs."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"what-changes","__idx":11},"children":["What changes"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Instead of a PSTN phone number, the external caller targets your Sinch SIP URI. The exact URI depends on how your project's SIP trunk is configured; consult the Sinch dashboard under your Voice project's SIP settings."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PATCH /v2/projects/{projectId}/services/{serviceId}"]}," payload is the same as Scenario 1 (the static behavior handles whatever inbound call arrives, regardless of whether it came in over PSTN or SIP)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"setup-1","__idx":12},"children":["Setup"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Run the same PATCH from Scenario 1 (shell or Python). Then, from an external SIP client, dial your Sinch SIP URI. The call is answered, bridged, and the ElevenLabs agent greets the caller."]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you have both a phone number and a SIP trunk assigned to the same service, the same static behavior handles calls from either ingress. You do not need separate services unless you want different call flows for PSTN and SIP callers."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"scenario-3-outbound-pstn-bridged-to-elevenlabs-agent","__idx":13},"children":["Scenario 3: Outbound PSTN, bridged to ElevenLabs agent"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Sinch dials a phone number. When the callee answers, the call is bridged to the ElevenLabs SIP agent. Use this for outbound campaigns, appointment reminders, or survey calls where the AI agent drives the conversation."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /v2/projects/{projectId}/calls"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-svaml-1","__idx":14},"children":["The SVAML"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"commands\": [\n    {\n      \"command\": \"dial\",\n      \"callName\": \"origin\",\n      \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"<SINCH_NUMBER>\" } },\n      \"to\":   { \"type\": \"PHONE\", \"phone\": { \"number\": \"<DESTINATION_NUMBER>\" } },\n      \"dialTimeoutDurationSeconds\": 30,\n      \"maxCallDurationSeconds\": 180,\n      \"events\": {\n        \"onAnswer\": [\n          { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" },\n          {\n            \"command\": \"dial\",\n            \"callName\": \"elevenlabs\",\n            \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"<SINCH_NUMBER>\" } },\n            \"to\": {\n              \"type\": \"SIP\",\n              \"sip\": {\n                \"endpoint\": \"<ELEVENLABS_SIP_URI>\",\n                \"transport\": \"TCP\"\n              }\n            },\n            \"events\": {\n              \"onAnswer\": [\n                { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" }\n              ]\n            }\n          }\n        ],\n        \"onHangup\": [\n          { \"command\": \"hangup\", \"callName\": \"elevenlabs\" }\n        ]\n      }\n    }\n  ]\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Key points:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callName: \"origin\""]}," is the PSTN leg. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callName: \"elevenlabs\""]}," is the SIP leg. Both join ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeName: \"bridge\""]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The ElevenLabs ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," fires only ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onAnswer"]}," of the PSTN leg, so the agent is not invoked for unanswered calls."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onHangup"]}," on the origin tears down the ElevenLabs leg when the callee hangs up."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"shell-curl-1","__idx":15},"children":["Shell (curl)"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"#!/bin/bash\nset -e\n\n: \"${PROJECT_ID:?ERROR: PROJECT_ID is not set.}\"\n: \"${KEY_ID:?ERROR: KEY_ID is not set.}\"\n: \"${KEY_SECRET:?ERROR: KEY_SECRET is not set.}\"\n: \"${SINCH_NUMBER:?ERROR: SINCH_NUMBER is not set.}\"\n: \"${DESTINATION_NUMBER:?ERROR: DESTINATION_NUMBER is not set.}\"\n: \"${ELEVENLABS_SIP_URI:?ERROR: ELEVENLABS_SIP_URI is not set.}\"\n\nDIAL_TIMEOUT=\"${DIAL_TIMEOUT:-30}\"\nMAX_CALL_DURATION=\"${MAX_CALL_DURATION:-180}\"\n\necho \"Dialing ${DESTINATION_NUMBER}, will bridge to ElevenLabs SIP on answer ...\"\n\nRESPONSE=$(curl -s -w \"\\n%{http_code}\" \\\n  -X POST \\\n  -u \"${KEY_ID}:${KEY_SECRET}\" \\\n  \"https://voice.api.sinch.com/v2/projects/${PROJECT_ID}/calls\" \\\n  -H \"Content-Type: application/json\" \\\n  -d @- <<EOF\n{\n  \"commands\": [\n    {\n      \"command\": \"dial\",\n      \"callName\": \"origin\",\n      \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"${SINCH_NUMBER}\" } },\n      \"to\":   { \"type\": \"PHONE\", \"phone\": { \"number\": \"${DESTINATION_NUMBER}\" } },\n      \"dialTimeoutDurationSeconds\": ${DIAL_TIMEOUT},\n      \"maxCallDurationSeconds\": ${MAX_CALL_DURATION},\n      \"events\": {\n        \"onAnswer\": [\n          { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" },\n          {\n            \"command\": \"dial\",\n            \"callName\": \"elevenlabs\",\n            \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"${SINCH_NUMBER}\" } },\n            \"to\": {\n              \"type\": \"SIP\",\n              \"sip\": {\n                \"endpoint\": \"${ELEVENLABS_SIP_URI}\",\n                \"transport\": \"TCP\"\n              }\n            },\n            \"events\": {\n              \"onAnswer\": [\n                { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" }\n              ]\n            }\n          }\n        ],\n        \"onHangup\": [\n          { \"command\": \"hangup\", \"callName\": \"elevenlabs\" }\n        ]\n      }\n    }\n  ]\n}\nEOF\n)\n\nHTTP_BODY=$(echo \"${RESPONSE}\" | head -n -1)\nHTTP_CODE=$(echo \"${RESPONSE}\" | tail -n 1)\n\nif [ \"${HTTP_CODE}\" -eq 201 ]; then\n  echo \"Call created (HTTP ${HTTP_CODE}):\"\n  echo \"${HTTP_BODY}\" | (command -v jq > /dev/null && jq '.' || cat)\nelse\n  echo \"ERROR: API returned HTTP ${HTTP_CODE}:\" >&2\n  echo \"${HTTP_BODY}\" >&2\n  exit 1\nfi\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"python-1","__idx":16},"children":["Python"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Requirements: pip install requests\nimport json\nimport os\nimport sys\n\nimport requests\n\n\ndef env(name, default=None):\n    value = os.environ.get(name, default)\n    if not value:\n        print(f\"ERROR: {name} is not set. Run: export {name}=...\", file=sys.stderr)\n        sys.exit(1)\n    return value\n\n\nproject_id         = env(\"PROJECT_ID\")\nkey_id             = env(\"KEY_ID\")\nkey_secret         = env(\"KEY_SECRET\")\nsinch_number       = env(\"SINCH_NUMBER\")\ndestination_number = env(\"DESTINATION_NUMBER\")\nelevenlabs_sip     = env(\"ELEVENLABS_SIP_URI\")\ndial_timeout       = int(env(\"DIAL_TIMEOUT\", \"30\"))\nmax_call_duration  = int(env(\"MAX_CALL_DURATION\", \"180\"))\n\nurl = f\"https://voice.api.sinch.com/v2/projects/{project_id}/calls\"\n\npayload = {\n    \"commands\": [\n        {\n            \"command\": \"dial\",\n            \"callName\": \"origin\",\n            \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": sinch_number}},\n            \"to\":   {\"type\": \"PHONE\", \"phone\": {\"number\": destination_number}},\n            \"dialTimeoutDurationSeconds\": dial_timeout,\n            \"maxCallDurationSeconds\": max_call_duration,\n            \"events\": {\n                \"onAnswer\": [\n                    {\"command\": \"bridgeCall\", \"bridgeName\": \"bridge\"},\n                    {\n                        \"command\": \"dial\",\n                        \"callName\": \"elevenlabs\",\n                        \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": sinch_number}},\n                        \"to\": {\n                            \"type\": \"SIP\",\n                            \"sip\": {\n                                \"endpoint\": elevenlabs_sip,\n                                \"transport\": \"TCP\",\n                            },\n                        },\n                        \"events\": {\n                            \"onAnswer\": [\n                                {\"command\": \"bridgeCall\", \"bridgeName\": \"bridge\"}\n                            ]\n                        },\n                    },\n                ],\n                \"onHangup\": [\n                    {\"command\": \"hangup\", \"callName\": \"elevenlabs\"}\n                ],\n            },\n        }\n    ]\n}\n\nprint(f\"Dialing {destination_number}, will bridge to ElevenLabs SIP on answer ...\")\n\nresp = requests.post(url, json=payload, auth=(key_id, key_secret))\nif resp.status_code == 201:\n    print(f\"Call created (HTTP {resp.status_code}):\")\n    print(json.dumps(resp.json(), indent=2))\nelse:\n    print(f\"ERROR: API returned HTTP {resp.status_code}:\", file=sys.stderr)\n    print(resp.text, file=sys.stderr)\n    sys.exit(1)\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"scenario-4-outbound-sip-bridged-to-elevenlabs-agent","__idx":17},"children":["Scenario 4: Outbound SIP, bridged to ElevenLabs agent"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Identical to Scenario 3, but the outbound leg dials an external SIP endpoint instead of a phone number. Use this when the person you are calling is reachable over SIP (a softphone, a PBX extension, another SIP trunk)."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"the-svaml-2","__idx":18},"children":["The SVAML"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"commands\": [\n    {\n      \"command\": \"dial\",\n      \"callName\": \"origin\",\n      \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"<SINCH_NUMBER>\" } },\n      \"to\":   { \"type\": \"SIP\", \"sip\": { \"endpoint\": \"<DESTINATION_SIP>\" } },\n      \"dialTimeoutDurationSeconds\": 30,\n      \"maxCallDurationSeconds\": 180,\n      \"events\": {\n        \"onAnswer\": [\n          { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" },\n          {\n            \"command\": \"dial\",\n            \"callName\": \"elevenlabs\",\n            \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"<SINCH_NUMBER>\" } },\n            \"to\": {\n              \"type\": \"SIP\",\n              \"sip\": {\n                \"endpoint\": \"<ELEVENLABS_SIP_URI>\",\n                \"transport\": \"TCP\"\n              }\n            },\n            \"events\": {\n              \"onAnswer\": [\n                { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" }\n              ]\n            }\n          }\n        ],\n        \"onHangup\": [\n          { \"command\": \"hangup\", \"callName\": \"elevenlabs\" }\n        ]\n      }\n    }\n  ]\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The only difference from Scenario 3 is that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["to"]}," on the origin leg uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type: \"SIP\""]}," with a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sip.endpoint"]}," instead of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type: \"PHONE\""]},". Note that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transport"]}," is not set on the destination SIP leg here (it defaults to UDP), since the external SIP endpoint may support different transports than ElevenLabs. Set it explicitly if your destination requires TCP or TLS."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"shell-curl-2","__idx":19},"children":["Shell (curl)"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"#!/bin/bash\nset -e\n\n: \"${PROJECT_ID:?ERROR: PROJECT_ID is not set.}\"\n: \"${KEY_ID:?ERROR: KEY_ID is not set.}\"\n: \"${KEY_SECRET:?ERROR: KEY_SECRET is not set.}\"\n: \"${SINCH_NUMBER:?ERROR: SINCH_NUMBER is not set.}\"\n: \"${DESTINATION_SIP:?ERROR: DESTINATION_SIP is not set.}\"\n: \"${ELEVENLABS_SIP_URI:?ERROR: ELEVENLABS_SIP_URI is not set.}\"\n\nDIAL_TIMEOUT=\"${DIAL_TIMEOUT:-30}\"\nMAX_CALL_DURATION=\"${MAX_CALL_DURATION:-180}\"\n\necho \"Dialing SIP ${DESTINATION_SIP}, will bridge to ElevenLabs SIP on answer ...\"\n\nRESPONSE=$(curl -s -w \"\\n%{http_code}\" \\\n  -X POST \\\n  -u \"${KEY_ID}:${KEY_SECRET}\" \\\n  \"https://voice.api.sinch.com/v2/projects/${PROJECT_ID}/calls\" \\\n  -H \"Content-Type: application/json\" \\\n  -d @- <<EOF\n{\n  \"commands\": [\n    {\n      \"command\": \"dial\",\n      \"callName\": \"origin\",\n      \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"${SINCH_NUMBER}\" } },\n      \"to\":   { \"type\": \"SIP\", \"sip\": { \"endpoint\": \"${DESTINATION_SIP}\" } },\n      \"dialTimeoutDurationSeconds\": ${DIAL_TIMEOUT},\n      \"maxCallDurationSeconds\": ${MAX_CALL_DURATION},\n      \"events\": {\n        \"onAnswer\": [\n          { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" },\n          {\n            \"command\": \"dial\",\n            \"callName\": \"elevenlabs\",\n            \"from\": { \"type\": \"PHONE\", \"phone\": { \"number\": \"${SINCH_NUMBER}\" } },\n            \"to\": {\n              \"type\": \"SIP\",\n              \"sip\": {\n                \"endpoint\": \"${ELEVENLABS_SIP_URI}\",\n                \"transport\": \"TCP\"\n              }\n            },\n            \"events\": {\n              \"onAnswer\": [\n                { \"command\": \"bridgeCall\", \"bridgeName\": \"bridge\" }\n              ]\n            }\n          }\n        ],\n        \"onHangup\": [\n          { \"command\": \"hangup\", \"callName\": \"elevenlabs\" }\n        ]\n      }\n    }\n  ]\n}\nEOF\n)\n\nHTTP_BODY=$(echo \"${RESPONSE}\" | head -n -1)\nHTTP_CODE=$(echo \"${RESPONSE}\" | tail -n 1)\n\nif [ \"${HTTP_CODE}\" -eq 201 ]; then\n  echo \"Call created (HTTP ${HTTP_CODE}):\"\n  echo \"${HTTP_BODY}\" | (command -v jq > /dev/null && jq '.' || cat)\nelse\n  echo \"ERROR: API returned HTTP ${HTTP_CODE}:\" >&2\n  echo \"${HTTP_BODY}\" >&2\n  exit 1\nfi\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"python-2","__idx":20},"children":["Python"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Requirements: pip install requests\nimport json\nimport os\nimport sys\n\nimport requests\n\n\ndef env(name, default=None):\n    value = os.environ.get(name, default)\n    if not value:\n        print(f\"ERROR: {name} is not set. Run: export {name}=...\", file=sys.stderr)\n        sys.exit(1)\n    return value\n\n\nproject_id        = env(\"PROJECT_ID\")\nkey_id            = env(\"KEY_ID\")\nkey_secret        = env(\"KEY_SECRET\")\nsinch_number      = env(\"SINCH_NUMBER\")\ndestination_sip   = env(\"DESTINATION_SIP\")\nelevenlabs_sip    = env(\"ELEVENLABS_SIP_URI\")\ndial_timeout      = int(env(\"DIAL_TIMEOUT\", \"30\"))\nmax_call_duration = int(env(\"MAX_CALL_DURATION\", \"180\"))\n\nurl = f\"https://voice.api.sinch.com/v2/projects/{project_id}/calls\"\n\npayload = {\n    \"commands\": [\n        {\n            \"command\": \"dial\",\n            \"callName\": \"origin\",\n            \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": sinch_number}},\n            \"to\":   {\"type\": \"SIP\", \"sip\": {\"endpoint\": destination_sip}},\n            \"dialTimeoutDurationSeconds\": dial_timeout,\n            \"maxCallDurationSeconds\": max_call_duration,\n            \"events\": {\n                \"onAnswer\": [\n                    {\"command\": \"bridgeCall\", \"bridgeName\": \"bridge\"},\n                    {\n                        \"command\": \"dial\",\n                        \"callName\": \"elevenlabs\",\n                        \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": sinch_number}},\n                        \"to\": {\n                            \"type\": \"SIP\",\n                            \"sip\": {\n                                \"endpoint\": elevenlabs_sip,\n                                \"transport\": \"TCP\",\n                            },\n                        },\n                        \"events\": {\n                            \"onAnswer\": [\n                                {\"command\": \"bridgeCall\", \"bridgeName\": \"bridge\"}\n                            ]\n                        },\n                    },\n                ],\n                \"onHangup\": [\n                    {\"command\": \"hangup\", \"callName\": \"elevenlabs\"}\n                ],\n            },\n        }\n    ]\n}\n\nprint(f\"Dialing SIP {destination_sip}, will bridge to ElevenLabs SIP on answer ...\")\n\nresp = requests.post(url, json=payload, auth=(key_id, key_secret))\nif resp.status_code == 201:\n    print(f\"Call created (HTTP {resp.status_code}):\")\n    print(json.dumps(resp.json(), indent=2))\nelse:\n    print(f\"ERROR: API returned HTTP {resp.status_code}:\", file=sys.stderr)\n    print(resp.text, file=sys.stderr)\n    sys.exit(1)\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-it-works","__idx":21},"children":["How it works"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All four scenarios use the same underlying mechanism: a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["bridge"]}," that joins two call legs."]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Inbound:"]}," Sinch receives the call on the service and executes the static SVAML. It answers the caller, puts the caller into a named bridge, then dials the ElevenLabs SIP endpoint as a second leg and puts it into the same bridge. Audio flows bidirectionally."]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Outbound:"]}," A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /v2/projects/{projectId}/calls"]}," creates the session. The first ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," reaches the destination (phone or SIP). On answer, SVAML puts that leg into a bridge and fires a second ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," to the ElevenLabs SIP endpoint, which also joins the bridge."]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In both cases, the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeCall"]}," command on each leg's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onAnswer"]}," is what connects the audio. The bridge name (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"sip-bridge\""]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"bridge\""]}," in the examples) is arbitrary but must match across both legs within the same session."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"sip-transport","__idx":22},"children":["SIP transport"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ElevenLabs SIP endpoint requires ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"transport\": \"TCP\""]}," (at the time of writing). If omitted, the default is UDP, which may cause the SIP ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["INVITE"]}," to fail or audio to not flow. Verify the current transport requirement in the ElevenLabs documentation."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"hangup-propagation","__idx":23},"children":["Hangup propagation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Each scenario includes ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onHangup"]}," handlers on both the caller/origin leg and the agent leg so that when either party disconnects, the other leg is torn down. Without these, the surviving leg would remain connected (and billable) until ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["maxCallDurationSeconds"]}," expires."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"audio-considerations","__idx":24},"children":["Audio considerations"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["SIP audio negotiation happens at the SIP level between Sinch and ElevenLabs, so there is no manual sample-rate alignment like the WebSocket bridge requires. The two platforms negotiate codecs during SIP session setup. If you hear degraded audio quality, check:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["That the ElevenLabs agent's audio configuration matches what Sinch is offering during SDP negotiation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["That ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transport: \"TCP\""]}," is set on the ElevenLabs ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["to"]}," leg (UDP may cause packet loss on some paths)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Network connectivity between your Sinch region and ElevenLabs' SIP infrastructure."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"troubleshooting","__idx":25},"children":["Troubleshooting"]},{"$$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":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Symptom"},"children":["Symptom"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Likely cause"},"children":["Likely cause"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400"]}," on the PATCH or POST"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Malformed SVAML. Check that the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["to.type"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"SIP\""]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sip.endpoint"]}," is a valid SIP URI."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["401"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Bad or missing Basic Auth credentials."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["404"]}," on the PATCH"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unknown ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["projectId"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["serviceId"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Inbound calls are not answered"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The service's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callBehavior"]}," was not patched, or the phone number is not assigned to the service."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["ElevenLabs leg times out"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The SIP URI is wrong, ElevenLabs' SIP service is unreachable, or the transport does not match. Verify ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ELEVENLABS_SIP_URI"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transport"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Audio flows one way only"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Transport mismatch or firewall blocking RTP. Confirm ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transport: \"TCP\""]}," and check network path."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Agent does not greet the caller"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The ElevenLabs agent may not have a first message configured, or the Phone/SIP channel is not enabled on the agent. Check the ElevenLabs dashboard."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"production-readiness-checklist","__idx":26},"children":["Production-readiness checklist"]},{"$$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":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Concern"},"children":["Concern"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"What to do"},"children":["What to do"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Call duration caps"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["maxCallDurationSeconds"]}," to bound costs. The inbound examples default to 7200 s (2 h); outbound to 180 s. Tune these to your use case."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Hangup propagation"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Both legs need mutual ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onHangup"]}," handlers. The examples include them; do not remove them."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["ElevenLabs costs"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["ElevenLabs bills per minute of agent usage. Cap exposure with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["maxCallDurationSeconds"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Failover"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["If the ElevenLabs SIP endpoint is unreachable, the agent ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," will time out and the caller hears nothing. Consider adding an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onTimeout"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onFailure"]}," handler on the agent leg to play a fallback TTS message or route to a human."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Idempotency (outbound)"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["For outbound calls, send an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}," header to make retries safe. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/outbound-tts"},"children":["Make an Outbound Call"]}," for details."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["AMD (outbound PSTN)"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["If dialing mobile numbers that may go to voicemail, insert an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["amd"]}," command before bridging. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/amd"},"children":["AMD"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Recording"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["If you need call recordings, add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["startRecording"]}," inside ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onAnswer"]},". See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/recording-and-transcription"},"children":["Recording & Transcription"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Monitoring"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionId"]}," from the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," response (or retrieve it for inbound calls) with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /v2/projects/{projectId}/sessions/{sessionId}"]}," to inspect call legs and outcomes. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/voice-2.0/tutorials/track-call-status"},"children":["Track Call Status"]},"."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"api-reference-at-a-glance","__idx":27},"children":["API reference (at a glance)"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PATCH /v2/projects/{projectId}/services/{serviceId}"]},": sets the service's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callBehavior"]},". ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type: \"STATIC\""]}," means every inbound call executes the same inline SVAML, no webhook needed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /v2/projects/{projectId}/calls"]},": creates an outbound call session. Returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["201"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["projectId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["serviceId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionId"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["to: { type: \"SIP\", sip: { endpoint, transport } }"]},": the SIP destination type. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["endpoint"]}," is a SIP URI (required). ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transport"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"UDP\""]}," (default), ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"TCP\""]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"TLS\""]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeCall"]},": joins the current call leg to a named bridge. Two legs in the same bridge exchange audio bidirectionally."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["from"]},": the originating identity. Uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type: \"PHONE\""]}," with a Sinch virtual number in these examples. Also supports ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type: \"SIP\""]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dialTimeoutDurationSeconds"]},": how long to wait for the destination to answer."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["maxCallDurationSeconds"]},": hard ceiling on the answered call. The call is terminated automatically when reached."]}]}]},"headings":[{"value":"Integrate an ElevenLabs AI Agent via SIP","id":"integrate-an-elevenlabs-ai-agent-via-sip","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"What success looks like","id":"what-success-looks-like","depth":2},{"value":"Prerequisites","id":"prerequisites","depth":2},{"value":"ElevenLabs SIP setup","id":"elevenlabs-sip-setup","depth":2},{"value":"Setup","id":"setup","depth":2},{"value":"Scenario 1: Inbound PSTN to ElevenLabs agent","id":"scenario-1-inbound-pstn-to-elevenlabs-agent","depth":2},{"value":"The SVAML","id":"the-svaml","depth":3},{"value":"Shell (curl)","id":"shell-curl","depth":3},{"value":"Python","id":"python","depth":3},{"value":"Scenario 2: Inbound SIP to ElevenLabs agent","id":"scenario-2-inbound-sip-to-elevenlabs-agent","depth":2},{"value":"What changes","id":"what-changes","depth":3},{"value":"Setup","id":"setup-1","depth":3},{"value":"Scenario 3: Outbound PSTN, bridged to ElevenLabs agent","id":"scenario-3-outbound-pstn-bridged-to-elevenlabs-agent","depth":2},{"value":"The SVAML","id":"the-svaml-1","depth":3},{"value":"Shell (curl)","id":"shell-curl-1","depth":3},{"value":"Python","id":"python-1","depth":3},{"value":"Scenario 4: Outbound SIP, bridged to ElevenLabs agent","id":"scenario-4-outbound-sip-bridged-to-elevenlabs-agent","depth":2},{"value":"The SVAML","id":"the-svaml-2","depth":3},{"value":"Shell (curl)","id":"shell-curl-2","depth":3},{"value":"Python","id":"python-2","depth":3},{"value":"How it works","id":"how-it-works","depth":2},{"value":"SIP transport","id":"sip-transport","depth":3},{"value":"Hangup propagation","id":"hangup-propagation","depth":3},{"value":"Audio considerations","id":"audio-considerations","depth":2},{"value":"Troubleshooting","id":"troubleshooting","depth":2},{"value":"Production-readiness checklist","id":"production-readiness-checklist","depth":2},{"value":"API reference (at a glance)","id":"api-reference-at-a-glance","depth":2}],"frontmatter":{"seo":{"title":"Integrate an ElevenLabs AI Agent via SIP"}},"lastModified":"2026-09-01T08:14:37.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/voice-2.0/tutorials/elevenlabs-sip","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}