classSupportTicket(models.Model):"""A support ticket submitted by an unsatisfied customer"""name=models.CharField(max_length=100)phone_number=PhoneNumberField()description=models.TextField()timestamp=models.DateTimeField(auto_now_add=True)

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

browser_calls/views.py

Submit a support ticket

browser_calls/views.py

Now we can create a ticket. Next up, let's work on the dashboard for the support agent.

When a support agent visits /support/dashboard, they see all the support tickets which have been submitted.

Each ticket also has a "Call Customer" button which invokes a JavaScript function we wrote named callCustomer(). That function kicks off a Twilio Client call to the phone number passed as its sole parameter.

That method requires an identifier for a TwiML Application. Twilio will send a POST request to our backend every time a user makes a Twilio Client call — the TwiML Application tells Twilio which URL to send that request to.

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

browser_calls/views.py

Generate a capability token

browser_calls/views.py

Once we are equipped with our Capability Token, the next step is to set up the Twilio Device Client in the browser.

We start by retrieving a capability token from the view we defined in the previous step with a POST request through AJAX. Then we enable the Twilio Device Client for this page by passing our token to Twilio.Device.setup().

After that the Twilio.Device.ready() callback will let us know when the browser is ready to make and receive calls.

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

browser_calls/static/js/browser-calls.js

Setting up a Twilio Device Client

browser_calls/static/js/browser-calls.js

Now that we have almost everything in place, it's time to see the core of this tutorial. Let's look at how we can let our agents start a call from their browsers.

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

browser_calls/static/js/browser-calls.js

Calling a Customer (browser-to-phone)

browser_calls/static/js/browser-calls.js

Great! Now our agents are able to make calls to their customers. Next up, let's look at how to connect that call to a phone number.

Whenever one of our users makes a call, Twilio will send a POST request to the URL we set on our TwiML Application - in this case, /support/call.

We use TwiML to respond to the request and tell Twilio how to handle the call. Twilio will pass along the phoneNumber parameter from the previous step in its request, which we will then Dial in our TwiML.

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

browser_calls/views.py

Connect the call to a phone number

browser_calls/views.py

After our call view responds, Twilio completes the connection between our support agent's browser and the customer's phone. Let's go back to the browser and look at how to notify the agent of a call in progress.

We use the Twilio.Device.connect() callback to update some UI elements to notify our users that they are in a call. This function receives a Connection object, which offers some additional details about the call.

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

browser_calls/static/js/browser-calls.js

Indicating a live call

browser_calls/static/js/browser-calls.js

And that's all for our browser-to-phone example. Next up, we will go even further and show a browser-to-browser example.

Support tickets are useful, but sometimes a customer needs help right now. With just a little more work we let customers speak with a support agent live via a browser-to-browser call.

When a customer clicks the Call support button on the home page we again use Twilio.Device.connect() to initiate the call. This time we don't pass any additional parameters — our backend will route this call to our support agent.

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

browser_calls/static/js/browser-calls.js

Call a support agent (browser-to-browser)

browser_calls/static/js/browser-calls.js

Setting up the browser-to-browser call was rather simple right? Now let's look at how our backend will route this call to our support agent.

To allow our support agents to accept incoming calls we use the allow_client_incoming() method when generating their capability token. We have to also pass support_agent as the client's name to this method.

When Twilio sends a POST request to our call view, we can connect the call to our support agent by responding with a <Client> TwiML noun and the support_agent name.

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

browser_calls/views.py

Connect the call to the support agent's client

browser_calls/views.py

That's how we prepare everything for accepting incoming calls. Now we should go back in the browser and see how to handle the connection this time.

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

browser_calls/static/js/browser-calls.js

Answering the call

browser_calls/static/js/browser-calls.js

Great! Now we know how to work on both cases: browser-to-phone and browser-to-browser calls! Next up, we will see what happens when they decide to hang up the call.

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

fromdjango.confimportsettingsfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.core.urlresolversimportreverse,reverse_lazyfromdjango.httpimportHttpResponse,JsonResponsefromdjango.shortcutsimportrenderfromdjango.views.decorators.csrfimportcsrf_exemptfromdjango.views.genericimportCreateViewfromtwilio.twiml.voice_responseimportDialfromtwilio.jwt.clientimportClientCapabilityTokenfrom.modelsimportSupportTicketclassSupportTicketCreate(SuccessMessageMixin,CreateView):"""Renders the home page and the support ticket form"""model=SupportTicketfields=['name','phone_number','description']template_name='index.html'success_url=reverse_lazy('home')success_message="Your ticket was submitted! An agent will call you soon."defsupport_dashboard(request):"""Shows the list of support tickets to a support agent"""context={}context['support_tickets']=SupportTicket.objects.order_by('-timestamp')returnrender(request,'browser_calls/support_dashboard.html',context)defget_token(request):"""Returns a Twilio Client token"""# Create a TwilioCapability token with our Twilio API credentialscapability=ClientCapabilityToken(settings.TWILIO_ACCOUNT_SID,settings.TWILIO_AUTH_TOKEN)# Allow our users to make outgoing calls with Twilio Clientcapability.allow_client_outgoing(settings.TWIML_APPLICATION_SID)# If the user is on the support dashboard page, we allow them to accept# incoming calls to "support_agent"# (in a real app we would also require the user to be authenticated)ifrequest.GET['forPage']==reverse('dashboard'):capability.allow_client_incoming('support_agent')else:# Otherwise we give them a name of "customer"capability.allow_client_incoming('customer')# Generate the capability tokentoken=capability.generate()returnJsonResponse({'token':token})@csrf_exemptdefcall(request):"""Returns TwiML instructions to Twilio's POST requests"""response=Dial(caller_id=settings.TWILIO_NUMBER)# If the browser sent a phoneNumber param, we know this request# is a support agent trying to call a customer's phoneif'phoneNumber'inrequest.POST:response.number(request.POST['phoneNumber'])else:# Otherwise we assume this request is a customer trying# to contact support from the home pageresponse.client('support_agent')returnHttpResponse(str(response))

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}

/** * Twilio Client configuration for the browser-calls-django * example application. */// Store some selectors for elements we'll reusevarcallStatus=$("#call-status");varanswerButton=$(".answer-button");varcallSupportButton=$(".call-support-button");varhangUpButton=$(".hangup-button");varcallCustomerButtons=$(".call-customer-button");/* Helper function to update the call status bar */functionupdateCallStatus(status){callStatus.text(status);}/* Get a Twilio Client token with an AJAX request */$(document).ready(function(){$.get("/support/token",{forPage:window.location.pathname},function(data){// Set up the Twilio Client Device with the tokenTwilio.Device.setup(data.token);});});/* Callback to let us know Twilio Client is ready */Twilio.Device.ready(function(device){updateCallStatus("Ready");});/* Report any errors to the call status display */Twilio.Device.error(function(error){updateCallStatus("ERROR: "+error.message);});/* Callback for when Twilio Client initiates a new connection */Twilio.Device.connect(function(connection){// Enable the hang up button and disable the call buttonshangUpButton.prop("disabled",false);callCustomerButtons.prop("disabled",true);callSupportButton.prop("disabled",true);answerButton.prop("disabled",true);// If phoneNumber is part of the connection, this is a call from a// support agent to a customer's phoneif("phoneNumber"inconnection.message){updateCallStatus("In call with "+connection.message.phoneNumber);}else{// This is a call from a website user to a support agentupdateCallStatus("In call with support");}});/* Callback for when a call ends */Twilio.Device.disconnect(function(connection){// Disable the hangup button and enable the call buttonshangUpButton.prop("disabled",true);callCustomerButtons.prop("disabled",false);callSupportButton.prop("disabled",false);updateCallStatus("Ready");});/* Callback for when Twilio Client receives a new incoming call */Twilio.Device.incoming(function(connection){updateCallStatus("Incoming support call");// Set a callback to be executed when the connection is acceptedconnection.accept(function(){updateCallStatus("In call with customer");});// Set a callback on the answer button and enable itanswerButton.click(function(){connection.accept();});answerButton.prop("disabled",false);});/* Call a customer from a support ticket */functioncallCustomer(phoneNumber){updateCallStatus("Calling "+phoneNumber+"...");varparams={"phoneNumber":phoneNumber};Twilio.Device.connect(params);}/* Call the support_agent from the home page */functioncallSupport(){updateCallStatus("Calling support...");// Our backend will assume that no params means a call to support_agentTwilio.Device.connect();}/* End a call */functionhangUp(){Twilio.Device.disconnectAll();}