{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-docs/voice-2.0/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"product":"Voice v2 (preview)","type":"markdown"},"seo":{"title":"Call Forwarding","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":"call-forwarding","__idx":0},"children":["Call Forwarding"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Voice API v2 has no dedicated \"forward\" or \"transfer\" command. Instead, you build forwarding from three primitives:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}]}," creates a new outbound call leg within the same session."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeCall"]}]}," joins two legs together so both sides hear each other. The bridge is created when the first leg references it, and the second leg joins it."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["hangup"]}]}," drops a specific named leg."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every forwarding pattern, whether it's unconditional, no-answer fallback, time-of-day routing, or a mid-call transfer, is just a combination of these three commands with different event triggers."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"the-basic-pattern-forward-on-no-answer","__idx":2},"children":["The basic pattern: forward on no answer"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This is the most common scenario. A caller dials in, you try a primary number, and if nobody picks up within a timeout, you try a fallback number instead. Both the primary and the fallback use the same bridge name, so whichever one answers ends up connected to the caller."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's what happens step by step:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The caller leg is answered and hears a hold prompt."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The caller joins a named bridge (creating it)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The platform dials the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["primary"]}," number."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the primary answers, the hold prompt stops and the primary joins the same bridge. Two-way audio begins. Done."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the primary doesn't answer within the timeout, the platform dials the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["fallback"]}," number."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the fallback answers, the hold prompt stops and the fallback joins the bridge with the caller."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the fallback also times out, the caller is hung up."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-the-svaml-expresses-this","__idx":3},"children":["How the SVAML expresses this"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The structure is nested: the fallback ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," lives inside the primary's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onTimeout"]}," event. That nesting ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["is"]}," the forwarding logic."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"caller dial\n  └─ onAnswer\n       ├─ play hold prompt\n       ├─ bridgeCall \"fwd-bridge\"      ← caller joins the bridge\n       └─ primary dial\n            ├─ onAnswer  → stop hold, bridgeCall \"fwd-bridge\"\n            └─ onTimeout → fallback dial\n                              ├─ onAnswer  → stop hold, bridgeCall \"fwd-bridge\"\n                              └─ onTimeout → hang up caller\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Both the caller and the destination explicitly join the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeName"]},". The caller joins first (creating the bridge); whichever destination answers joins the same one, and two-way audio begins."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"minimal-working-example-outbound-test-call","__idx":4},"children":["Minimal working example (outbound test call)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This places an outbound call to your own phone, then tries a primary number (let it ring out), and falls through to a fallback. No webhook server needed."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set your environment variables first:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"export PROJECT_ID=\"your-project-id\"\nexport KEY_ID=\"your-key-id\"\nexport KEY_SECRET=\"your-key-secret\"\nexport SINCH_NUMBER=\"+15551234567\"       # Your Sinch virtual number\nexport CALLER_NUMBER=\"+15550009999\"      # Your mobile (answer this one)\nexport PRIMARY_NUMBER=\"+15557770001\"     # Let this ring out\nexport FALLBACK_NUMBER=\"+15557770002\"    # Should ring after primary times out\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"python","__idx":5},"children":["Python"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import os, uuid, requests\n\nbody = {\n    \"commands\": [{\n        \"command\": \"dial\",\n        \"callName\": \"caller\",\n        \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": os.environ[\"SINCH_NUMBER\"]}},\n        \"to\":   {\"type\": \"PHONE\", \"phone\": {\"number\": os.environ[\"CALLER_NUMBER\"]}},\n        \"dialTimeoutDurationSeconds\": 30,\n        \"events\": {\n            \"onAnswer\": [\n                # Step 1: play hold music while we try the primary\n                {\"command\": \"messages\", \"messagesName\": \"hold\",\n                 \"messages\": [{\"type\": \"SAY\",\n                   \"say\": {\"text\": \"Connecting your call.\", \"voiceName\": \"Emma\"}}]},\n\n                # Step 2: caller joins the bridge (created on first reference)\n                {\"command\": \"bridgeCall\", \"bridgeName\": \"fwd-bridge\"},\n\n                # Step 3: dial the primary number\n                {\"command\": \"dial\",\n                 \"callName\": \"primary\",\n                 \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": os.environ[\"SINCH_NUMBER\"]}},\n                 \"to\":   {\"type\": \"PHONE\", \"phone\": {\"number\": os.environ[\"PRIMARY_NUMBER\"]}},\n                 \"dialTimeoutDurationSeconds\": 20,\n                 \"events\": {\n                     # Primary answered: stop hold, bridge them\n                     \"onAnswer\": [\n                         {\"command\": \"stopMessages\", \"messagesName\": \"hold\"},\n                         {\"command\": \"bridgeCall\", \"bridgeName\": \"fwd-bridge\"},\n                     ],\n                     # Primary didn't answer: try the fallback\n                     \"onTimeout\": [{\n                         \"command\": \"dial\",\n                         \"callName\": \"fallback\",\n                         \"from\": {\"type\": \"PHONE\", \"phone\": {\"number\": os.environ[\"SINCH_NUMBER\"]}},\n                         \"to\":   {\"type\": \"PHONE\", \"phone\": {\"number\": os.environ[\"FALLBACK_NUMBER\"]}},\n                         \"dialTimeoutDurationSeconds\": 20,\n                         \"events\": {\n                             \"onAnswer\": [\n                                 {\"command\": \"stopMessages\", \"messagesName\": \"hold\"},\n                                 {\"command\": \"bridgeCall\", \"bridgeName\": \"fwd-bridge\"},\n                             ],\n                             \"onTimeout\": [\n                                 {\"command\": \"hangup\", \"callName\": \"caller\"},\n                             ],\n                         },\n                     }],\n                 }},\n            ],\n            \"onHangup\": [\n                {\"command\": \"hangup\", \"callName\": \"primary\"},\n                {\"command\": \"hangup\", \"callName\": \"fallback\"},\n            ],\n        },\n    }]\n}\n\nresp = requests.post(\n    f\"https://voice.api.sinch.com/v2/projects/{os.environ['PROJECT_ID']}/calls\",\n    auth=(os.environ[\"KEY_ID\"], os.environ[\"KEY_SECRET\"]),\n    headers={\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": str(uuid.uuid4()),\n    },\n    json=body,\n)\nprint(resp.status_code, resp.json())\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"nodejs","__idx":6},"children":["Node.js"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"import { randomUUID } from \"crypto\";\n\nconst { PROJECT_ID, KEY_ID, KEY_SECRET,\n        SINCH_NUMBER, CALLER_NUMBER, PRIMARY_NUMBER, FALLBACK_NUMBER } = process.env;\n\nconst body = {\n  commands: [{\n    command: \"dial\",\n    callName: \"caller\",\n    from: { type: \"PHONE\", phone: { number: SINCH_NUMBER } },\n    to:   { type: \"PHONE\", phone: { number: CALLER_NUMBER } },\n    dialTimeoutDurationSeconds: 30,\n    events: {\n      onAnswer: [\n        // Step 1: play hold music while we try the primary\n        { command: \"messages\", messagesName: \"hold\",\n          messages: [{ type: \"SAY\", say: { text: \"Connecting your call.\", voiceName: \"Emma\" } }] },\n\n        // Step 2: caller joins the bridge (created on first reference)\n        { command: \"bridgeCall\", bridgeName: \"fwd-bridge\" },\n\n        // Step 3: dial the primary number\n        { command: \"dial\",\n          callName: \"primary\",\n          from: { type: \"PHONE\", phone: { number: SINCH_NUMBER } },\n          to:   { type: \"PHONE\", phone: { number: PRIMARY_NUMBER } },\n          dialTimeoutDurationSeconds: 20,\n          events: {\n            // Primary answered: stop hold, bridge them\n            onAnswer: [\n              { command: \"stopMessages\", messagesName: \"hold\" },\n              { command: \"bridgeCall\", bridgeName: \"fwd-bridge\" },\n            ],\n            // Primary didn't answer: try the fallback\n            onTimeout: [{\n              command: \"dial\",\n              callName: \"fallback\",\n              from: { type: \"PHONE\", phone: { number: SINCH_NUMBER } },\n              to:   { type: \"PHONE\", phone: { number: FALLBACK_NUMBER } },\n              dialTimeoutDurationSeconds: 20,\n              events: {\n                onAnswer: [\n                  { command: \"stopMessages\", messagesName: \"hold\" },\n                  { command: \"bridgeCall\", bridgeName: \"fwd-bridge\" },\n                ],\n                onTimeout: [{ command: \"hangup\", callName: \"caller\" }],\n              },\n            }],\n          },\n        },\n      ],\n      onHangup: [\n        { command: \"hangup\", callName: \"primary\" },\n        { command: \"hangup\", callName: \"fallback\" },\n      ],\n    },\n  }],\n};\n\nconst auth = \"Basic \" + Buffer.from(`${KEY_ID}:${KEY_SECRET}`).toString(\"base64\");\n\nconst resp = await fetch(\n  `https://voice.api.sinch.com/v2/projects/${PROJECT_ID}/calls`,\n  {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\", Authorization: auth, \"Idempotency-Key\": randomUUID() },\n    body: JSON.stringify(body),\n  }\n);\nconsole.log(resp.status, await resp.json());\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-to-expect-when-you-run-it","__idx":7},"children":["What to expect when you run it"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your phone (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CALLER_NUMBER"]},") rings. Answer it and you'll hear \"Connecting your call.\""]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PRIMARY_NUMBER"]}," rings for ~20 seconds with no answer."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Within about a second, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FALLBACK_NUMBER"]}," rings."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Answer the fallback and you get two-way audio with the caller leg."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"key-concepts-to-remember","__idx":8},"children":["Key concepts to remember"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Every leg needs a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["callName"]},"."]}," This is how you reference a specific leg later, for example when hanging up just the agent without dropping the caller."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Both sides must join the bridge."]}," The caller joins the bridge explicitly via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeCall"]}," (which creates it on first reference). Whichever destination answers also calls ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeCall"]}," with the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bridgeName"]},", joining the existing bridge. Using the same name across primary and fallback is what makes the handoff seamless."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Events drive the forwarding logic."]}," The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["events"]}," block on a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," command gives you hooks for what happens next. The ones relevant to forwarding:"]},{"$$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":"Event"},"children":["Event"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"When it fires"},"children":["When it fires"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Typical action"},"children":["Typical action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onAnswer"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Destination picked up"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Bridge the legs together"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onTimeout"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Rang for the full timeout, no answer"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dial the next number"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onBusy"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Destination returned busy"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dial the next number"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onReject"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Destination actively declined"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dial the next number"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onFailure"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Call setup failed (carrier error, unreachable)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Dial the next number"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onHangup"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A leg disconnected"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Clean up the session"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Always send an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}]}," on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /calls"]}," so a retried request doesn't accidentally place a duplicate call."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"adapting-this-pattern","__idx":9},"children":["Adapting this pattern"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To handle busy, reject, or carrier failure in addition to no-answer, add the same fallback ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dial"]}," block under ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onBusy"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onReject"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onFailure"]}," on the primary leg. SVAML doesn't support references, so each event handler needs its own copy of the fallback commands."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To make the routing dynamic (time-of-day, per-caller lookup, agent availability), switch from a static outbound call to an inbound webhook. Your server receives a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["call.incoming"]}," event and returns the same SVAML structure, but you choose the destination at runtime based on whatever your backend knows."]}]},"headings":[{"value":"Call Forwarding","id":"call-forwarding","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"The basic pattern: forward on no answer","id":"the-basic-pattern-forward-on-no-answer","depth":2},{"value":"How the SVAML expresses this","id":"how-the-svaml-expresses-this","depth":2},{"value":"Minimal working example (outbound test call)","id":"minimal-working-example-outbound-test-call","depth":2},{"value":"Python","id":"python","depth":3},{"value":"Node.js","id":"nodejs","depth":3},{"value":"What to expect when you run it","id":"what-to-expect-when-you-run-it","depth":2},{"value":"Key concepts to remember","id":"key-concepts-to-remember","depth":2},{"value":"Adapting this pattern","id":"adapting-this-pattern","depth":2}],"frontmatter":{"seo":{"title":"Call Forwarding"}},"lastModified":"2026-08-31T13:48:15.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/voice-2.0/tutorials/call-forwarding","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}