{"slug":"swml-overview","title":"SWML — SignalWire Markup Language Overview","tags":["signalwire","swml","call-flow","voice"],"agent_summary":"SWML is JSON or YAML that defines a call flow. Covers the document shape (version, sections, main), verb categories, expression substitution, and how SWML is served (hosted file, web hook, Call Flow Builder, or generated by Python SDK).","trigger_phrases":["what is SWML","SWML document structure","SWML sections main","SWML version 1.0.0","how to host SWML","SWML vs TwiML"],"runnable":true,"markdown":"\n# SWML — SignalWire Markup Language\n\nSWML is a JSON or YAML script that describes a phone call. Each call execution loads one SWML document and runs the verbs inside it. SWML is the SignalWire equivalent of TwiML — but it is JSON-first, has a built-in `ai` verb, supports expression substitution natively, and accepts both `.json` and `.yaml`.\n\n## Document shape\n\n```yaml\nversion: 1.0.0\nsections:\n  main:\n    - answer: {}\n    - play:\n        url: \"say:Hello there.\"\n    - hangup: {}\n```\n\nEquivalent JSON:\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"sections\": {\n    \"main\": [\n      { \"answer\": {} },\n      { \"play\": { \"url\": \"say:Hello there.\" } },\n      { \"hangup\": {} }\n    ]\n  }\n}\n```\n\n`sections` is an object; `main` is the entry section. Other named sections are reachable via `goto`, `execute`, or `swml_transfer`.\n\n## How SWML is served\n\n| Source | When to use |\n|---|---|\n| Hosted file (S3, your CDN, a static URL) | Truly static flows |\n| Web hook returning SWML | Anything dynamic — flow depends on caller, time, CRM lookup |\n| Call Flow Builder export | No-code visual flow, deployed inside the SignalWire portal |\n| Python Agents SDK | Programmatic, AI-first agents (auto-generates the SWML) |\n\nSignalWire fetches the SWML each call. The endpoint must return `application/json` or `application/yaml`. A web hook can vary the SWML per call by reading the inbound request body.\n\n## Verb categories\n\n### Call control\n\n| Verb | Notes |\n|---|---|\n| `answer` | Answers the inbound call. Optional unless explicit timing matters. |\n| `hangup` | Ends the call. Reason field is for logs. |\n| `connect` | Bridges to a PSTN number, SIP URI, or another endpoint. See [connect verb](/topic/swml-connect-verb). |\n| `goto` | Jumps to another section or step inside the current document. |\n| `execute` | Fetches and runs a sub-document, returns when done. |\n| `cond` | Conditional branching (if/elif/else). |\n\n### Media\n\n| Verb | Notes |\n|---|---|\n| `play` | Plays an audio URL, ringtone, silence, or TTS via the `say:` prefix. |\n| `prompt` | Plays a prompt and gathers DTMF or speech. |\n| `record` | Foreground recording (blocking). Use for voicemail. |\n| `record_call` | Background recording (non-blocking). Use for dashboards. |\n| `live_transcribe` | Real-time transcript streaming to a webhook. |\n| `tap` | Forks audio to another endpoint for live monitoring. |\n| `denoise` | Enables noise suppression mid-call. |\n\n### AI\n\n| Verb | Notes |\n|---|---|\n| `ai` | Runs an AI agent inside the call — speech in, speech out, SWAIG functions. See [ai verb](/topic/swml-ai-verb). |\n| `context_switch` | Switches the active AI context mid-call. See [context switch](/topic/swml-context-switch). |\n\n### Queue / conference\n\n| Verb | Notes |\n|---|---|\n| `enter_queue` | Place the caller in a call queue. |\n| `join_conference` | Add the caller to a conference room. |\n| `join_room` | Join a Relay video room. |\n\n### Detection\n\n| Verb | Notes |\n|---|---|\n| `detect_machine` | Answering-machine detection — branches based on human/voicemail outcome. |\n\n## Expression substitution\n\nSWML supports inline expressions in any string field.\n\n| Pattern | Expands to |\n|---|---|\n| `%{call.from}` | Caller's E.164 number |\n| `%{call.to}` | The dialed DID |\n| `%{call.call_id}` | Unique call ID |\n| `%{call.direction}` | `inbound` or `outbound` |\n| `%{vars.<key>}` | Custom variable set earlier |\n| `%{record_call_url}` | URL of last `record_call` recording |\n| `%{record_url}` | URL of last `record` (foreground) recording |\n| `%{prompt_value}` | Speech value from last `prompt` |\n\nExpressions also accept light JavaScript:\n\n```yaml\n- play:\n    url: \"say:Your area code is %{call.from.slice(2,5)}.\"\n```\n\nIn SWAIG/data-map context the prefix is `${...}` (not `%{...}`). The `%{...}` form is the SWML in-document substitution prefix; `${...}` is the SWAIG/DataMap variable prefix.\n\n## Sections, goto, and execute\n\n`goto` is in-document jumping. `execute` is a sub-routine — fetches and runs a remote SWML, returns.\n\n```yaml\nversion: 1.0.0\nsections:\n  main:\n    - prompt:\n        play: \"say:Press 1 for sales, 2 for support.\"\n        max_digits: 1\n        terminators: \"#\"\n    - cond:\n        if: \"%{prompt_value} == '1'\"\n        then:\n          - goto:\n              section: sales\n        elif: \"%{prompt_value} == '2'\"\n        then:\n          - goto:\n              section: support\n        else:\n          - play:\n              url: \"say:Invalid choice.\"\n          - hangup: {}\n  sales:\n    - connect:\n        to: \"+15555550101\"\n  support:\n    - connect:\n        to: \"+15555550102\"\n```\n\n## Anti-patterns\n\n- Forgetting `version: 1.0.0` at the top — script fails validation.\n- Returning HTML or plain text from your webhook — must be JSON or YAML with the correct content type.\n- Calling `goto` with a section name that doesn't exist — call hangs up silently.\n- Mixing `%{...}` (SWML) and `${...}` (SWAIG/DataMap) prefixes — wrong prefix = no substitution.\n- Hosting SWML on a slow endpoint — every call pays the round-trip. Aim for sub-200ms.\n\n## See also\n\n- [SWML AI verb](/topic/swml-ai-verb)\n- [SWML connect](/topic/swml-connect-verb)\n- [SWML record and transcribe](/topic/swml-record-and-transcribe)\n- [SWML IVR and gather](/topic/swml-ivr-and-gather)\n- [Call Flow Builder](/topic/signalwire-call-flow-builder)\n","html":"<h1>SWML — SignalWire Markup Language</h1>\n<p>SWML is a JSON or YAML script that describes a phone call. Each call execution loads one SWML document and runs the verbs inside it. SWML is the SignalWire equivalent of TwiML — but it is JSON-first, has a built-in <code>ai</code> verb, supports expression substitution natively, and accepts both <code>.json</code> and <code>.yaml</code>.</p>\n<h2>Document shape</h2>\n<pre><code class=\"language-yaml\">version: 1.0.0\nsections:\n  main:\n    - answer: {}\n    - play:\n        url: \"say:Hello there.\"\n    - hangup: {}\n</code></pre>\n<p>Equivalent JSON:</p>\n<pre><code class=\"language-json\">{\n  \"version\": \"1.0.0\",\n  \"sections\": {\n    \"main\": [\n      { \"answer\": {} },\n      { \"play\": { \"url\": \"say:Hello there.\" } },\n      { \"hangup\": {} }\n    ]\n  }\n}\n</code></pre>\n<p><code>sections</code> is an object; <code>main</code> is the entry section. Other named sections are reachable via <code>goto</code>, <code>execute</code>, or <code>swml_transfer</code>.</p>\n<h2>How SWML is served</h2>\n<p>| Source | When to use |\n|---|---|\n| Hosted file (S3, your CDN, a static URL) | Truly static flows |\n| Web hook returning SWML | Anything dynamic — flow depends on caller, time, CRM lookup |\n| Call Flow Builder export | No-code visual flow, deployed inside the SignalWire portal |\n| Python Agents SDK | Programmatic, AI-first agents (auto-generates the SWML) |</p>\n<p>SignalWire fetches the SWML each call. The endpoint must return <code>application/json</code> or <code>application/yaml</code>. A web hook can vary the SWML per call by reading the inbound request body.</p>\n<h2>Verb categories</h2>\n<h3>Call control</h3>\n<p>| Verb | Notes |\n|---|---|\n| <code>answer</code> | Answers the inbound call. Optional unless explicit timing matters. |\n| <code>hangup</code> | Ends the call. Reason field is for logs. |\n| <code>connect</code> | Bridges to a PSTN number, SIP URI, or another endpoint. See <a href=\"/topic/swml-connect-verb\">connect verb</a>. |\n| <code>goto</code> | Jumps to another section or step inside the current document. |\n| <code>execute</code> | Fetches and runs a sub-document, returns when done. |\n| <code>cond</code> | Conditional branching (if/elif/else). |</p>\n<h3>Media</h3>\n<p>| Verb | Notes |\n|---|---|\n| <code>play</code> | Plays an audio URL, ringtone, silence, or TTS via the <code>say:</code> prefix. |\n| <code>prompt</code> | Plays a prompt and gathers DTMF or speech. |\n| <code>record</code> | Foreground recording (blocking). Use for voicemail. |\n| <code>record_call</code> | Background recording (non-blocking). Use for dashboards. |\n| <code>live_transcribe</code> | Real-time transcript streaming to a webhook. |\n| <code>tap</code> | Forks audio to another endpoint for live monitoring. |\n| <code>denoise</code> | Enables noise suppression mid-call. |</p>\n<h3>AI</h3>\n<p>| Verb | Notes |\n|---|---|\n| <code>ai</code> | Runs an AI agent inside the call — speech in, speech out, SWAIG functions. See <a href=\"/topic/swml-ai-verb\">ai verb</a>. |\n| <code>context_switch</code> | Switches the active AI context mid-call. See <a href=\"/topic/swml-context-switch\">context switch</a>. |</p>\n<h3>Queue / conference</h3>\n<p>| Verb | Notes |\n|---|---|\n| <code>enter_queue</code> | Place the caller in a call queue. |\n| <code>join_conference</code> | Add the caller to a conference room. |\n| <code>join_room</code> | Join a Relay video room. |</p>\n<h3>Detection</h3>\n<p>| Verb | Notes |\n|---|---|\n| <code>detect_machine</code> | Answering-machine detection — branches based on human/voicemail outcome. |</p>\n<h2>Expression substitution</h2>\n<p>SWML supports inline expressions in any string field.</p>\n<p>| Pattern | Expands to |\n|---|---|\n| <code>%{call.from}</code> | Caller's E.164 number |\n| <code>%{call.to}</code> | The dialed DID |\n| <code>%{call.call_id}</code> | Unique call ID |\n| <code>%{call.direction}</code> | <code>inbound</code> or <code>outbound</code> |\n| <code>%{vars.&#x3C;key>}</code> | Custom variable set earlier |\n| <code>%{record_call_url}</code> | URL of last <code>record_call</code> recording |\n| <code>%{record_url}</code> | URL of last <code>record</code> (foreground) recording |\n| <code>%{prompt_value}</code> | Speech value from last <code>prompt</code> |</p>\n<p>Expressions also accept light JavaScript:</p>\n<pre><code class=\"language-yaml\">- play:\n    url: \"say:Your area code is %{call.from.slice(2,5)}.\"\n</code></pre>\n<p>In SWAIG/data-map context the prefix is <code>${...}</code> (not <code>%{...}</code>). The <code>%{...}</code> form is the SWML in-document substitution prefix; <code>${...}</code> is the SWAIG/DataMap variable prefix.</p>\n<h2>Sections, goto, and execute</h2>\n<p><code>goto</code> is in-document jumping. <code>execute</code> is a sub-routine — fetches and runs a remote SWML, returns.</p>\n<pre><code class=\"language-yaml\">version: 1.0.0\nsections:\n  main:\n    - prompt:\n        play: \"say:Press 1 for sales, 2 for support.\"\n        max_digits: 1\n        terminators: \"#\"\n    - cond:\n        if: \"%{prompt_value} == '1'\"\n        then:\n          - goto:\n              section: sales\n        elif: \"%{prompt_value} == '2'\"\n        then:\n          - goto:\n              section: support\n        else:\n          - play:\n              url: \"say:Invalid choice.\"\n          - hangup: {}\n  sales:\n    - connect:\n        to: \"+15555550101\"\n  support:\n    - connect:\n        to: \"+15555550102\"\n</code></pre>\n<h2>Anti-patterns</h2>\n<ul>\n<li>Forgetting <code>version: 1.0.0</code> at the top — script fails validation.</li>\n<li>Returning HTML or plain text from your webhook — must be JSON or YAML with the correct content type.</li>\n<li>Calling <code>goto</code> with a section name that doesn't exist — call hangs up silently.</li>\n<li>Mixing <code>%{...}</code> (SWML) and <code>${...}</code> (SWAIG/DataMap) prefixes — wrong prefix = no substitution.</li>\n<li>Hosting SWML on a slow endpoint — every call pays the round-trip. Aim for sub-200ms.</li>\n</ul>\n<h2>See also</h2>\n<ul>\n<li><a href=\"/topic/swml-ai-verb\">SWML AI verb</a></li>\n<li><a href=\"/topic/swml-connect-verb\">SWML connect</a></li>\n<li><a href=\"/topic/swml-record-and-transcribe\">SWML record and transcribe</a></li>\n<li><a href=\"/topic/swml-ivr-and-gather\">SWML IVR and gather</a></li>\n<li><a href=\"/topic/signalwire-call-flow-builder\">Call Flow Builder</a></li>\n</ul>\n"}