Skip to main content

Migration from Twilio

Are you thinking of switching from Twilio to Telnyx? This document describes some key differences between the platforms as well as implementation details for standard SDK features to make your experience as smooth as possible.

How Twilio’s Voice SDK works

With Twilio, a lot of setup is required before you can get started making calls. because users are required to have their own backend in place, with Telnyx this is not needed.

TwiML is similar to Call Control that Telnyx provides - but it isn’t a requirement when using our Voice SDK.

In short, Twilio’s Voice SDK flow is as follows:

  1. Your browser / mobile device connects to Twilio
  2. Twilio connects to your pre-deployed server node application which can generate a token and receive voice webhooks
  3. Twilio sends you a webhook to get TwiML instructions
  4. Your backend server node responds with a set of TwiML instructions that you have defined for certain use cases (eg. call a number, connect to a conference)
  5. Twilio receives your TwiML instructions and executes them on your behalf. (eg. Dial a number contained in your TwiML instructions)
  6. Twilio creates a VoIP connection between your callee and your application.

Flow looks like this:

Caller > Twillio Voice SDK > Twillio Servers > customer backend (Webhook receiver) > Twillio Servers > Callee

It's much easier with the Telnyx Voice SDK

Telnyx’s Voice SDK has been designed to be as simple as possible to make/receive calls in a matter of minutes. Unlike Twilio, there is no backend setup required.

Simply, implement the Voice SDK library on the platform of your choice, and log in with your Telnyx Connection and you’re all set.

To summarize:

  1. Your browser / mobile device connects to Telnyx
  2. You send an invitation from the client
  3. If accepted, Telnyx creates a VoIP connection between your callee and your application.

Flow looks like this:

Caller > Telnyx WebRTC SDK > Telnyx servers > Callee

Optionally, if you would like to control the call, like you do with TwiML, you can use Call Control.

Pricing

Below is a comparison table for the United States region. (Note regional prices may vary).

SERVICE TELNYX ORIGINATIONTWILIO ORIGINATIONTELNYX TERMINATIONTWILIO TERMINATION
Local Calls 0.0070/ min 0.0140/ min 0.0055/ min 0.0085/ min
Toll-Free Call 0.0020/ min 0.0140/ min 0.0170/ min 0.0220/ min
Browser / App Calling 0.0020/ min 0.0040/ min 0.0020/ min 0.0040/ min
SIP Interface 0.0020/ min 0.0040/ min 0.0020/ min 0.0040/ min
Secure Media included included included included

Sources: https://telnyx.com/pricing/call-control https://www.twilio.com/en-us/voice/pricing/us

| Web | Android | iOS |


Web

Comparative Table (Web SDK)

Telnyx RTCTwilio Voice SDK
Portal and server initial configurationNo server setup is required. Create SIP connections Buy a phone number and assign it to a SIP connection.Create a TwiML App and find the TwiML App SID and configure a webhook endpoint to make outbound calls Buy a phone number to make outbound and receive inbound calls and configure a webhook to be able to receive incoming calls. Create an API KEY to be able to generate an Access Token Run a server node application to generate token and to receive the voice webhook to exec dial command.
SDK Installationnpm i @telnyx/webrtcnpm i twillio (backend) npm i @twilio/voice-sdk (front-end)
To make callsThe SDK is connected using a SIP username or JWT Token It calls directly between the browsers with the command call.newCall({...})The SDK is connected using a Token. When connecting it will return a Call object that will send a POST in Twillio Sever to /voice endpoint and in the local backend API it will exec the dial command

Connect

Telnyx

// Initialize the client
const client = new TelnyxRTC({
/* Use a JWT to authenticate (recommended) */
login_token: login_token,
/* or use your Connection credentials */
// login: username,
// password: password,
});
// Connect and login
client.connect();
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

import twilio from 'twilio';

// Download the helper library from https://www.twilio.com/docs/node/install
// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);
Note

After pasting the above content, Kindly check and remove any new line added

Make a Call

Telnyx

const call = client.newCall({
// Destination is required and can be a phone number or SIP URI
destinationNumber: '18004377950',
callerNumber: '155531234567',
});
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

client.calls
.create({
url: 'https://example.com',
to: '+15558675310',
from: '+15017122661'
})
.then(call => console.log(call.sid));
Note

After pasting the above content, Kindly check and remove any new line added

Answer an incoming Call

Note: in Twilio’s case, a backend server needs to be setup. We have included a Python flask example as well as the client implementation

Telnyx

client.on('telnyx.notification', (notification) => {
const call = notification.call;
if (notification.type === 'callUpdate' && call.state === 'ringing') {
call.answer();
}
});
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

// Backend Server, in this case Python with flask
@app.route('/handle_calls', methods=['POST'])
def call():
p.pprint(request.form)
response = VoiceResponse()
dial = Dial(callerId=twilio_number)
if 'To' in request.form and request.form['To'] != twilio_number:
print('outbound call')
dial.number(request.form['To'])
else:
print('incoming call')
caller = request.form['Caller']
dial = Dial(callerId=caller)
dial.client(twilio_number)
return str(response.append(dial))
Note

After pasting the above content, Kindly check and remove any new line added

// Client
device.on("incoming", function (conn) {
conn.accept();
});
Note

After pasting the above content, Kindly check and remove any new line added

Android

Comparative Table (Android SDK)

Telnyx RTCTwilio Voice SDK
Portal and server initial configurationNo server setup is required. Create SIP connections Buy a phone number and assign it to a SIP connection.Deployment of a TwiML. This will generate an Application SID. Create a token using the Application SID. Buy a phone number to make PSTN calls
SDK InstallationJitPackMaven Central
Android Minimum API LevelAndroid 23 (6) and higherAndroid 16 (4.1) and higher
Java CompatibilitysourceCompatibility 1.8 targetCompatibility 1.8sourceCompatibility 1.8 targetCompatibility 1.8
LanguageKotlin SDK Kotlin Sample app Compose Android Sample AppJava SDK Java Sample app
To make callsThe client is connected while the app is opened, creating an instance of TelnyxClient. With this instance of TelnyxClient you can create and receive multiple callsThe SDK is connected using a Token. When connecting it will return a Call object The SDK creates a call object once you have connected. Meaning you authenticate per call. (Or at least include a valid access token per call, tokens live for an hour)
Receiving callsIncoming calls when logged in are handled as socket messages which the SDK is listening for. When receiving an invite socket message, a Call object is made which can be answered or declined. Incoming calls when logged out are handled via FCM.All incoming calls are delivered via FCM
Push notifications setup (CLI)Create a firebase server key Create push credential in portal with firebase server key Attach push credential to a SIP connection.Create a firebase server key Use Twillio CLI to create Push Credential Twilio CLI returns a Push Credential ID You can now include Credential ID with access token request via a Voice Grant.
Push notification setup on the client applicationInclude firebase in your project with google-services.json that includes server key Generate a FCM token at launch via standard getInstance() method. Include FCM token with either credntialLogin or tokenLogin method. The device can now receive notifications when being calledInclude firebase in your project with google-services.json that includes server key This access token mentioned above is then used with a Voice.register() method which will register your mobile application with the FCM device token as well as the access token. The device can now receive notifications when being called

Connect

Note: in Twilio’s case, for their mobile SDKs, they connect and authenticate per call rather than one initial connection

Telnyx

val telnyxClient = TelnyxClient(context)
telnyxClient.connect()
telnyxClient.credentialLogin(credentialConfig)
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

val contact = (dialog as AlertDialog).findViewById<EditText>(R.id.contact)
params.put("to", contact.text.toString())
val connectOptions: ConnectOptions = Builder(accessToken)
.params(params)
.build()
activeCall = Voice.connect(this@VoiceActivity, connectOptions, callListener)
Note

After pasting the above content, Kindly check and remove any new line added

Make a Call

Telnyx

telnyxClient.call.newInvite(callerName, callerNumber, destinationNumber, clientState)
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

 val contact = (dialog as AlertDialog).findViewById&lt;EditText>(R.id.contact)
params.put("to", contact.text.toString())
val connectOptions: ConnectOptions = Builder(accessToken)
.params(params)
.build()
activeCall = Voice.connect(this@VoiceActivity, connectOptions, callListener)
Note

After pasting the above content, Kindly check and remove any new line added

Answer an incoming Call

Telnyx

 mainViewModel.getSocketResponse()
?.observe(this, object : SocketObserver<ReceivedMessageBody>() {
SocketMethod.INVITE.methodName -> {
val inviteResponse = data.result as InviteResponse
telnyxClient.call.acceptCall(inviteResponse.callId, inviteResponse.callerIdNumber)
}
})
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

 // Receive Intent from notification:
private fun handleIncomingCallIntent(intent: Intent?) {
if (intent != null && intent.action != null) {
val action = intent.action
activeCallInvite = intent.getParcelableExtra<Parcelable>(Constants.INCOMING_CALL_INVITE)
activeCallNotificationId = intent.getIntExtra(Constants.INCOMING_CALL_NOTIFICATION_ID, 0)
when (action) {
Constants.ACTION_ACCEPT -> answer()
else -> {}
}
}
}
// answer the call
private fun answer() {
activeCallInvite.accept(this, callListener)
}
Note

After pasting the above content, Kindly check and remove any new line added

iOS

Comparative Table (iOS SDK)

Telnyx RTCTwilio Voice SDK
Portal and server initial configurationNo server setup is required. Create SIP connections Buy a phone number and assign it to a SIP connection.Deployment of a TwiML. This will generate an Application SID. Create a token using the Application SID. Buy a phone number to make PSTN calls
SDK InstallationCocoapodsSPM: Recommended. Cocoapods Carthage Framework
To make callsThe client is connected while the app is opened. While connected you can make calls.The SDK is connected using a Token. When connecting it will return a Call object
Push notifications setup (Portal)Create an APNS certificate Upload the APNS certificate Assign the APNS certificate to a SIP connection.Create an APNS certificate Upload the APNS certificate: This will create a CR_ID. Assign the CR_ID to the APPLICATION_SID
Push notification setup on the client APPTo register a device for PN: We need to wait until APNS assign a new token and then connect to the client to send the PN parameters over the login message. Unregister a device from the PN is not supported The last registered device for a SIP connection is the one that will receive the push notification.Register a device for PN: Requires a deviceToken and the PushToken. The device is a relation between the TwiML app, the user and the device. You can unregister to stop getting PN The same user can be registered on multiple devices

Connect

Note: in Twilio’s case, for their mobile SDKs, they connect and authenticate per call rather than one initial connection

Telnyx

let telnyxClient = TxClient()
do {
try telnyxClient.connect(txConfig: txConfigToken)
} catch let error {
print("ViewController:: connect Error \(error)")
}
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

let connectOptions = ConnectOptions(accessToken: accessToken) { builder in
builder.params = [twimlParamTo: self.outgoingValue.text ?? ""]
builder.uuid = uuid
}
let call = TwilioVoiceSDK.connect(options: connectOptions, delegate: self)
Note

After pasting the above content, Kindly check and remove any new line added

Make a Call

Telnyx

self.currentCall = try self.telnyxClient?.newCall(callerName: "Caller name",                                           callerNumber: "155531234567",
// Destination is required and can be a phone number or SIP URI
destinationNumber: "18004377950",
callId: UUID.init())
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

  let connectOptions = ConnectOptions(accessToken: accessToken) { builder in
builder.params = [twimlParamTo: self.outgoingValue.text ?? ""]
builder.uuid = uuid
}
let call = TwilioVoiceSDK.connect(options: connectOptions, delegate: self)
Note

After pasting the above content, Kindly check and remove any new line added

Answer an incoming Call

Telnyx

 extension ViewController: TxClientDelegate {
//....
func onIncomingCall(call: Call) {
// We are automatically answering any incoming call as an example, but
// maybe you want to store a reference of the call, and answer the call after a button press.
self.myCall = call.answer()
}
}
Note

After pasting the above content, Kindly check and remove any new line added

Twilio

 // Listen for telephony notification (after prior setup)
extension ViewController: CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
NSLog("provider:performAnswerCallAction:")
performAnswerVoiceCall(uuid: action.callUUID) { success in
if success {
NSLog("performAnswerVoiceCall() successful")
} else {
NSLog("performAnswerVoiceCall() failed")
}
}
action.fulfill()
}
}
// answer the call
func performAnswerVoiceCall(uuid: UUID, completionHandler: @escaping (Bool) -> Void) {
guard let callInvite = activeCallInvites[uuid.uuidString] else {
NSLog("No CallInvite matches the UUID")
return
}
let acceptOptions = AcceptOptions(callInvite: callInvite) { builder in
builder.uuid = callInvite.uuid
}
let call = callInvite.accept(options: acceptOptions, delegate: self)
}
Note

After pasting the above content, Kindly check and remove any new line added