T
Telephony SOPKnowledge Base
Search
← All topics

SWML — SignalWire Markup Language Overview

runnable

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).

signalwireswmlcall-flowvoice
Agent trigger phrases: what is SWML · SWML document structure · SWML sections main · SWML version 1.0.0 · how to host SWML · SWML vs TwiML

SWML — SignalWire Markup Language

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 ai verb, supports expression substitution natively, and accepts both .json and .yaml.

Document shape

version: 1.0.0
sections:
  main:
    - answer: {}
    - play:
        url: "say:Hello there."
    - hangup: {}

Equivalent JSON:

{
  "version": "1.0.0",
  "sections": {
    "main": [
      { "answer": {} },
      { "play": { "url": "say:Hello there." } },
      { "hangup": {} }
    ]
  }
}

sections is an object; main is the entry section. Other named sections are reachable via goto, execute, or swml_transfer.

How SWML is served

| Source | When to use | |---|---| | Hosted file (S3, your CDN, a static URL) | Truly static flows | | Web hook returning SWML | Anything dynamic — flow depends on caller, time, CRM lookup | | Call Flow Builder export | No-code visual flow, deployed inside the SignalWire portal | | Python Agents SDK | Programmatic, AI-first agents (auto-generates the SWML) |

SignalWire 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.

Verb categories

Call control

| Verb | Notes | |---|---| | answer | Answers the inbound call. Optional unless explicit timing matters. | | hangup | Ends the call. Reason field is for logs. | | connect | Bridges to a PSTN number, SIP URI, or another endpoint. See connect verb. | | goto | Jumps to another section or step inside the current document. | | execute | Fetches and runs a sub-document, returns when done. | | cond | Conditional branching (if/elif/else). |

Media

| Verb | Notes | |---|---| | play | Plays an audio URL, ringtone, silence, or TTS via the say: prefix. | | prompt | Plays a prompt and gathers DTMF or speech. | | record | Foreground recording (blocking). Use for voicemail. | | record_call | Background recording (non-blocking). Use for dashboards. | | live_transcribe | Real-time transcript streaming to a webhook. | | tap | Forks audio to another endpoint for live monitoring. | | denoise | Enables noise suppression mid-call. |

AI

| Verb | Notes | |---|---| | ai | Runs an AI agent inside the call — speech in, speech out, SWAIG functions. See ai verb. | | context_switch | Switches the active AI context mid-call. See context switch. |

Queue / conference

| Verb | Notes | |---|---| | enter_queue | Place the caller in a call queue. | | join_conference | Add the caller to a conference room. | | join_room | Join a Relay video room. |

Detection

| Verb | Notes | |---|---| | detect_machine | Answering-machine detection — branches based on human/voicemail outcome. |

Expression substitution

SWML supports inline expressions in any string field.

| Pattern | Expands to | |---|---| | %{call.from} | Caller's E.164 number | | %{call.to} | The dialed DID | | %{call.call_id} | Unique call ID | | %{call.direction} | inbound or outbound | | %{vars.<key>} | Custom variable set earlier | | %{record_call_url} | URL of last record_call recording | | %{record_url} | URL of last record (foreground) recording | | %{prompt_value} | Speech value from last prompt |

Expressions also accept light JavaScript:

- play:
    url: "say:Your area code is %{call.from.slice(2,5)}."

In SWAIG/data-map context the prefix is ${...} (not %{...}). The %{...} form is the SWML in-document substitution prefix; ${...} is the SWAIG/DataMap variable prefix.

Sections, goto, and execute

goto is in-document jumping. execute is a sub-routine — fetches and runs a remote SWML, returns.

version: 1.0.0
sections:
  main:
    - prompt:
        play: "say:Press 1 for sales, 2 for support."
        max_digits: 1
        terminators: "#"
    - cond:
        if: "%{prompt_value} == '1'"
        then:
          - goto:
              section: sales
        elif: "%{prompt_value} == '2'"
        then:
          - goto:
              section: support
        else:
          - play:
              url: "say:Invalid choice."
          - hangup: {}
  sales:
    - connect:
        to: "+15555550101"
  support:
    - connect:
        to: "+15555550102"

Anti-patterns

  • Forgetting version: 1.0.0 at the top — script fails validation.
  • Returning HTML or plain text from your webhook — must be JSON or YAML with the correct content type.
  • Calling goto with a section name that doesn't exist — call hangs up silently.
  • Mixing %{...} (SWML) and ${...} (SWAIG/DataMap) prefixes — wrong prefix = no substitution.
  • Hosting SWML on a slow endpoint — every call pays the round-trip. Aim for sub-200ms.

See also