No description, website, or topics provided.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

Call Center

Support for defining call center workflows.

Build Status


Call Center streamlines the process of defining multi-party call workflows in your application. Particularly, with Twilio in mind.

Twilio provides a two-part API for managing phone calls, and is mostly driven by callbacks. Call Center DRYs up the application logic dealing with a callback driven API so you can focus on the business logic of your call center.


class Call
  include CallCenter

  call_flow :state, :intial => :incoming do
    actor :customer do |call, event|

    state :incoming do
      response do |x|
        x.Gather :numDigits => '1', :action => customer(:wants_voicemail) do
          x.Say "Hello World"
          x.Play some_nice_music, :loop => 100
        # <?xml version="1.0" encoding="UTF-8" ?>
        # <Response>
        #   <Gather numDigits="1" action="/voice/calls/flow?event=wants_voicemail&actor=customer&call_id=5000">
        #     <Say>Hello World</Say>
        #     <Play loop="100"></Play>
        #   </Gather>
        # </Response>

      event :called, :to => :routing, :if => :agents_available?
      event :called, :to => :voicemail
      event :wants_voicemail, :to => :voicemail
      event :customer_hangs_up, :to => :cancelled

    state :voicemail do
      response do |x|
        x.Say "Please leave a message"
        x.Record(:action => customer(:voicemail_complete))
        # <?xml version="1.0" encoding="UTF-8" ?>
        # <Response>
        #   <Say>Please leave a message</Say>
        #   <Record action="/voice/calls/flow?event=voicemail_complete&actor=customer&call_id=5000"/>
        # </Response>

      event :voicemail_complete, :to => :voicemail_completed
      event :customer_hangs_up, :to => :cancelled

    state :routing do


Benefits of CallCenter is that it's backed by state_machine. Which means you can interact with events the same you do in state_machine.

@call.render # See Rendering


The general application flow for a CallFlow is like this:

  1. An incoming call is posted to your application
    • You create a Call
    • You execute an initial event
    • You respond by rendering TwiML. Your TwiML contains callbacks to events or redirects
  2. Something happens and Twilio posts an event to your application
    • You find the Call
    • You store any new information
    • You execute the posted event
    • You respond by rendering TwiML. Your TwiML contains callbacks to events or redirects
  3. Repeat 2.

In order to DRY up the callbacks, it is best to have use standardized callback URLs. A handy concept is the flow_url, which follows the pattern:

By handling this in your controller, you can immediately retrieve the Call from persistence, run an event on the call, and return the rendered TwiML. Here's an example:

def flow
  render :xml =>[:event])

For an in-depth example, take a look at call_roulette.


Rendering is your way of interacting with Twilio. Thus, it provides two facilities: access to an XML builder and access to your call.

state :sales do
  response do |xml_builder, the_call|
    xml_builder.Say "This is #{}!" # Or, you can access he call implicitly

Renders with @call.render if the current state is :sales:

<?xml version="1.0" encoding="UTF-8"?>
  <Say>This is Henry!</Say>


You have control over what you want to happen before/after state transitions:

state :voicemail do
  before(:always) { # Invokes before any transition }
  before(:always, :uniq => true) { # Invokes before transitions to a different state }

  after(:always) { # Invokes after any transition }
  after(:success) { # Invokes after any successful transition }
  after(:failure) { # Invokes after any failed transition (those not covered in your call flow) }

  after(:always, :uniq => true) { # Invokes after any transition to a different state }
  after(:success, :uniq => true) { # Successful unique transitions }
  after(:failure, :uniq => true) { # Failed unique transitions }

For example,

state :voicemail do
  before(:always) { log_start_event }

  after(:always) { log_end_event }
  after(:failure) { notify_airbrake }

  after(:success, :uniq => true) { notify_browser }
  after(:failure, :uniq => true) { notify_cleanup_browser }



Twilio requests your application to return TwiML that describes the call workflow. TwiML contains commands which Twilio then executes. It is essentially an application-to-application API, synonymous to making a REST call.

In the context of "Skinny Controller, Fat Model", outgoing REST calls for the function of business logic are not a view concern but a model concern. Therefore, so is TwiML.

Twilio supports callbacks URLs and redirects to URLs that also render TwiML as a method of modifying live calls. Incoming callbacks are handled by the controller first, but the response is still a model concern.


  • Call - An application resource of yours that encapsulates a phone call. Phone calls are then acted on: answered, transferred, declined, etc.
  • Event - Is something that happens outside or inside your application in relation to a Call. Someone picks up, hangs up, presses a button, etc. But overall, it's anything that can be triggered by Twilio callbacks.
  • State - Is the status a Call is in which is descriptive of what's happened so far and what are the next things that should happen. (e.g. a call on hold is waiting for the agent to return)
  • CallFlow - Is a definition of the process a Call goes through. Events drive the flow between States. (e.g. a simple workflow is when noone answers the call, send the call to voicemail)
  • Render - Is the ability of the CallFlow to return TwiML to bring the call into the State or modify the live call through a Redirect.
  • Redirect - Is a way of modifying a live call outside of a TwiML response (e.g. background jobs)



Should you be interested in what your call center workflow looks like, you can draw.

Call.state_machines[:status].draw(:font => 'Helvetica Neue')
# OR
@call.draw_call_flow(:font => 'Helvetica Neue')


  • Integrate making new calls into the CallFlow DSL

Copyright and license

Copyright 2013 Zendesk

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.