Twilio Call, use custom endpoint for xml - node.js

Using this code, i am able to receive the call and listen to the contents coming from the voice.xml.
client.calls
.create({
url: 'http://demo.twilio.com/docs/voice.xml',
from: '+16173973230',
to: '+13392153860'
})
.then(call => console.log(call.sid))
I'm trying to use my own generated twiml but when i change to
url: 'http://myserver.com/twilio/auto-message.xml',
which replies exactly the same way:
twilioRouter.get('/auto-message.xml', (req, res) => {
res.type('text/xml')
res.send(`<Response>
<Say voice="alice">Thanks for calling the E T Phone Home Service.</Say>
</Response>`)
})
I get a giant (error) log in the console and on the phone call i hear "We are sorry, an application error has occurred. Goodbye"
What am i doing wrong?

Twilio uses a POST by default. You can tell Twilio to use a GET where you configure the webhook for your phone number.

Related

Get Twilio phone number Friendly Name when forwarding SMS message using Twilio Functions

I would like to pass along the Twilio phone number's Friendly Name when I forward the SMS message to another phone number. (The Friendly Name is a property assigned to a Twilio number when it is purchased.)
This is not the same as "Send Branded SMS Messages Using Twilio Alphanumeric Sender ID" described here and here.
I am operating in the USA where the above is not supported, and I am OK including the "Friendly Name" in the body of the forwarded message (or the subject line of the email). Also, The "Friendly Name" is not associated with the original sender of the message as in the above examples, but instead is associated with my Twilio numbers. Hope that's all clear.
I am using this example code:
Forwarding SMS messages to another phone number – Twilio Support
Three parameters are passed into the function:
exports.handler = function(context, event, callback) {
context includes environment variables I configure. callback isn't relevant to this question. And for the event parameter, we have these properties:
AccountSid
ApiVersion
Body
From
FromCity
FromCountry
FromState
FromZip
MessageSid
NumMedia
NumSegments
SmsMessageSid
SmsSid
SmsStatus
To
ToCity
ToCountry
ToState
ToZip
Using Twilio Functions, I want to obtain Friendly Name, which is not a property of event. Is it possible to obtain the Friendly Name through one of the other properties? If so, how?
UPDATE: from this Twilio doc I see a clue that I can possibly get Friendly Name from AccountSid.something.outgoing_caller_id.friendlyName
I can't quite understand how to do that in a Twilio function. I tried using:
context.getTwilioClient();
The docs say that "will return an initialized REST client that you can use to make calls to the Twilio REST API." However, it returns an empty httpClient object along with strings for username, password and accountSID. I was expecting a populated object from which I could obtain the phone number's Friendly Name.
As an aside, I would like to ask what objects get passed into the event parameter. In what circumstances would the event parameter contain different properties from those I listed above?
You are well on the right path! Excellent research. In fact, context.getTwilioClient() is part of it. Once you have the Twilio REST API client initialized, you can use another Twilio API to determine what the FriendlyName is from the event.To. I found that here, Filter IncomingPhoneNumbers with exact match.
Below is one way, there certainly may may be others.
const got = require('got');
// async function to deal with async REST API call
exports.handler = async function(context, event, callback) {
const client = context.getTwilioClient();
// await an async response
await client.incomingPhoneNumbers
.list({phoneNumber: event.To, limit: 1})
.then(incomingPhoneNumbers => event.friendlyName = incomingPhoneNumbers[0].friendlyName)
.catch(err => console.log(err));
const requestBody = {
personalizations: [{ to: [{ email: context.TO_EMAIL_ADDRESS }] }],
from: { email: context.FROM_EMAIL_ADDRESS },
subject: `New SMS message from: ${event.From}`,
content: [
{
type: 'text/plain',
value: `${event.Body} - ${event.friendlyName}`
}
]
};
got
.post('https://api.sendgrid.com/v3/mail/send', {
headers: {
Authorization: `Bearer ${context.SENDGRID_API_KEY}`,
"Content-Type": 'application/json'
},
body: JSON.stringify(requestBody)
})
.then(response => {
console.log(response);
let twiml = new Twilio.twiml.MessagingResponse();
twiml.message({to: '+1555xxxxxxx'}, `You Message: ${event.Body} - ${event.friendlyName}`);
callback(null, twiml);
})
.catch(err => {
console.log(err);
callback(err);
});
};
Specific to the key's associated with the event object, this is a handy one to use.
Object.keys(event).forEach( thisKey => console.log(`${thisKey}: ${event[thisKey]}`));

Getting 11205 error when trying to use calls().update to transfer to conference room

I'm trying to move the inbound caller to a conference room:
//this is the endpoint for the voice webhook
app.post('/voice',(req,res)=>{
sid=req.body.CallSid;
conferenceName="test conference room";
params={'conferenceName':conferenceName};
url='https://appname.herokuapp.com/addToConference?conferenceName=test';
console.log('now updating inbound call sid '+sid);
client.calls(sid).update({
url:url,
method:'GET'
});
});
//this is the endpoint for adding a caller to a conference
app.get('/addToConference',(req,res)=>{
var conferenceName=req.query.conferenceName;
const response=new VoiceResponse();
response.say("Now connecting you to conference "+conferenceName);
dial=response.dial();
dial.conference(conferenceName);
responseTwiml=response.toString();
console.log("responseTwiml: "+responseTwiml);
res.send(responseTwiml);
});
Console logging shows that the .update() call is reached:
now updating inbound call sid 9j92f892309
But then the Twilio debugger shows an 11205 error, where the url is https://appname.herokuapp.com/voice/. The console log does not show Now connecting you to conference test, so I'm guessing the /addToConference endpoint isn't being reached. Heroku error log shows a Request timeout error.
How can I reach the endpoint and drop the inbound caller into a conference call? If it matters, I want the app to then call someone else, interact with them, and then transfer that call recipient to the conference where the inbound caller is waiting.
Twilio developer evangelist here.
There's a couple of issues here. To start with, the 11205 error is because of a timeout from the call to your /voice endpoint. The issue here is that you never return anything from the function with the res. You could fix that one by calling res.send('') at the end of that function.
However...
There is no need to do the redirect that you're doing at all. You can use the initial webhook response to both drop the caller into the conference and dial the other party. You would do this with the following code:
app.post('/voice',(req,res)=>{
conferenceName="test conference room";
url='https://appname.herokuapp.com/addToConference?conferenceName=' + conferenceName;
client.calls.create({
from: YOUR_TWILIO_NUMBER,
to: THE_OTHER_PERSON,
url: url
});
const response=new VoiceResponse();
response.say("Now connecting you to conference "+conferenceName);
dial=response.dial();
dial.conference(conferenceName);
responseTwiml=response.toString();
res.set('Content-Type': 'text/xml');
res.send(responseTwiml);
});
For this you will still need the /addToConference endpoint which just adds the other caller to the conference, which would look like this:
app.get('/addToConference',(req,res)=>{
var conferenceName=req.query.conferenceName;
const response=new VoiceResponse();
response.say("Now connecting you to conference "+conferenceName);
dial=response.dial();
dial.conference(conferenceName);
responseTwiml=response.toString();
console.log("responseTwiml: "+responseTwiml);
res.send(responseTwiml);
});
You could also redirect the caller in the way you wanted to do in the first place, but instead of modifying the call with the REST API you would use the TwiML <Redirect> verb. That would look like this:
app.post('/voice',(req,res)=>{
conferenceName="test conference room";
url='https://appname.herokuapp.com/addToConference?conferenceName=' + conferenceName;
client.calls.create({
from: YOUR_TWILIO_NUMBER,
to: THE_OTHER_PERSON,
url: url
});
const response=new VoiceResponse();
response.redirect(url);
responseTwiml=response.toString();
res.set('Content-Type': 'text/xml');
res.send(responseTwiml);
});
Let me know if that helps at all.

get_started button sends messaging_postbacks callbacks thrice

Hi I am using nodejs and developing a bot on facebook messenger platform. I have my webhook subscribed only to messages and messaging_postbacks events. However, when I test the bot, it seems to send callback three times. This is my webhook code
server.post('/', (req, res, next) => {
let postback = req.body.entry[0].messaging[0].postback;
if (postback.payload === 'Greet User'){
console.log(postback);
}
}
When I test my bot, the postback object gets printed thrice as below.
{ payload: 'Greet User', title: 'Get Started' }
{ payload: 'Greet User', title: 'Get Started' }
{ payload: 'Greet User', title: 'Get Started' }
Any help how to avoid it? I read in some of the posts here that I should deselect message_reads and message_deliveries subscriptions. But I do not have those selected anyways. Not sure what else I am missing? Please help me.
I have found the problem after some more searching on the net and debugging it myself. In case, if others reading this might be interested to know, the issue was I was not sending back 200 status back to facebook. I found the hint regarding the need to do that in this stack overflow post.
Facebook webhook making multiple calls for the same message?
After sending the 200 response, I m not getting this issue. So relieved :)

Attach messagingServiceSid to a twiml response in nodejs library

I have a webhook setup, and I am able to receive messages and reply to them. I would like to have the responses sent by my webhook to have messagingServiceSid attached to them.
I didn't find on documentation a way to configure that for responses from my webhook, only for new SMS using
client.sendMessage({
messagingServiceSid: 'MG9752274e9e519418a7406176694466fa',
to: '+16518675309',
body: 'Phantom Menace was clearly the best of the prequel trilogy.'
}, function(err, message) {
console.log(message);
});
Is there something similar for this code? Is it doable through the UI?
app.post('/foo/bar/sms', twilio.webhook({
host:'gassy-ocelot-129.herokuapp.com',
protocol:'https'
}), function(request, response) {
var twiml = new twilio.TwimlResponse();
twiml.message('This HTTP request came from Twilio!');
response.send(twiml);
});
Images:
No messagingService on reply messages sent using twiml response
Message Detail view from logs
Twilio developer evangelist here.
As far as I'm aware, there's no way to reply to message from a message service with TwiML.
However, rather than using TwiML, you could just send the SMS back to your user from the REST API and return an empty <Response> to the incoming webhook. Something a bit like this:
app.post('/foo/bar/sms', twilio.webhook({
host:'gassy-ocelot-129.herokuapp.com',
protocol:'https'
}), function(request, response) {
// send the message from the message service
client.sendMessage({
messagingServiceSid: 'MG9752274e9e519418a7406176694466fa',
to: request.body.From,
body: 'Your message'
}, function(err, message) {
console.log(message);
});
// send empty TwiML response
var twiml = new twilio.TwimlResponse();
response.send(twiml);
})
Let me know if that helps at all.
If you receive an incoming SMS on a phone number currently set up to that Messaging Service (via the web ui or phone number REST), then the incoming requests will have MessagingServiceSid in the query string.

Twilio: Hangup a call in an existing conference, ERROR 20404

Following situation:
Someone called my Twilio Number
Twilio requested my url
Caller gets into a conference (don't starts until a second person join)
TwiML makes call to a Mobile
The Moblie dont accept the call
=> no second Person enters the conference so it wont stop and the caller is stuck there.
My solution is to end the whole call if this happens, I already know where to place the endCall function so this is not my problem. The function looks like this (You'll find it in the twilio API too):
client.calls(accountSid).update({
status: "completed"
}, function(err, call) {
if(err){
console.log(err);
}
});
My programm logic is fine, I see that this function is called at the right place but I receive this Error:
{ status: 404,
message: 'The requested resource /2010-04-01/Accounts/AC/Calls/AC.json was not found',
code: 20404,
moreInfo: 'https://www.twilio.com/docs/errors/20404' }
I already red whats at the moreInfo url but I disqualify
the solutions there. Maybe you have an idea whats the problem with this.
Twilio developer evangelist here.
You are almost all the way there. Your problem is that you are using your accountSid when trying to update the call's status.
You need to get hold of the callSid of the original call. You will find the callSid in the parameters that you receive in the incoming webhook when the person calls your Twilio number.
app.post('/calls', function(req, res, next) {
var callSid = req.body.CallSid;
// store callSid somewhere for use later
// return TwiML to set up conference and dial your mobile number
});
You'll need to save that callSid and then use it at this point later when you want to hangup the call.
client.calls(callSid).update({
status: "completed"
}, function(err, call) {
if(err){
console.log(err);
}
});
Let me know if this helps at all.

Resources