I implemented conference call in Twilio, but it doesn't work. The error is:
Error: 11200 HTTP retrieval failure
In more details :
405 - HTTP verb used to access this page is not allowed.
Code:
string AccountSid = "...";
string AuthToken = ".....";
var twilio = new TwilioRestClient(AccountSid, AuthToken);
string appversion = twilio.ApiVersion;
ArrayList participants = new ArrayList();
// participants.Add("+972599223072");
participants.Add(txtphone1.Text);
participants.Add(txtphone2.Text);
participants.Add(txtphone3.Text);
participants.Add(txtphone4.Text);
participants.Add(txtphone5.Text);
participants.Add(txtphone6.Text);
participants.Add(txtphone7.Text);
// Go through the participants array and call each person.
foreach (string user in participants)
{
if (user != "")
{
var options = new CallOptions();
options.Url = "http://sandbox4.eureeca.com/Conference/conference.xml";
options.To = user;
options.From = "+97243741357";
options.Method = "POST";
options.Record = true;
// options.StatusCallback = "/2010-04-01/Accounts/" + AccountSid + "/Calls";
var call = twilio.InitiateOutboundCall(options);
Console.WriteLine(call.Sid);
}
Code END
Conference.xml content :
<?xml version="1.0" encoding="utf-8" ?>
<Response>
<Say>Joining a conference room</Say>
<Dial>
<Conference>MyConference</Conference>
</Dial>
</Response>
Twilio evangelist here.
Looks like you're TwiML is in a static XML file? Its pretty common for web servers to not allow POST requests to static files. You can either reconfigure your web server to allow this, or change the CallOptions Method property to `GET' to tell Twilio to make a GET request for the file rather than a POST.
Hope that helps.
Related
Am trying to setup a soft phone in browser, via TWiML app.
I created the following:
A page on my own server which serves TWiML to dial a number, say '+11111111111'.
A TWiML app which points to that page
A Twilio number which points to that app.
A page on my server which creates a Twilio Device associated with the app and buttons to run device.connect() or device.register()
The device is setup correctly, as I can register and connect with no errors.
The app works - the phone rings at +111 when I press "Call Using Twilio" button on the TWiML app page, when I call the number pointing to the TWiML app, and when I press the button on my own page. Yay!
What I cannot figure out:
How to answer the phone using the Twilio Device.
The device registers with no issue, so why doesn't it get incoming calls?
How to call other numbers aside from the one in my app.
I did in device.connect({params: {To: '+2222222222'}}), why doesn't it call that number?
Here are all the relevant pages:
calls.pug:
doctype html
html(lang="en")
head
meta(charset="utf-8")
title Browser Calls
body
input#call(type="submit" value="call")
input#register(type="submit" value="register")
pre
script(src="/js/twilio-sdk/twilio.js")
script(type="module" src="/js/calls.js")
[client] calls.js
const $ = css => document.querySelector(css);
const echo = msg => $('pre').innerText += msg + "\n";
var device;
async function setupDevice(){
let data = await fetch('/token/new');
data = await data.json();
device = new Twilio.Device(data.token);
device.on("error",
err => echo("Twilio.Device Error: " + err.message));
echo ('Device setup complete.')
}
$('#register').addEventListener('click', async e => {
if (!device) await setupDevice();
device.on("registered", conn =>
echo('Ready to accept incoming calls.')
);
device.on("incoming", call =>
echo('Incoming call to device')
);
device.register()
});
$('#call').addEventListener('click', async e => {
if (!device) await setupDevice();
let params = { To: '+22222222222' }
device.connect({ params })
});
[node] token.js
const express = require('express');
const router = express.Router();
const AccessToken = require('twilio').jwt.AccessToken;
const VoiceGrant = AccessToken.VoiceGrant;
const config = require('../config');
router.get('/new', function (req, res) {
const accessToken = new AccessToken(
config.accountSid, config.apiKey, config.apiSecret, {identity: 'SG'}
);
const grant = new VoiceGrant({
outgoingApplicationSid: config.appSid,
incomingAllow: true,
});
accessToken.addGrant(grant);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ token: accessToken.toJwt() }));
});
module.exports = router;
Twilio developer evangelist here.
How to answer the phone using the Twilio Device.
The device registers with no issue, so why doesn't it get incoming calls?
To direct a call to the Device, you need to return TwiML that <Dial>s the <Client> with the ID of your access token ("SG" in this case).
So, if you want calls to your Twilio number to be directed to this client you should update the Twilio number's incoming webhook to point to a URL that returns this:
<Response>
<Dial>
<Client>
<Identity>SG</Identity>
</Client>
</Dial>
</Response>
How to call other numbers aside from the one in my app.
I did in device.connect({params: {To: '+2222222222'}}), why doesn't it call that number?
Currently, it sounds like you point the Device to a TwiML app that responds with static TwiML that dials your example number '+11111111111'. To use the parameters, you will need to make that TwiML dynamic, by returning it from your Node server instead. The parameters are sent to the TwiML endpoint, so you can then use them in the response.
Here is an example Express endpoint that would work for you:
const express = require('express');
const router = express.Router();
const { VoiceResponse } = require("twilio").twiml;
const config = require('../config');
router.use(express.urlencoded({ extended: false }));
router.post("/call", function(res, res) {
const To = req.body;
const twiml = new VoiceResponse();
const dial = twiml.dial({ callerId: config.twilioNumber });
dial.number(To);
res.set("Content-Type", "text/xml");
res.send(twiml.toString());
});
module.exports = router;
Sending a message from Twilio is succesful, now i want to be able to enter the TO phone number the message body from a form, but i'm not sure which method is the best. I'm thinking maybe calling a variable from another ViewController but i am not sure if that would work, suggestions?
Here is my twilio controller
public IActionResult Sendsms()
{
var accountSid = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
var authToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
TwilioClient.Init(accountSid, authToken);
var to = new PhoneNumber("+XXXXXXXXXXXXXXX");
var from = new PhoneNumber("+XXXXXXXXXXXXXXXX");
var message = MessageResource.Create(to: to,
from: from,
body: "this is the ship that made the kessel run in 14 parsecs?");
return Content(message.Sid);
}
I am trying to set up a hunt group with Twilio Twiml
Do I have to set up a different twimlbin for each number in the hunt group?
Or is there a way to join all this together into a single Twimlbin?
Twimlbin 1:
<Response>
<Dial
action="http://www.ourapp.com/webhook;FailUrl=/Twimlbin 2"
timeout="10"
callerId="555-555-5555">
NUMBER1
</Dial>
</Response>
Twimlbin 2:
<Response>
<Dial
action="http://www.ourapp.com/webhook;FailUrl=/Twimlbin 3"
timeout="10"
callerId="555-555-5555">
NUMBER2
</Dial>
</Response>
... Repeat N times for each agent ...
Thank you :-)
Twilio developer evangelist here.
TwiML Bins are great for static bits of TwiML, but your use case needs a bit more than that.
I recommend you check out Twilio Functions which allow you to run Node.js code in Twilio's infrastructure. I've built and tested a version of this that works with Twilio Functions.
Here's an explanation of how it works:
Start with an array of your numbers:
const numbers = [...];
Then, in the function, check if the callstatus is completed and hang up if it is.
exports.handler = function(context, event, callback) {
const response = new Twilio.twiml.VoiceResponse();
if (event.DialCallStatus === "complete" || event.finished) {
// Call was answered and completed or no one picked up
response.hangup();
} else {
If it's not, we work out the next number to call. If you have the next number in the URL. If you do save it to a variable, otherwise pick the first number in the array:
const numberToDial = event.nextNumber ? event.nextNumber : numbers[0];
Then, assign the next number to dial from the array.
let url;
const currentNumberIndex = numbers.indexOf(numberToDial);
if (currentNumberIndex + 1 === numbers.length) {
// no more numbers to call after this.
url = "/hunt?finished=true";
} else {
const nextNumber = numbers[currentNumberIndex + 1];
url = "/hunt?nextNumber=" + encodeURIComponent(nextNumber);
}
Then generate the TwiML to Dial the next number and pass the URL as the action. You can add your own URL as the statusCallbackUrl to keep a track of the statuses.
const dial = response.dial({ action: url });
dial.number({ statusCallback: "https://yourapp.com/statuscallback" }, numberToDial);
}
callback(null, response);
}
I can't promise this will work, but I hope you see where I'm going with it. Let me know if it helps at all.
I created TwiML application and set Voice request URL the web deployed ASP.NET-MVC aplication action method: http://voiceapp-001-site1.myasp.net/voice
This action method is invoked when somebody goes to the URL posted above:
public ActionResult Voice() {
Response.ContentType = "text/xml";
// put a phone number you've verified with Twilio to use as a caller ID number
string callerId = Settings.TwilioNumber;
// put your default Twilio Client name here, for when a phone number isn't given
string number = "jenny";
// get the phone number from the page request parameters, if given
if (Request["PhoneNumber"] != null) {
number = Request["PhoneNumber"];
}
// wrap the phone number or client name in the appropriate TwiML verb
// by checking if the number given has only digits and format symbols
string numberOrClient;
var m = Regex.Match(number, #"^[\d\+\-\(\) ]+$");
if (m.Success) {
numberOrClient = string.Format("<Number>{0}</Number>", number);
} else {
numberOrClient = string.Format("<Client>{0}</Client>", number);
}
ViewBag.CallerId = callerId;
ViewBag.NumberOfClient = numberOrClient;
return View();
}
The Voice view looks like:
<?xml version="1.0" encoding="UTF-8" ?>
<response>
<dial callerid="#ViewBag.CallerId">
#Html.Raw(ViewBag.NumberOfClient)
</dial>
</response>
Then I try to make test call:
but after 13 seconds call is automatically terminated and In the error log I get:
Notification SID NOe85ffe80dfc52e81f942a7414c9f7c9c
Warning 12200 Schema validation warning
Description Cannot find the declaration of element 'response'.
But below in the Body section I can see the element response:
Hi Twilio developer evangelist here.
Can you try modifying your view to look like this instead?
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Dial callerId="#ViewBag.CallerId">
#Html.Raw(ViewBag.NumberOfClient)
</Dial>
</Response>
Remember XML is case-sensitive, so the casing in your XML tags actually matter. Also, I would suggest using the Twilio.TwiML helper library. With that, you can get your XML generated for you with the right casing, and avoiding typos altogether.
Here's how you'd do it:
var twiml = new TwilioResponse();
var dialAttributes = new {callerId = "48326304351"};
var dial = twiml.Dial("+15555555555", dialAttributes);
return TwiML(dial);
Using Twilio API I managed to make a call and play one audio file, but I did not succeed to play two files. how can I do it?
Here is my code:
public HttpResponseMessage Call(string callToNumber, string audioUrl)
{
// Set our Account SID and AuthToken
var accountSid = ConfigurationManager.AppSettings["ACCOUNT_SID"];
var authToken = ConfigurationManager.AppSettings["AUTH_TOKEN"];
var twilioNumber = ConfigurationManager.AppSettings["TwilioMobileNumber"];
// Instantiate a new Twilio Rest Client
var client = new TwilioRestClient(accountSid, authToken);
// Initiate a new outbound call
var call = client.InitiateOutboundCall
(
twilioNumber,
callToNumber,
audioUrl
// ,audioUrl2 -- I want to add another file
);
return Request.CreateResponse(HttpStatusCode.OK);
}
Twilio evangelist here.
Is the audiofile variable just a URL to a wav or mp3? If it is, then you'll need to change that to a URL that can return some TwiML that includes two <Play> verbs, like this:
<Response>
<Play>http://example.com/music1.mp3</Play>
<Play>http://example.com/music2.mp3</Play>
</Response>
Hope that helps.