Recipes← all recipesView on GitHub

Move a TwiML app by changing the endpoint

VoiceTwilio migration (TwiML compatibility)

Point your TwiML app at SignalWire's compatible REST endpoint and credentials while keeping the same call request and XML response.

migration

The claim

The compatibility API page, https://signalwire.com/docs/compatibility-api, says to “update the base URL from api.twilio.com to your-space.signalwire.com”. It adds that this “is not required if using the SignalWire Compatibility SDK”. It also says “Your existing TwiML/cXML response handlers work without modification”. The SDK’s compat namespace builds every path as /api/laml/2010-04-01/Accounts/<project id>/... on your Space. The project id sits where Twilio had the account SID, and the API token is the password; the SDK sets that basic-auth pair in rest/_base.py:38 (self._session.auth = (project, token)). The verifier proves the path and the body, not the credentials, which the recorder never sees. The compat spec’s Calls create requires To and From and takes Url, “The URL to handle the call”. The handler is a Flask route that returns the TwiML document as text/xml, and the document is the one you had.

How it works

CXML = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        "<Response>\n"
        "  <Say voice=\"Polly.Salli\">{greeting}</Say>\n"
        "  <Hangup/>\n"
        "</Response>\n")

def place(to):
    return client.compat.calls.create(To=to, From=FROM, Url=VOICE_URL)

@app.post("/voice")
def voice():
    return Response(CXML.format(greeting=GREETING), mimetype="text/xml")

What the platform receives, then what it fetches from you:

POST /api/laml/2010-04-01/Accounts/<project id>/Calls
{"To": "+1555YYYYYYY", "From": "+1555XXXXXXX", "Url": "https://<your-host>/voice"}

POST https://<your-host>/voice
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say voice="Polly.Salli">Thanks for calling Ridgeline Cycles. The workshop opens at nine.</Say>
  <Hangup/>
</Response>

RestClient() reads the Space, project id and token from the environment; the compat client is client.compat. That is the whole of the change on the REST side. The handler did not change at all.

Limitations

You prove the request and the document. Which TwiML verbs and attributes the platform runs is defined by the public cXML reference. <VirtualAgent> is deprecated, <Play> inside <Gather> has no digits, and <Start>, <Siprec>, <Autopilot>, <Client> and <Task> have no reference pages. Check your handlers’ verbs against the reference before you move.

The document here is static. A handler that reads request parameters keeps reading the same names; the compat spec documents them under the Calls webhooks.

What to change first

Change CXML to answer with <Response><Say>Hello</Say></Response> and run the verifier. The children assertion fails on the missing Hangup, and the greeting assertion on the text. The verifier pins the document, because the document is the part you brought with you.