Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The features of this demo include all of the following:
**-> **CDR Log Handling
**-> **Text Bot Ability

<br/>


What do I need to Run the Code
------------------------------
Expand All @@ -46,7 +46,7 @@ You can view or fork the code in our [Github Repo](https://github.com/signalwire
This guide uses the Python SignalWire SDK, for a guide on installation click [here](/compatibility-api/sdks).

You will need a SignalWire phone number as well as your API Credentials (API Token, Space URL, and Project ID) which can all be found in an easily copyable format within the API tab of your SignalWire portal.
<br/>


How to Run the Application
--------------------------
Expand Down Expand Up @@ -79,7 +79,7 @@ docker-compose up -d

3. The application will run on port 80

<br/>


### Build and Run Natively

Expand All @@ -88,7 +88,7 @@ docker-compose up -d

You may need to use an SSH tunnel for testing this code if running on your local machine. – we recommend [ngrok](https://ngrok.com/). You can learn more about how to use ngrok [here](/platform/basics/guides/technical-troubleshooting/how-to-test-webhooks-with-ngrok).

<br/>


Step by Step Code Walkthrough
-----------------------------
Expand All @@ -98,12 +98,12 @@ Within the Github repository, you will find several files, but we're interested
- app.py
- config.json

<br/>


### Configuring the JSON File

You can use the settings menu to enable/disable certain features such as waiting music, wait time advertisements or the language/dialect for text to speech. The use of a JSON menu to specify menus, settings, and other instructions is a feature that will save you hours of development time when setting up or customizing your call center!
<br/>


```javascript
{
Expand Down Expand Up @@ -234,12 +234,12 @@ Within the Github repository, you will find several files, but we're interested
},
```

<br/>


### Configuring the Python code

We need to start with a little housekeeping by creating an array to store our queues, opening the config.json file so that we can access the values inside, and setting our SignalWire authentication credentials. There are a few additional functions such as `getLogs()`, `cycle_check_thread()`, and `updateLogs()` that we will not review in this writeup but you can read about them in detail through line comments within `app.py`!
<br/>


```python
# Active Queues Array
Expand All @@ -258,10 +258,10 @@ SIGNALWIRE_PROJECT= ccConfig['signalwire']['project']
SIGNALWIRE_TOKEN= ccConfig['signalwire']['token']
```

<br/>


Our first function to define will be `enqueue()` which will use the [Enqueue](/compatibility-api/cxml/voice/enqueue) verb to place a caller into a specified queue. We will use the `friendlyName` parameter to indicate the queue and specify additional parameters such as the `action` URL containing instructions for what to do next and the `waitUrl` to play music.
<br/>


```python
def enqueue(queueName, action = HOSTNAME + "/enqueue_event", method = "POST", waitUrl=HOSTNAME + "/wait_music_queue", waitUrlMethod="POST"):
Expand All @@ -273,11 +273,11 @@ def enqueue(queueName, action = HOSTNAME + "/enqueue_event", method = "POST", wa
return response
```

<br/>


Our next function `dial_conference()` will use the [Dial](pathname:///compatibility-api/cxml/voice/dial) verb and the [Conference](pathname:///compatibility-api/cxml/voice/conference-noun) noun to connect an endpoint to a conference using the `friendlyName` parameter and allow to specify additional parameters such as `statusCallbackEvent` or `startConferenceOnEnter`.

<br/>


```python
def dial_conference(conferenceName, muted=False, beep=False, startConferenceOnEnter=True, endConferenceOnExit=False, statusCallbackEvent="start end join leave speaker", statusCallback=HOSTNAME + "/conference_event", statusCallbackMethod="POST"):
Expand All @@ -293,11 +293,11 @@ def dial_conference(conferenceName, muted=False, beep=False, startConferenceOnEn
return response
```

<br/>


The next function to define is `redirectByRestApi()` which uses the [Update Call API](/rest/compatibility-api/endpoints/update-a-call) to redirect it using the `callSid`. This will merge the caller into the conference with the agent assigned to the caller.

<br/>


```python
def redirectByRestApi(callSid, urlToRedirect):
Expand All @@ -314,10 +314,10 @@ def redirectByRestApi(callSid, urlToRedirect):
return "200"
```

<br/>


The next function `connect_agent_ready()` allows us to update a call by queue like in the example above, but you can use a `callSid` or say `Front` to pop the next member in the queue and merge the call. In some cases, you may not have a `callSid`! This function allows the queue to handle the update and get the next caller connected to the agent even without that parameter.
<br/>


```python
def connect_agent_ready(queueSid, callSidOrFront, agent, channel):
Expand Down Expand Up @@ -349,12 +349,12 @@ def connect_agent_ready(queueSid, callSidOrFront, agent, channel):
return "200"
```

<br/>

Now that we have displayed all the major conference functionality functions, we will move on to the routes for handling GET or POST requests! As with the previous section, we will leave out some of the housekeeping routes for clarity but you can view the detailed comments within app.py to learn more about them.

Our first route `/conference_event` will accept conference events from GET or POST. Within this route we will authenticate the SignalWire Client, look for the last conference participant, and redirect them for post conference using the `redirectByRestApi()` function we defined in the previous section.

<br/>


```python
@app.route('/conference_event', methods=['GET', 'POST'])
Expand All @@ -377,7 +377,7 @@ def conference_event():
return "200"
```

<br/>


The next app route `/wait_music_queue` will generate wait music as well as queue stat updates by utilizing our logger functions. Here we will update the queue logs and then play a message stating the caller's position in the queue, the current size of the queue, and the average queue size. If the `config.json` file has `enableWaitingAds` and `enableWaitingMusic` set to `True` in the `settings` menu, we will play waiting music and ads until the music and ads cycle has completed. At this point, we will redirect back to the same `/wait_music_queue` and increase the count by 1.

Expand Down Expand Up @@ -418,11 +418,11 @@ def wait_music_queue():
return str(response)
```

<br/>


The next few routes are quite short and perform very simple functions! `/enqueue_event` and `/voice_event` both exist to update the logs with the correct queue stats and voice stats. The `/inbound_sms` route handles the acceptance of inbound messages but does not respond.

<br/>


```python
# accepts enqueue events from GET or POST
Expand All @@ -447,11 +447,11 @@ def inbound_sms():
return "200"
```

<br/>


The next route `/post_conference` handles what to do with the caller after their call with the agent has ended but before the termination of the call. We will check the `settings` menu in the `config.json` file to see if `enableExitMessage` is set to `True`. If it is, we will play a short exit message for the caller using the verbiage in the menu. If `enableTextSummary` is set to `True`, we will use the [Create Message API](/rest/compatibility-api/endpoints/create-message) to send a message to the caller thanking them for their call. Lastly, we will check if `enableExitSurvey` is enabled. If so, we will redirect to the `/get_survey` route which will be shown below.

<br/>


```python
@app.route('/post_conference', methods=['GET', 'POST'])
Expand Down Expand Up @@ -483,11 +483,11 @@ def post_conference():
return str(response)
```

<br/>


The next route `/enter_queue` is the web entry for entering the queue. The queue name is passed through as a query string variable. If a queue with the specified name doesn't currently exist within our `ActiveQueues` array, we will use [Enqueue](pathname:///compatibility-api/cxml/voice/enqueue) to create one.

<br/>


```python
# Web entry for entering a queue, passing queue name as a querystring var
Expand All @@ -503,11 +503,11 @@ def enter_queue():
return str(response)
```

<br/>


The route `/connect_agent` is pretty straightforward - this will accept GET and POST requests in order to connect the agent to the conference with the caller.

<br/>


```python
@app.route('/connect_agent', methods=['GET', 'POST'])
Expand All @@ -519,11 +519,11 @@ def connect_agent():
return str(response)
```

<br/>


The next route `/connect_caller` is the exact opposite - it will accept GET and POST requests to connect the caller to the conference with the agent!

<br/>


```python
# connects the caller to the conference with agent
Expand All @@ -534,11 +534,11 @@ def connect_caller():
return str(response)
```

<br/>


The next route `/inbound_voice` will handle inbound calls to our phone number. We will first check the `settings` menu to see if `enableRecording` is `True` and then play an entry message for the caller using the verbiage in the `messages` submenu of the `settings` menu. We will check if any announcements should be played and then redirect the main menu of options for the caller to sort through in the `mainMenu` submenu of the `settings` menu in the `config.json` file.

<br/>


```python
@app.route('/inbound_voice', methods=['GET', 'POST'])
Expand All @@ -562,11 +562,11 @@ def inbound_voice():
return str(response)
```

<br/>


The next route `get_menu` dynamically builds the IVR menu tree from the JSON file and uses action routing to continually progress through the various submenus. We will loop through the menus starting at the main menu and ask the user to select input based on the option they'd like to select. After the input has been detected from the caller, we will reroute back to the `/get_menu` route except we will specify the next menu to rotate through. This process will continue until the user has reached an agent or ended the call.

<br/>


```python
@app.route('/get_menu', methods=['GET', 'POST'])
Expand Down Expand Up @@ -608,11 +608,11 @@ def get_menu():
return str(response)
```

<br/>


The last two routes are quite simple! `/get_survey` and `/get_voicemail` are both basic examples of routes that could take a survey after a call has ended or [gather a voicemail ](/voice/getting-started/how-to-set-up-voicemail) when an agent is not available.

<br/>


```python
# Mock survey rendering for demo
Expand All @@ -631,7 +631,7 @@ def get_voicemail():
return str(response)
```

<br/>


Wrap Up
-------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Multi-factor authentication (MFA) is used to authenticate users of an applicatio

SignalWire's [Multi-Factor Authentication](/rest/signalwire-rest/endpoints/space/request-mfa-sms) provides a simple and secure flow to request and verify tokens via REST HTTP calls. This application implements a simple flow to showcase how the API operates in a Ruby environment.

<br/>


What do I Need to Run this Code?
--------------------------------
Expand All @@ -41,7 +41,7 @@ Lastly, you will need to install some additional Ruby packages:
- [Sinatra](https://github.com/sinatra/sinatra) for quickly creating web applications in Ruby
- [Dotenv](https://github.com/bkeepers/dotenv) for managing our environment variables

<br/>


How to Run the Application
--------------------------
Expand All @@ -54,7 +54,7 @@ How to Run the Application

If you are running the application with Ruby on your computer, set up the `.env` file and then run `bundle install` followed by `bundle exec ruby app.rb`.

<br/>


Step by Step Code Walkthrough
-----------------------------
Expand Down Expand Up @@ -96,7 +96,7 @@ def make_request(action, payload)
end
```

<br/>


Next, we must verify that the token was entered correctly. For this, we will look at the SignalWire MFA API for [verifying a token](/rest/signalwire-rest/endpoints/space/verify-mfa-token). To make this request with the ruby definition below, we simple change the `mfa#{action}` to `verify` and send the token

Expand Down Expand Up @@ -134,7 +134,7 @@ post '/' do
end
```

<br/>


Wrap Up
-------
Expand Down
1 change: 0 additions & 1 deletion website/docs/main/home/calling/ai/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import UseCases from "./_usecases/_useCases.mdx";

<Subtitle>Programmable, integrated, realtime voice AI</Subtitle>

<br/><br/>

SignalWire AI is built for **unlimited programmability and scale**.
Integrate AI and deploy a MVP with low-code/no-code drag-and-drop tools, then scale your application on SignalWire's cloud platform.
Expand Down
1 change: 0 additions & 1 deletion website/docs/main/home/calling/video/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { MdRestartAlt, MdRouter, MdWeb, MdVideoCall } from "react-icons/md";

<Subtitle>Programmable, lightweight, scalable video conferencing</Subtitle>

<br/><br/>

SignalWire Video is a powerful WebRTC video conferencing tool built on an
[MCU (Multipoint Control Unit)][mcu] that handles all the muxing in the cloud.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ title: Get started with Voice

<Subtitle>Get started</Subtitle>

<br/><br/>

<DocCardList />
1 change: 0 additions & 1 deletion website/docs/main/home/calling/voice/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { MdPayment, MdBolt, MdPhone, MdRocket, MdApps, MdApi, MdCompareArrows, M

<Subtitle>Build next-generation calling applications with integrated AI, plug-and-play compatibility with other providers, and infinite scalability</Subtitle>

<br/><br/>

Whether building a UCaaS solution, modernizing a legacy IVR, augmenting CX with AI, or migrating from another provider's APIs, our comprehensive technical references and guides have you covered.

Expand Down
1 change: 0 additions & 1 deletion website/docs/main/home/calling/voice/voice-faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Accordion, AccordionGroup } from "@site/src/components/Extras/Accordion

<Subtitle>Frequently Asked Questions</Subtitle>

<br/><br/>

<AccordionGroup>
<Accordion title="How many calls per second can I send?">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ x-custom:

<Subtitle>The Campaign Registry</Subtitle>

<br/><br/>

:::warning Do I need to be a CSP?
If you intend to only create a few Brands and Campaigns then you may choose to have SignalWire act as your CSP and submit your Messaging Campaign Applications on your behalf.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ x-custom:

<Subtitle>The Campaign Registry</Subtitle>

<br/><br/>

## Does the TCR requirement apply only to SignalWire?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ x-custom:

<Subtitle>Everything you need to know</Subtitle>

<br/><br/>

If you're using an application platform (e.g. SignalWire) to send customers messages from a local phone number,
you need to register with the Campaign Registry regardless of your use case.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ slug: /messaging/getting-started/campaign-registry/registration

<Subtitle>The Campaign Registry</Subtitle>

<br/><br/>

:::info TLDR: Action Items to Start Sending Messages

Expand Down