Using masked numbers for voice and messaging using Node.js, MySQL, and Express Routes

Notice: This post uses a legacy version of our API. Visit our developer portal to view current API documentation.
A while back we talked about the nature of masked numbers. Masked numbers are especially useful for allowing two-way communication between users while protecting each user’s identity. Your users can talk to each other without feeling like they are revealing too much by using their personal phone numbers.
Masked numbers also easily allow you to prevent communication between two users once they no longer need to communicate. Users feel secure knowing they can’t be contacted by the other party once the connection is no longer needed or wanted.
npm Packages
Once you initiate your package.json, you will need the following packages:
- body-parser
- express
- mysql
- node-bandwidth
Setting Up server.js
Your server.js should look similar to the following:
//requirements
const express = require("express");
const bodyParser = require("body-parser");
//initialize app
const app = express();
const port = process.env.PORT || 3000;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
require("./routes/routes.js")(app);
//listen
app.listen(port, function() {
console.log("App listening on PORT " + port);
});
Using MySQL
MySQL is one among many database tools you can use to store the matching pairs of user numbers that will communicate through a masking number. The database needs to be set up so that when a Bandwidth callback comes in from a phone call or text message (SMS or MMS), the database can be queried by the receiving Bandwidth number and your server can automatically find the other user’s number and can forward along the call or message.
Here is an example of a MySQL schema that can easily be used to mask numbers.
CREATE TABLE masks (
maskingNum VARCHAR(16) NOT NULL,
num1 VARCHAR(16) NOT NULL,
num2 VARCHAR(16) NOT NULL,
PRIMARY KEY (maskingNum)
);
If you want two numbers to be connected through a masking number, all you have to do is insert an entry into your MySQL database that stores the first user number, the second user number, and the masking number that connects them, as below.
INSERT INTO masks(maskingNum, num1, num2) VALUES ("{{MASKING_NUM}}", "{{NUM1}}", "{{NUM2}}");
Setting Up Routes with Connections
To prepare for your voice and messaging routes, you need to set up your requirements and your connections that will power your routes.
As for requirements, the below are needed:
const bandwidth = require("node-bandwidth");
const mysql = require('mysql');
Now, for your connections, one to your Bandwidth client and one to your MySQL database.
const client = new bandwidth({
userId : “{{userId}}”,
apiToken : “{{token}}”,
apiSecret : “{{secret}}“
});
const connection = mysql.createConnection({
host : “{{host}}”,
user : “{{user}}“,
password : “{{password}}“,
database : “{{database}}”
});
connection.connect();
Setting Up the Message Callback Route
What happens in this masked numbers project is that your express routes listen for messaging and voice callback events in order to trigger the masking process.
Callbacks are event notifications sent to your server. They happen for incoming messages, incoming calls, calls being answered, conferences being created, DTMF digits being pressed, digit Gathers ending, and a plethora of other events within the Voice and Messaging platform. For more information on callbacks, check out our documentation on callbacks here.
To set up a route that listens for incoming messages, we will do the following.
//set up a post route named “messageCallback”
app.post("/messageCallback", (req, res) => {
//detect if the eventType is “sms” and direction is “in”
if (req.body.eventType == "sms" && req.body.direction == “in”) {
//query your MySQL database to what numbers are connected via the “to” Bandwidth number
connection.query("SELECT * FROM masks WHERE maskingNum = " + req.body.to, (error, results, field) => {
//if the “from” number is equal to num1, use num2 as the outgoing “to” number
if (results[0].num1 == req.body.from) {
//creating a new outgoing message where “from” is the connecting Bandwidth number, “to” is num2, and “text” is the text from the original message
client.Message.send({
from : req.body.to,
to : results[0].num2,
text : req.body.text
}).then(() => {
//end response after message is sent
res.end();
});
//if the “from” number is equal to num2, use num1 as the outgoing “to” number
} else if (results[0].num2 == req.body.from) {
//creating a new outgoing message where “from” is the connecting Bandwidth number, “to” is num1, and “text” is the text from the original message
client.Message.send({
from : req.body.to,
to : results[0].num1,
text : req.body.text
}).then(() => {
//end response after message is sent
res.end();
});
}
});
//end the response in the event that the request eventType is not “sms” or the request direction is not “in”
} else res.end();
});
Setting up The Voice Callback Route
Like the messaging callback route, the voice callback route listens for an incoming communication to mask. Unlike the messaging route, which creates a new message containing the original message’s text content, the voice callback route uses the transfer function of Bandwidth’s Voice and Messaging API to connect the incoming call to a Bandwidth phone number and then to an outgoing call from a Bandwidth number. Hence, the two numbers are connected via the masking Bandwidth number.
To set up a route that listens for incoming calls, we do the following.
//set up a post route named “voiceCallback”
app.post("/voiceCallback", (req, res) => {
//check for that eventType is “incomingcall”
if (req.body.eventType == "incomingcall") {
//query your MySQL database to what numbers are connected via the “to” Bandwidth number
connection.query("SELECT * FROM masks WHERE maskingNum = " + req.body.to, (error, results, field) => {
//if the “from” number is equal to num1, use num2 as the transferTo number
if (results[0].num1 == req.body.from) {
//transfer the call to num2
client.Call.transfer(req.body.callId, {
transferTo : results[0].num2,
transferCallerId: req.body.to
}).then(() => {
//end the response
res.end();
});
//if the “from” number is equal to num2, use num1 as the transferTo number
} else if (results[0].num2 == req.body.from) {
//transfer the call to num1
client.Call.transfer(req.body.callId, {
transferTo: results[0].num1,
transferCallerId: req.body.to
}).then(() => {
//end the response
res.end();
});
}
});
//end the response if eventType does not equal “incomingcall”
} else res.end();
});
Ending the Connection
In order to the end the connection between two numbers through a masking number, simply delete the connection stored in your MySQL database. If the connection does not exist in your database, there is no way for the two numbers to remain connected. Be sure to add a way to handle MySQL errors in case a number tries to connect using a masking number, but a connection does not exist in the database for that masking Bandwidth number.
Go do it!
The above code provides an example of a simple implementation of masked numbers using the Bandwidth Voice and Messaging API. To see a repository with the full sample code for this app, go here. Be sure to check out our API documentation at dev.bandwidth.com for more details on how to use the API. If you haven’t yet, sign up for a trial on our Voice and Messaging Platform at app.bandwidth.com.