Ruby: Make a call from browser using Twilio - ruby

I want to call from my browser to customer phone number using Twilio. I am using toturial of Twilio. I have already an account that I am using for sending sms to my users. Now I want to make phone calls too. This is the code that I am using at my controller
account_sid = "My Twilio account SID"
auth_token = "My Twilio auth"
sender = "My Twilio from number"
capability = Twilio::Util::Capability.new account_sid, auth_token
capability.allow_client_outgoing "My Twilio Twiml app sid"
#capability.allow_client_incoming "jenny"
#token = capability.generate
And this is the javascript code
Twilio.Device.setup("<%= #token %>", {debug: true});
Twilio.Device.ready(function (device) {
$("#log").text("Ready");
});
Twilio.Device.error(function (error) {
$("#log").text("Error: " + error.message);
});
Twilio.Device.connect(function (conn) {
$("#log").text("Successfully established call");
});
Twilio.Device.disconnect(function (conn) {
$("#log").text("Call ended");
});
Twilio.Device.incoming(function (conn) {
$("#log").text("Incoming connection from " + conn.parameters.From);
// accept the incoming connection and start two-way audio
conn.accept();
});
function call() {
// get the phone number to connect the call to
params = {"PhoneNumber": $("#number").val()};
Twilio.Device.connect(params);
}
function hangup() {
Twilio.Device.disconnectAll();
}
But when I try to load my page, it gives me Error: No valid account. I have double checked my credentials and same credentials are successfully sending sms but here it is creating problem. Can any one guide me what Am I doing wrong?
I am doing it on localhost

Megan from Twilio here. You mention you're on localhost. You would need to make your URL publicly accessible. If you're not ready for production, testing with something like Ngrok will allow you to tunnel your localhost to a publicly available URL.

Related

Is Single Sender Validation in Sendgrid possible without logging in?

Was just wondering if it's possible for Single Sender Validation to be completed without having to login to Sendgrid as part of the process (e.g. click-through without login). For context, sometimes the people who "own" a mail address that we want to use for sending don't have access to Sendgrid, and we'd like them to be able to validate it. I think they can't by design, but wanted to confirm.
Looking at the API documentation, it looks like you can use the token sent in the validation email to complete the validation process, but I'm not sure if there's any way to effectively make use of that to redirect the user back to a process we control. There's another post that mentions the same kind of challenge, but thought I'd ask again as there wasn't anything definitive.
Is there a simple way to have the user who receives the validation redirect back to something other than sendgrid directly?
Thanks in advance!
The only alternative to logging in is to use the SendGrid API.
First, you either request the verification using the UI, or you use the Create Verified Sender Request API to start the verification for the single sender.
Then, the verification email will be sent to the specified email address which contains the verification URL. Usually, this URL will redirect you the the actual URL containing the verification token, as mentioned in the SO post you linked.
Once you get the verification token, you can use the Verify Sender Request API, passing in the verification token, to verify the single sender.
Note: All these APIs require a SendGrid API key.
So technically, you could have an application that prompts your user for their email address to verify, then uses the SendGrid API to start the verification which sends the verification email, then ask the user to go to their email inbox and copy in their verification link, then let the user paste in the URL from which you can extract the verification token, and use the API to verify. While the user didn't have to log in, it still requires some manual work.
However, the inputting of the email address and the checking the email inbox can also be done programmatically, so this process can be 100% automated, although it takes quite a bit of programming.
Here's a C# sample:
using System.Net;
using Microsoft.AspNetCore.WebUtilities;
using SendGrid;
namespace VerifySender;
internal class Program
{
public static async Task Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddUserSecrets<Program>(optional: true)
.Build();
var apiKey = configuration["SendGrid:ApiKey"]
?? Environment.GetEnvironmentVariable("SENDGRID_API_KEY")
?? throw new Exception("SendGrid API Key not configured.");
var client = new SendGridClient(apiKey);
// replace this JSON with your own values
const string data = """
{
"nickname": "Orders",
"from_email": "orders#example.com",
"from_name": "Example Orders",
"reply_to": "orders#example.com",
"reply_to_name": "Example Orders",
"address": "1234 Fake St",
"address2": "PO Box 1234",
"state": "CA",
"city": "San Francisco",
"country": "USA",
"zip": "94105"
}
""";
var response = await client.RequestAsync(
method: SendGridClient.Method.POST,
urlPath: "verified_senders",
requestBody: data
);
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"Failed to request sender verification. HTTP status code {response.StatusCode}.");
Console.WriteLine(await response.Body.ReadAsStringAsync());
Console.WriteLine(response.Headers.ToString());
}
Console.WriteLine("Enter verification URL:");
var verificationUrl = Console.ReadLine();
var token = await GetVerificationTokenFromUrl(verificationUrl);
response = await client.RequestAsync(
method: SendGridClient.Method.GET,
urlPath: $"verified_senders/verify/{token}"
);
if (!response.IsSuccessStatusCode)
{
Console.WriteLine($"Failed to verify sender. HTTP status code {response.StatusCode}.");
Console.WriteLine(await response.Body.ReadAsStringAsync());
Console.WriteLine(response.Headers.ToString());
}
}
private static async Task<string> GetVerificationTokenFromUrl(string url)
{
/*
* url could be three different types:
* 1. Click Tracking Link which responds with HTTP Found and Location header to url type 2.
* 2. URL containing the verification token:
* https://app.sendgrid.com/settings/sender_auth/senders/verify?token=[VERIFICATION_TOKEN]&etc=etc
* 3. URL prompting the user to login, but contains url 2. in the redirect_to parameter:
* https://app.sendgrid.com/login?redirect_to=[URL_TYPE_2_ENCODED]
*/
const string verificationBaseUrl = "https://app.sendgrid.com/settings/sender_auth/senders/verify";
const string loginBaseUrl = "https://app.sendgrid.com/login";
if (url.StartsWith(verificationBaseUrl))
{
var uri = new Uri(url, UriKind.Absolute);
var parameters = QueryHelpers.ParseQuery(uri.Query);
if (parameters.ContainsKey("token"))
{
return parameters["token"].ToString();
}
throw new Exception("Did not find token in verification URL.");
}
if (url.StartsWith(loginBaseUrl))
{
var uri = new Uri(url, UriKind.Absolute);
var parameters = QueryHelpers.ParseQuery(uri.Query);
if (parameters.ContainsKey("redirect_to"))
{
url = $"https://app.sendgrid.com{parameters["redirect_to"]}";
return await GetVerificationTokenFromUrl(url);
}
throw new Exception("Did not find token in verification URL.");
}
var clientHandler = new HttpClientHandler();
clientHandler.AllowAutoRedirect = false;
using var httpClient = new HttpClient(clientHandler);
var response = await httpClient.GetAsync(url);
if (response.StatusCode == HttpStatusCode.Found)
{
var uri = response.Headers.Location;
return await GetVerificationTokenFromUrl(uri.ToString());
}
throw new Exception("Did not find token in verification URL.");
}
}
Take note of the comments inside of GetVerificationTokenFromUrl. Since I don't trust the user to copy the URL from the email without clicking on it, I added support for three types of URL:
Click Tracking Link which responds with HTTP Found and Location header to url type 2.
URL containing the verification token: https://app.sendgrid.com/settings/sender_auth/senders/verify?token=[VERIFICATION_TOKEN]&etc=etc
URL prompting the user to login, but contains url 2. in the redirect_to parameter: https://app.sendgrid.com/login?redirect_to=[URL_TYPE_2_ENCODED]
Here's the full source code on GitHub.

Botframework | Twilio WhatsApp Adapter: how to fix "request doesn't contain a valid Twilio Signature"

I need to use Twilio as a channel for a chatbot (Bot Framework V4 NodeJS and the Twilio WhatsApp Adapter)
Messages send to Twilio via WhatsApp do reach the chatbot as a request. In the chatbot itself the validation of the request keeps failing.
const { TwilioWhatsAppAdapter } = require('#botbuildercommunity/adapter-twilio-whatsapp');
const whatsAppAdapter = new TwilioWhatsAppAdapter({
accountSid: '<Sid from Twilio console >',
authToken: '<>Auth token from Twilio console',
phoneNumber: '<phone number from Whatsapp Sandbox settings in Twilio>',
endpointUrl: 'url from Sandbox setting in Twilio'
});
The adapter is using a Twilio module. Twilio.validateRequest keeps returning false.
const signature = req.headers['x-twilio-signature'] || req.headers['X-Twilio-Signature'];
const authToken = this.settings.authToken;
const requestUrl = this.settings.endpointUrl;
const message = await this.retrieveBody(req);
return Twilio.validateRequest(authToken, signature, requestUrl, message);
I would appreciate some guidance. Otherwise I will need to figure our a way to debug this module
tnx
For the endpointUrl parameter I use is the one from my chatbot: https://mybot.azurewebsites.net/api/whatsapp/messages
for the phoneNumber parameter I tried multiple formats without succes:
whatsapp:+1XXXXXXXXXX
whatsapp:1XXXXXXXXXX
+1XXXXXXXXXX
1XXXXXXXXXX
I checked the source of the adapter and there are two possible causes.
No x-twilio-signature header. I checked the request headers and there seems to be a valid x-twilio-signature header in there.
The result of the twilio.validateRequest returns false. This method is taking authToken, signature, requestUrl and message. I checked them all and they seem fine.

API Gateway Websockets not sending to all clients

I'm using websockets with API Gateway and dynamoDB to maintain all connection IDs.
What I'm trying to do is when a new message comes in, a message is sent to all connected clients.
For example, inside the $default route a message will be received from the client. I'm then querying dynamo to get all connected ids and sending that message.
Querying dynamo:
const params = {
TableName: process.env.CONNECTIONS_TABLE,
IndexName: process.env.CONNECTIONS_COMPANY_INDEX,
KeyConditionExpression: "company = :company",
ExpressionAttributeValues: {
":company": data.company,
},
};
const response = await dynamodb.query(params).promise();
response.Items.forEach(async (item) => {
try {
await apig
.postToConnection({
ConnectionId: item.connectionId,
Data: JSON.stringify(data),
})
.promise();
} catch (e) {
if (e.statusCode === 410) {
console.log(e)
}
}
});
The issue I'm having is that it's only received on the clients after the second attempt. So the client sends a message "123" (the above code is run successfully and I've verified it's getting all connections, no errors) but nothing is received by the client. The client sends another message - "456", now both clients will receive the "123" message.
Any ideas why this would happen? I'd expect that each message sent, would receive the same message to all connected clients, not delayed and always one behind.
Thank you!
i faced with exact same issue. Then i just Remove integration response from the API gateway and leave the function return {}
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-routes-integrations.html#apigateway-websocket-api-overview-integrations-differences
In the HTTP protocol, in which requests and responses are sent
synchronously; communication is essentially one-way. In the WebSocket
protocol, communication is two-way. Responses are asynchronous and are
not necessarily received by the client in the same order as the
client's messages were sent. In addition, the backend can send
messages to the client.

The twilio module in Parse Cloud is missing latest APIs

Based on the API documentation on twilio.com, twilio.availablePhoneNumbers('COUNTRY_CODE').mobile.get() should exist. I should be able to call something like this below:
twilio.availablePhoneNumbers('US').mobile.get({
smsEnabled: true
}).then(function(searchResults) {
....
});
But when I used twilio module provided inside Parse cloud code, twilio.availablePhoneNumbers('COUNTRY_CODE').local and twilio.availablePhoneNumbers('COUNTRY_CODE').tollFree are available.
Am I wrong?
I need to programmatically acquire a phone number in the cloud code. If twilio on Parse cloud code is limited, how can I use the latest twilio APIs?
Twilio developer evangelist here.
The Twilio module on Parse is indeed outdated. I am currently working with their team to get an updated version available for developers like yourself.
In the meantime, you could use a normal HTTP request on Parse without the Twilio module to make calls like the one you are after. Something like this might work for now:
var accountSid = 'AC123...'; // your account SID
var authToken = 'xyzabc...'; // your auth token
var countryCode = 'US'; // the country code you want to search within
var url = 'https://';
url += accountSid + ':' + authToken + '#'; // add auth to URL
url += 'api.twilio.com/2010-04-01/Accounts/';
url += accountSid;
url += '/AvailablePhoneNumbers/';
url += countryCode;
url += '/Mobile.json';
Parse.Cloud.httpRequest({
url: url,
}).then(function(httpResponse) {
// success
console.log(httpResponse.text);
// httpResponse.data is the parsed JSON response
},function(httpResponse) {
// error
console.error('Request failed with response code ' + httpResponse.status);
});
You might want to check out the documentation for Parse's Parse.Cloud.httpRequest. It's available here: https://parse.com/docs/cloudcode/guide#cloud-code-advanced

Backbone/JS: looking to access the Twilio SMS API via an AJAX call

Looking to set up Twilio's SMS service so that when a user presses a certain button, it leverages my account with Twilio to send a text.
Using Backbone.js with coffeescript, and this has to be done client-side for the moment, so I'm doing something like this:
events: {
"click .button": "sendText"
}
and then sendText looks like this:
sendText: ()->
accountSid = '{my account sid}'
authToken = '{my auth token}'
ToNumber = "{string of a number to text to}"
FromNumber = "{string of my Twilio number}"
Body = escape("Hey, this is working.")
myJSONData = "To=%2B1" + ToNumber + ", From=%2B1" + FromNumber + ", Body=" + Body
$.ajax({
type: 'POST',
url: 'https://api.twilio.com/2010-04-01/Accounts/'+ accountSid + '/SMS/Messages',
data: myJSONData,
success: (data) -> {
console.log('SMS sent successfully!')
}
})
Is this heading in the right direction? I know that I haven't entered my auth credentials anywhere yet, but I'm not certain where to do that yet.
You shouldn't, under any circumstance, have your authToken (and the situation is worse as you're also including your account sid) available for anyone who wants to see you source code.
With that info, I can provision numbers on your behalf, make calls, return numbers... You just can't do it on the client side.
You should connect (using Ajax if you want) to your server, which in turn would connect to twilio passing your credentials. That way, the only one who knows them is your server.

Resources