Twilio call routing/management for small customer service team - twilio

I am trying to create a phone system with Twilio Javascript client SDK for a small customer service team with the following criteria:
each Client can see if multiple calls are coming in at the same time and choose which one to answer
each Client can transfer a call to another Client
From what I can tell there is no way to see multiple incoming calls
Which means, when transferring a call, if the phone is also ringing at the same time, the Client who is to be receiving the transferred call cannot see/accept the incoming call.
We have a small team (between 2-4 Clients online at any one time) working from the same office. It seems like TaskRouter is the only viable option but feels like overkill considering the size of our team and the simplicity of the problem I am trying to solve.
Any help would be much appreciated.

Twilio developer evangelist here.
This is what TaskRouter was designed for, though I understand that it may be overkill for the size of the team.
You could place all incoming calls into a queue using <Enqueue> (without a workflow ID) and then query the Queue resource to display all the current incoming calls. Then when you choose to answer or redirect the call, you can eject it from the queue using the REST API too, then directing it on to <Dial> the <Client> of choice.
Let me know if that points you in the right direction.

I thought I'd answer my own question as I have solved this problem for myself.
Nowhere in any of the docs or stack overflow questions I read did I see any mention that handling multiple incoming calls is possible within the browser with the JavaScript SDK. However, I have been able to do so. It seems that each Twilio.Device() can have multiple Connections. So by creating a new phone container as outlined bellow, you can manage each separately.
HTML
<div id="main_container">
<div class="phone_container" call_sid="">
<div class="well well-sm call-status">
Connecting to Twilio...
</div>
<div class="phone_btn_container">
<button class="btn btn-md btn-success answer-button" disabled>Answer</button>
<button class="btn btn-md btn-danger hangup-button" disabled>End</button>
<button class="btn btn-md btn-default mute-button" disabled>Mute</button>
</div>
</div>
</div>
Javascript
device.on('incoming', function(connection) {
// get call sid
var call_sid = connection.parameters.CallSid
// get phone container which holds the buttons and call status etc.
var phone_container = $('.phone_container')
// if there is only one container and it's empty, use this to handle call
if (phone_container.length == 1 && phone_container.attr('call_sid') == '') {
// set call sid to container
$('.phone_container').attr('call_sid', call_sid)
}
// else clone phone container for new call
else {
// clone , set call sid and append to main container
$('.phone_container').first().clone().attr('call_sid', call_sid).appendTo($('#main_container'))
}
});
In regards to transferring calls, I have used conference rooms to manage this. Similar to Devin Rader's answer to this question: Twilio - How to move an existing call to a conference

Related

Microsoft Graph API Subscriptions endpoint provides #odata.nextLink that gives a 404

I'm currently experiencing an issue with the subscriptions endpoint.
When making a call to https://graph.microsoft.com/v1.0/subscriptions, a next link is returned.
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions",
"#odata.nextLink": "https://graph.microsoft.com/v1.0/subscriptions?$skiptoken=NPt3S7g2KIxJBA0KWwQetRhFtPT2ht6ZVYoisBCCtvlN2050CZg8WeNGnmaMqUn.....",
"value": [
...
...
When following this next link, most of the time, more results and another nextLink should be provided until all the data has been returned.
However for the last two days we have been experiencing issues where following this link has led to the final link giving a 404 response and some html with the following body.
<body>
<div id="header"><h1>Server Error</h1></div>
<div id="content">
<div class="content-container"><fieldset>
<h2>404 - File or directory not found.</h2>
<h3>The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable.</h3>
</fieldset></div>
</div>
</body>
Is this a known issue with the service, or is there a process that should be being followed differently here?
I have been able to replicate this in Postman as well as impacting the java sdk here.
Thank you for your help.
As of 2021-10-13, this issue is no longer occurring and the Graph API is once again functioning as expected.

Get Auth0 access token via command line

I am force to use an unergonomic web site (let’s call it zzz) that uses auth0 for authentication, and a REST API internally, and I have a strong desire to use the API directly.
Using the browser inspector, I can see how that API works, and if I use the JWT Access Token (transmitted using Authorization: Bearer) that I find there, I can script access to API.
The problem I am facing is getting such a JWT access token via auth0, given my username and password.
When I use the browser-based login, I see that zzz redirects me to
https://zzz.eu.auth0.com/login
?state=g6…mo
&client=uz…6j
&protocol=oauth2
&response_type=token%20id_token
&redirect_uri=https%3A%2F%2Ffoo.zzz.com%2Fcallback
&scope=openid%20read%3Amore%20scopes…
&audience=zz-api-prod
&nonce=0G…L7
&auth0Client=ey…n0%3D
(line breaks for your convenience)
I can now manually enter username and password, and get logged in, which seems to perform these steps:
A POST to
https://zzz.eu.auth0.com/usernamepassword/login
with a body of
{ "client_id":"uz…6j",
"redirect_uri":"https://foo.zzz.com/callback",
"tenant":"zzz",
"response_type":"token id_token"
"connection":"zzz-production-users",
"username":"…",
"password":"…",
"nonce":"0G…L7",
"state":"g6…mo",
"sso":true,
"_intstate":"deprecated",
"_csrf":"fb…KI",
"audience":"zzz-api-prod",
"auth0Client":"ey…n0=",
"scope":"openid read:stores more:scopes …",
"protocol":"oauth2"
}
and a response of
<form method="post" name="hiddenform" action="https://zzz.eu.auth0.com/login/callback">
<input type="hidden" name="wa" value="wsignin1.0">
<input type="hidden"
name="wresult"
value="ey…tE">
<input type="hidden" name="wctx" value="…">
<noscript>
<p>
Script is disabled. Click Submit to continue.
</p><input type="submit" value="Submit">
</noscript>
</form>
The JS on the login page seems to press that submit button, causing a POST to
https://zzz.eu.auth0.com/login/callback
which redirects to
https://foo.zzz.com/callback
#access_token=ey…7Q
&scope=openid%20read%3Amore%20scopes…
&expires_in=7200
&token_type=Bearer
&state=%7B%7D
&id_token=ey…Sg
… which contains the precious access token that I want.
Trying to script this precise flow, which would involve parsing the returned HTML to extract the wctx and wresult arguments, is quite tedious.
So my question is:
Is there a way to get the access_token some other way that is more convenient to script using just command line curl, or maybe some simple python code/library?
I have tried various things that I found on the auth0 documentation website (e.g. https://auth0.com/docs/api-auth/tutorials/password-grant#realm-support), but could not get them to work; presmably because they need to be explicitly enabled by zzz in their auth0 settings?
The correct approach should be a separation between these:
Unergonomic web site (Client A) - which uses the implicit flow
Web API
Client B (your command line) - which uses a different flow
In Auth0 you should configure a new OAuth Client Entry for Client B, which should probably use a different flow - perhaps the password grant you mention.
You will at least be able to get a token in this manner. Whether the API accepts calls from you may depend on other design aspects.

Quickbooks Online - How to implement SSO with intuit in Ruby/Rails

I was able to connect with to Intuit using the Minimul/QboApi gem and get the "Connect to Quickbooks" button working with oauth2 based on the example provided on Github. However neither the gem nor the samples show how to implement single sign on with Intuit. In the example provided by Minimul, the Connect To Quickbooks button is produced by intuit's javascript found at https://appcenter.intuit.com/Content/IA/intuit.ipp.anywhere-1.3.5.js
and a setup script and the tag . The tag appears to have been deprecated. Or at least, it doesn't appear to do anything other than produce the button with the right text and logo on it.
But bottom line, I have been unable to find any documentation on the ipp.anywhere.js package, and not even sure if i's meant to used with oauth2 since it's not mentioned anywhere. I believe that the connect to intuit button does the right things, but the guidelines seem pretty strict about what that the button needs to say the right thing and have th eright logo or they will reject it in the store. They also seem to suggest that users are much more likely to try something if an SSO with Intuit workflow is enabled. Any help appreciated.
After some further work, I figured out a solution that can create a 'log in with Inuit button' , although it's a bit of a javascript hack. First, I determined that the only thing I really needed to change was the button image. In other respects the code behind ` works fine for either a "login with intuit" or "connect to intuit work flow" . The only problem is the button image.
Here is the code (adapted from Minimul/QboApi) to get access and oauth2 refresh tokens via a "Connect to Quickbooks" button.
Setup in the controller code in login or sessions controller:
def new
#app_center = QboApi::APP_CENTER_BASE # "https://appcenter.intuit.com"
state= SecureRandom.uuid.to_s
intuit_id = ENV["CLIENT_ID"]
intuit_secret = ENV["CLIENT_SECRET"]
client = Rack::OAuth2::Client.new(
identifier: intuit_id,
secret: intuit_secret,
redirect_uri: ENV["OAUTH_REDIRECT_URL"],
uthorization_endpoint:"https://appcenter.intuit.com/connect/oauth2",
token_endpoint: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
response_type: "code"
)
#make sure to include at least "openid profile email"
#in the scope to you can retrieve user info.
#uri = client.authorization_uri(scope: 'com.intuit.quickbooks.accounting openid profile email phone address', state: state)
end
Here is the code required to generate the button on the view. (The view needs to load jquery as well in order for the script to work.)
<script type="text/javascript" src="<%= #app_center %>/Content/IA/intuit.ipp.anywhere-1.3.5.js">
</script>
<script>
intuit.ipp.anywhere.setup({
grantUrl: "<%== #uri %>",
datasources: {
quickbooks: true,
payments: false
}
});
</script>
<div>
<ipp:connecttointuit></ipp:connecttointuit>
This code produces the following html on the page delivered to the client:
<ipp:connecttointuit>
Connect with QuickBooks
</ipp:connecttointuit>
This code produces a button with the Connect with QuickBooks image, and an event handler inside intuit.ipp.anywhere-1.3.5.js attaches itself to the click event.
The problem is that the button is styled by the class=intuitPlatformConnectButton attribute inside the generated <a> tag, so if you want a "login with intuit button instead of a connect with intuit button the class on the anchor needs to be changed to class='intuitPlatformLoginButtonHorizontal' but still needs to attach to the event handler defined for <ipp:connecttointuit>. The best solution that doesn't require mucking with intuit.ipp.anywhere is to create the connect button and hide it, and then create another tag styled with class=intuitPlatformLoginButtonHorizontal whose click event calls click on the hidden connect button. I use AngularJs on my login page, so I handle the click with ng-click, but it could be done simply with jquery alone.
new.html.erb:
<div>
</div>
<div>
<ipp:connecttointuit id="connectToIntuit" ng-hide="true">< </ipp:connecttointuit>
</div>
and the controller code:
$scope.intuit_login = function() {
let el = angular.element("#connectToIntuit:first-child")
el[0].firstChild.click();
}
This will result in a redirect upon authentication to the supplied redirect url, where you can use openid to get the user credentials.

Is there a way to get the twitter share count for a specific URL?

I looked through the API documentation but couldn't find it. It would be nice to grab that number to see how popular a url is. Engadget uses the twitter share button on articles if you're looking for an example. I'm attempting to do this through javascript. Any help is appreciated.
You can use the following API endpoint,
http://cdn.api.twitter.com/1/urls/count.json?url=http://stackoverflow.com
Note that the http://urls.api.twitter.com/ endpoint is not public.)
The endpoint will return a JSON string similar to,
{"count":27438,"url":"http:\/\/stackoverflow.com\/"}
On the client, if you are making a request to get the URL share count for your own domain (the one the script is running from), then an AJAX request will work (e.g. jQuery.getJSON). Otherwise, issue a JSONP request by appending callback=?:
jQuery.getJSON('https://cdn.api.twitter.com/1/urls/count.json?url=http://stackoverflow.com/&callback=?', function (data) {
jQuery('#so-url-shares').text(data.count);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="so-url-shares">Calculating...</div>
Update:
As of 21st November 2015, this way of getting twitter share count, does not work anymore. Read more at: https://blog.twitter.com/2015/hard-decisions-for-a-sustainable-platform
This is not possible anymore as from today, you can read more here:
https://twitter.com/twitterdev/status/667836799897591808
And no plans to implement it back, unfortunately.
Up vote so users do not lose time trying out.
Update:
It is however possible via http://opensharecount.com, they provide a drop-in replacement for the old private JSON URL based on searches made via the API (so you don't need to do all that work).
It's based on the REST API Search endpoints. Its still new system, so we should see how it goes. In the future we can expect more of similar systems, because there is huge demand.
this is for url with https (for Brodie)
https://cdn.api.twitter.com/1/urls/count.json?url=YOUR_URL
No.
How do I access the count API to find out how many Tweets my URL has had?
In this early stage of the Tweet Button the count API is private. This means you need to use either our javascript or iframe Tweet Button to be able to render the count. As our systems scale we will look to make the count API public for developers to use.
http://dev.twitter.com/pages/tweet_button_faq#custom-shortener-count
Yes,
https://share.yandex.ru/gpp.xml?url=http://www.web-technology-experts-notes.in
Replace "http://www.web-technology-experts-notes.in" with "your full web page URL".
Check the Sharing count of Facebook, Twitter, LinkedIn and Pinterest
http://www.web-technology-experts-notes.in/2015/04/share-count-and-share-url-of-facebook-twitter-linkedin-and-pininterest.html
Update:
As of 21st November 2015, Twitter has removed the "Tweet count endpoint" API.
Read More: https://twitter.com/twitterdev/status/667836799897591808
The approved reply is the right one. There are other versions of the same endpoint, used internally by Twitter.
For example, the official share button with count uses this one:
https://cdn.syndication.twitter.com/widgets/tweetbutton/count.json?url=[URL]
JSONP support is there adding &callback=func.
I know that is an old question but for me the url http://cdn.api.twitter.com/1/urls/count.json?url=http://stackoverflow.com did not work in ajax calls due to Cross-origin issues.
I solved using PHP CURL, I made a custom route and called it through ajax.
/* Other Code */
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLOPT_ENCODING => "", // handle compressed
CURLOPT_USERAGENT => "test", // name of client
CURLOPT_AUTOREFERER => true, // set referrer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // time-out on connect
CURLOPT_TIMEOUT => 120, // time-out on response
);
$url = $_POST["url"]; //whatever you need
if($url !== ""){
$curl = curl_init("http://urls.api.twitter.com/1/urls/count.json?url=".$url);
curl_setopt_array($curl, $options);
$result = curl_exec($curl);
curl_close($curl);
echo json_encode(json_decode($result)); //whatever response you need
}
It is important to use a POST because passsing url in GET request cause issues.
Hope it helped.
This comment https://stackoverflow.com/a/8641185/1118419 proposes to use Topsy API. I am not sure that API is correct:
Twitter response for www.e-conomic.dk:
http://urls.api.twitter.com/1/urls/count.json?url=http://www.e-conomic.dk
shows 10 count
Topsy response fro www.e-conomic.dk:
http://otter.topsy.com/stats.json?url=http://www.e-conomic.dk
18 count
This way you can get it with jquery. The div id="twitterCount" will be populated automatic when the page is loaded.
function getTwitterCount(url){
var tweets;
$.getJSON('http://urls.api.twitter.com/1/urls/count.json?url=' + url + '&callback=?', function(data){
tweets = data.count;
$('#twitterCount').html(tweets);
});
}
var urlBase='http://http://stackoverflow.com';
getTwitterCount(urlBase);
Cheers!
Yes, there is. As long as you do the following:
Issue a JSONP request to one of the urls:
http://cdn.api.twitter.com/1/urls/count.json?url=[URL_IN_REQUEST]&callback=[YOUR_CALLBACK]
http://urls.api.twitter.com/1/urls/count.json?url=[URL_IN_REQUEST]&callback=[YOUR_CALLBACK]
Make sure that the request you are making is from the same domain as the [URL_IN_REQUEST]. Otherwise, it will not work.
Example:
Making requests from example.com to request the count of example.com/page/1. Should work.
Making requests from another-example.com to request the count of example.com/page/1. Will NOT work.
I just read the contents into a json object via php, then parse it out..
<script>
<?php
$tweet_count_url = 'http://urls.api.twitter.com/1/urls/count.json?url='.$post_link;
$tweet_count_open = fopen($tweet_count_url,"r");
$tweet_count_read = fread($tweet_count_open,2048);
fclose($tweet_count_open);
?>
var obj = jQuery.parseJSON('<?=$tweet_count_read;?>');
jQuery("#tweet-count").html("("+obj.count+") ");
</script>
Simple enough, and it serves my purposes perfectly.
This Javascript class will let you fetch share information from Facebook, Twitter and LinkedIn.
Example of usage
<p>Facebook count: <span id="facebook_count"></span>.</p>
<p>Twitter count: <span id="twitter_count"></span>.</p>
<p>LinkedIn count: <span id="linkedin_count"></span>.</p>
<script type="text/javascript">
var smStats=new SocialMediaStats('https://google.com/'); // Replace with your desired URL
smStats.facebookCount('facebook_count'); // 'facebook_count' refers to the ID of the HTML tag where the result will be placed.
smStats.twitterCount('twitter_count');
smStats.linkedinCount('linkedin_count');
</script>
Download
https://404it.no/js/blog/SocialMediaStats.js
More examples and documentation
Javascript Class For Getting URL Shares On Facebook, Twitter And LinkedIn

What is server to server posting script?

I am integrating a 3rd party module into my site. I read their documention, but I stuck at this line:
"Your script should then do a server-to-server posting to our server. For example: https://www.domain.com:XXXX/gateway..."
What is it? I write a php page with a POST-form:
<form action"https://www.domain.com:XXXX/..." method="post">
...
<input type="submit">
Is it something like that?
Then do a response, let say they send back "result=ok", then I catch the result and do a check whether the result is okay or failed?
I interpret in this way, I dont know if I am doing the correct thing. CAn anyone advice? What is the server-to-server posting?
A server-to-server posting means that the program running on your server makes an HTTP POST to a gateway running on the vendor's server. The code fragment that you provided is HTML. You will need to have a code fragment in PHP (or some other language) to execute the POST. (If you did it in JavaScript, the post will come from your user's web browser, which is not what you want.)
You want to use the PHP HttpRequest class. Take a look at Example #2 in the PHP Manual, reprinted here:
<?php
$r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
$r->setOptions(array('cookies' => array('lang' => 'de')));
$r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
try {
echo $r->send()->getBody();
} catch (HttpException $ex) {
echo $ex;
}
?>

Resources