Conversational AI • Last Updated 6/20/2024

Voice API: How we built a custom simple voice center

We used Telnyx Call Control to build a bespoke simple voice center application for our support team.

By Odhran Reidy

staffed simple voice center

Examples using the code from this project can be found on GitHub—try it out for yourself!




At Telnyx, we've always had a soft spot for the "do-it-yourself" approach. From kitting out our office spaces with custom-built dashboards and tooling, all the way to building our own global private IP communications network from the ground up, diving in and getting our hands dirty has given us a way of expressing ourselves and our problem-solving creativity, all the while helping us to operate and serve our customers more efficiently.

In line with this organization-wide love of DIY, we set out to build our own bespoke contact center application for our industry-leading 24/7 support team. The solution was built entirely inside the Telnyx ecosystem, leveraging our Elastic SIP Trunking product for phone services and our Voice API for advanced call control capabilities.

"The goal of this project was to provide our support team control over how they wanted to handle the calling experience workflow with our customers," said Sian Lennon, an automation engineer with the Telnyx network operations team. "We’ve already seen a positive response since we’ve rolled it out. We hope that this example can provide insight and guidance for other developers who are looking at Telnyx for their telecommunication requirements."

In this deep-dive, we're going to walk you through our experience building the contact center system in TeXML. We'll discuss how we grew the solution's capabilities throughout this project and describe the process of developing a back-end Python-based service to support additional growth, expansion and flexibility.

"The goal of this project was to provide our support team control over how they wanted to handle the calling experience workflow with our customers. We’ve already seen a positive response since we’ve rolled it out, and we hope that this example can provide insight and guidance for other developers who are looking at Telnyx for their telecommunication requirements."

Choosing TeXML For Simplicity and Scalability

We had a variety of tools to choose from in building our call center, but we decided to opt for TeXML, our XML-based data structure for controlling call flows. One of the great features of TeXML is that you can make an app as simple or as complex as you need it to be, depending on the specific features you require. This makes it ideal for building a quick but scalable minimum viable product (MVP), which also serves as a solid foundation for adding more complex functionality.

A TeXML application is a precise set of actions known as verbs and nouns in an XML file, which can easily be published in any simple web server for our call center service to access. When an inbound call is received to a phone number associated with our TeXML app, our service looks for the XML file and executes the actions in the file on the received call. The main advantage of our TeXML solution is that the server hosting the XML file doesn’t do anything but serve the file, while our service is in charge of running the processes to execute the commands for the calls. So with a simple XML file published using an inexpensive hosting service, you can still handle thousands of concurrent inbound calls without load issues. Our servers are the ones actually processing the calls as long as we use TeXML with static XML files.

Building a Scalable MVP with TeXML

We started with a simple TeXML script that would receive the client's call, play a greeting and route it to all available agents. This was our first script:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Play>http://webaddresss.of.audiofile</Play>
    <Dial>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
    </Dial>
</Response>

Here's what's happening in the script:

  • The <Response> element defines the body of the TeXML document.
  • The <Play> verb plays an audio file fetched from the supplied URL. In this case, we pointed to a pre-recorded greeting file stored on our internal servers.
  • The <Dial> verb transfers the incoming call to a new destination—in this case, we've passed it SIP URIs, wrapped in <Sip> nouns, but this verb also acts on phone numbers, designated as <Number> nouns.

The main advantage here is that the <Dial> verb in the TeXML application can dial into several destinations simultaneously, simply by specifying a list of numbers, SIP URIs or a combination of the two. If an agent finishes their shift, they can unregister their SIP client so they no longer receive calls. All other agents will still be dialed, and the first to answer takes the call. Our agents are located all around the world and use a variety of their preferred softphones to handle calls; the only requirements are a stable internet connection and registration using their dedicated SIP credential connection to their nearest Telnyx SIP Proxy.

This script captures the most basic feature set required by a call center solution, but this is far from a comprehensive production-ready solution, so we started adding more features specific to our needs.

Iterating on our MVP with Redirects and Voicemail

Our support team is continuously working on various problems and platforms—from email conversations to online chats, interacting internally and externally on Slack and answering calls.

Depending on the time of day, and especially during shift hand-overs, the support team may not be immediately available to take calls when they come in. Our initial MVP script only attempted to dial agents once, so we needed to include a second dial attempt to allow for calls missed on the first dial and a third action to send any unanswered calls to voicemail.

To accomplish this, we added a <Redirect> verb to our first XML file. This verb allows a second set of actions specified in a second XML file to be executed after the first file, and this second file handles the second call attempt. This process was repeated with a third XML file to handle the voicemail option.

After these changes, our first script looked like this:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Play>http://webaddresss.of.GreetingAudiofile</Play>
    <Dial record="record-from-answer-dual">
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
        <Sip>sip:[email protected]</Sip>
    </Dial>
   <Redirect method="GET">http://webaddress.of.2ndXMLfile</Redirect>
</Response>

The second file to handle the second call attempt looked the exact same as the first, with one change. Instead of passing the URL of the second XML file to the <Redirect> verb, the file URL was swapped out for that of the third and final XML file, which looked like this:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Play>http://webaddresss.of.BusyAudiofile</Play>
    <Record recordingStatusCallback="http://AddressToSend.RecordingURL" playBeep="true">
</Response>

A simple voicemail system can be implemented with the <Record> verb of TeXML. (It even has a feature to play a beep!) We simply play an audio recording that instructs callers to leave a message after the beep, then the <Record> verb plays the beep and records a voicemail. This verb sends a webhook with the URL of the audio file so that our team can access and listen to the recording. The link is only active for 10 minutes, but the recording is stored on our Telnyx Mission Control Portal account as a back-up.

Notice in the first and second script that we also added a recording action to the <Dial> verb (record="record-from-answer-dual"). This action records all calls in case we need to go over a specific call with a client due to an issue or just for training purposes. The specifics in the action make sure the call is recorded as soon as it's answered, and the dual specifies that both sides of the call are recorded.




That's how easy it is to build a fully-featured call center system with TeXML! Our developer docs provided clear instructions for our team to follow and made it easy to start building and controlling our bespoke call flow.

Check out part two of this series to find out how we built an asynchronous Python service to host our TeXML files and open up even more avenues for customizing our solution.

If you're interested in finding out how easy it is to build a similar contact center solution for your organization, talk to an expert today.

Share on Social

Related articles

Sign up and start building.