Trouble with Twilio / TwiML statusCallback using Node.js - node.js

When a user texts my number, I would like to respond with a message using TwiML. I'd also like to know whether my response message sends or fails. I'm creating my TwiML response using the Twilio library for Node.js.
Here is my code:
const response = new twilio.TwimlResponse();
response.message(Response, {
statusCallback: '/sms/status/'
});
Here is the code for the route. Please note that the router is mounted upon the "/sms/" router:
router.post('/status/', acceptRequestsOnlyFromTwilio, (req, res) => {
const Event = require('./../models/schemas/event');
const event = new Event({
description:
`MessageSid = ${req.body.MessageSid}
MessageStatus = ${req.body.MessageStatus}`
});
event.save();
console.log(
`MessageSid = ${req.body.MessageSid}
MessageStatus = ${req.body.MessageStatus}`
);
res.sendStatus(200);
});
When I check my logs using the Heroku CLI, I don't log nor do I see a record when I check MongoDB.
Anyone have any ideas or tips on how I can go about debugging this or if I'm implementing this incorrectly?
Thanks for you time!

Twilio developer evangelist here.
Firstly, have you set your Messaging request URL for the Twilio phone number you are using? Is it pointing at the correct route for your Message TwiML response?
Also, your first code block should also be within a router.post endpoint for your server. Do you correctly return the TwiML response as the server response?
As a tip, it might be better to develop this application locally and test your webhook endpoints using a tool like ngrok. I love using ngrok to test webhooks.

Related

Getting Invalid signature on incoming request with botBuilder adapter for Facebook

I have successfully deployed this example repo to azure and it is now working in the web chat and on slack.
Now I'm trying to use the facebook adapter in my bot. I have followed the instructions to use FacebookAdapter with BotBuilder and added the following code into index.js
const { FacebookAdapter } = require('botbuilder-adapter-facebook');
const restify = require('restify');
const adapter = new FacebookAdapter({
verify_token: process.env.FACEBOOK_VERIFY_TOKEN,
app_secret: process.env.FACEBOOK_APP_SECRET,
access_token: process.env.FACEBOOK_ACCESS_TOKEN
});
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.use(restify.plugins.queryParser());
server.get('/api/messages', (req, res) => {
if (req.query['hub.mode'] === 'subscribe') {
if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY_TOKEN) {
const val = req.query['hub.challenge'];
res.sendRaw(200, val);
} else {
console.log('failed to verify endpoint');
res.send('OK');
}
}
});
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async(context) => {
await context.sendActivity('I heard a message!');
});
});
server.listen(process.env.port || process.env.PORT || 3000, () => {
console.log(`\n${ server.name } listening to ${ server.url }`);
});
also in my .env file I have added the various tokens and secrets required.
When I try testing the app locally with bot framework emulator I get the error
(node:11588) UnhandledPromiseRejectionWarning: Error: Invalid signature on incoming request
at FacebookAdapter.<anonymous> (/home/ronald/Desktop/03.welcome-users/node_modules/botbuilder-adapter-facebook/lib/facebook_adapter.js:421:23)
at Generator.next (<anonymous>)
at /home/ronald/Desktop/03.welcome-users/node_modules/botbuilder-adapter-facebook/lib/facebook_adapter.js:15:71
I'm not sure what I'm doing wrong
Unfortunately, this appears to be a bug of some variety. An issue already exists on the Botkit Github repo with various customers experiencing a similar problem, however there is no fix at this time. It seemingly doesn't affect all customers, as the Botkit developer (at the time of his posting) was able to use the adapter without error.
In looking into your problem, I was able to determine that the error is generated from the verifySignature() method in the FacebookAdapter class. There should be an "x-hub-signature" header returned from Facebook which is used to check the signature of the request payload for the webhook event. For unknown reasons, this header is missing which results in the "invalid signature" message.
I would recommend you comment on the above GH issue to help facilitate work on the problem.
Hope of help!
-----EDIT-----
The Facebook Adapter is designed to work independently of the Azure Bot Service / ABS Channels, even when integrated with a BotFramework bot. As such, it will not work with BotFramework Emulator. It is designed to connect directly to the bot's adapter.
This also means you need to adjust the Webhook Callback URL in your Facebook app settings to point to your locally running bot. The webhook value, when configured for ABS looks something like:
https://facebook.botframework.com/api/v1/bots/[botname].
You will want to adjust it to point to your ngrok endpoint (used for tunneling between your local bot and external sources like Facebook). The new webhook value would look something like this:
https://1a04e4ad.ngrok.io/api/messages.
Don't forget to include the verify token which also comes from Facebook (found in the settings).
Assuming you've changed the webhook url, supplied the verify token, and are NOT using Emulator, then it should work seemlessly.
Note: Facebook sends echos and delivery confirmations for every event passed. The result is, if you don't filter on incoming event types or turn off additional events in Facebook, then your bot will be hit continuously.

Twiml Connect method issue

So i'm trying to make it so an outbound call gets redirected to my Autopilot system, but my Twiml does seem to recognize the connect function built into the voice response method
I've tried to have the account sid be provided, call, and even load the link in a browser, it just gives the same error
Heres the code im using
exports.handler = function(context, event, callback) {
let res = new Twilio.twiml.VoiceResponse();
console.log(res.toString());
res.connect().autopilot(context.AI_SID);
console.log(res.toString());
callback(null, res);
};
It should return the code below, but seems like this doc is not accurate: https://www.twilio.com/docs/voice/twiml/connect
<Response>
<Connect>
<Autopilot>#####</Autopilot>
</Connect>
</Response>
Update the Twilio helper libraries under your Twilio Functions, Configure, to use a release that added this verb.
https://github.com/twilio/twilio-node/blob/master/CHANGES.md

How to add a "say" message to the beginning of conference using Twilio API in Nodejs

This is my code and it is working perfectly for creating a conference by calling two numbers. However, I wanted to add a message at the beginning of the conference to say "Hello, you will be contacted shortly"
I read that I can use ngrok to create the URL with the XML response but ngrok is not working for me. because ngrok urls are only working for me when the code is still running locally. so If I stop the Twilio script that I wrote to generate this URL from running locally the ngrok URL stops working.
function CallTwilio(number1, number2) {
const Twilio = require('twilio');
var accountSid = 'XXX';
var authToken = 'YYY';
const client = Twilio (accountSid, authToken);
[number1, number2].forEach(function(number_i) {
client.calls.create({
url: 'https://handler.twilio.com/twiml/EH05a82ce144a55344f0d39ac6b20204f1',
to: number_i,
from: 'mynumber',
})
.then((call) => onprogress.stdout.write('Called'));
});
}
Twilio developer evangelist here.
I note that when you create the call you pass a url which is a TwiML Bin. My guess is that your TwiML Bin code looks a bit like:
<Response>
<Dial><Conference>Conference name</Conference></Dial>
</Response>
If you want to <Say> a message before the person you call enters the conference, then you need to adjust this to include the <Say> before the <Dial>. Like this:
<Response>
<Say>Hello, you will be connected shortly.</Say>
<Dial><Conference>Conference name</Conference></Dial>
</Response>

How to use Twilio to send SMS, and wait for response from phone to finish request in NodeJS

I know how to send an SMS via Twilio to a phone number specified in the request body, however I need a way for this route to wait for the user to respond with a text message. I need to capture that messages body and send it as a response.
router.post('/', function(req, res){
var customerNumber = req.body.mobileNumber;
var twilioNumber = process.env.TWILIO_NUMBER;
client.messages
.create({
to: '+1' + customerNumber,
from: twilioNumber,
body: 'message to user',
provideFeedback: 'true',
}, function(err, message){
if(err) res.send('message err: ' + err);
else{
// wait 10-20 seconds for user to respond
res.send("A response from the user");
}
})
});
I also know how to listen to responses with Twilio, but this doesn't work because I need the above route to respond with the message I get from the user in the route below.
router.post('/sms-response', function(req, res){
var twilio = require('twilio');
var twiml = new twilio.twiml.MessagingResponse();
twiml.message('thanks for your feedback');
res.writeHead(200, {'Content-Type':'text/xml'});
res.end(twiml.toString());
});
I've been looking for a way to do this all day with no success at all. I appreciate your help!
I dont know if that is possible yet, I went through their documentation and didnt see that feature yet. I would suggest using a web socket like socket.io. When message comes in you can just pass the response in through the socket to the user.
Twilio developer evangelist here.
While this could technically be possible I strongly recommend against it. You mention that you might be waiting for 10-20 seconds, but users are much more fickle than that, as are mobile networks. So getting a response may take much longer that that or even never happen. Then you'd be left with a long running connection to your server waiting for a response that might never come.
As Hammer suggested, it would be better to return a response to the user straight away, saying something like "We're waiting for your response", then connecting that user's browser to your server via a websocket or server sent event stream. When you receive the incoming message on your webhook endpoint, you can then send the information down the websocket or event source and react to that in the front end.
Let me know if that helps at all.

how to connect two anonymous callers together using twilio

I am currently doing using node js twilio module for a functionality in a project that i am working on for a client. Basically the server is going to initiate a call using twilio api to call a certain person A the connect him to another person B. I am new to twilio so i am still a noob, but this is the code i have written so far. Please i need u guys input on how to achieve this. cheers
var client = require('twilio')(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN);
exports.makeCall = function(callDetails, cb) {
client.makeCall({
to:'+16515556677', // Any number Twilio can call
from: TWILIO_CALLER_ID,
url: 'https://demo.twilio.com/welcome/voice' // A URL that produces an XML document (TwiML) which contains instructions for the call
}, function(err, responseData) {
//executed when the call has been initiated.
console.log(responseData.from); // outputs "+14506667788"
var resp = new client.TwimlResponse();
resp.say('Welcome to Acme Customer Service!')
.gather({
action:'http://www.example.com/callFinished.php',
finishOnKey:'*'
}, function() {
this.say('Press 1 for customer service')
.say('Press 2 for British customer service', { language:'en-gb' });
});
});
};
Twilio developer evangelist here.
You're part way there with this, but you don't want to be creating a TwiML response in the callback to your call to client.makeCall. The responseData there is a representation of the call in Twilio's system.
What you need to do is provide a URL to the makeCall function that hosts some TwiML that connects the call to another phone number. Currently you have the demo URL in place, so you'll need to point that to a URL that you own.
There's a very good in depth tutorial on how to accomplish all of this on the Twilio site which you might find helps out. You can find the tutorial here, give it a go and let me know if that helps.

Resources