Tropo is part of CiscoLearn More

Auto-Returning Phone Calls with Tropo

Posted on March 5, 2012 by Team Tropo

Using Tropo’s Scripting API and Ruby, I wrote a clever little script that allows you to automatically return missed calls from people as soon as you hang up a phone call.

Here is the use case:

  • User A calls user B
  • While users A and B talking, user C calls user B
  • Tropo script records the missed user C call and returns their call after B hangs up. The Tropo script automatically calls users B and C and bridges them in a conference call.

Here is a video to help demonstrate the concept:

Here is the Ruby script using Iris Couch as a JSON datastore directly from the Tropo cloud!

require 'rubygems'
require 'net/http'
require 'json'

# Setup couchdb JSON datastore calls
module Couch

class Server
def initialize(host, port, options = nil)
@host = host
@port = port
@options = options

def delete(uri)

def get(uri)

def put(uri, json)
req =
req["content-type"] = "application/json"
req.body = json

def post(uri, json)
req =
req["content-type"] = "application/json"
req.body = json

def request(req)
res = Net::HTTP.start(@host, @port) { |http|http.request(req) }
unless res.kind_of?(Net::HTTPSuccess)
handle_error(req, res)


def handle_error(req, res)
e ="#{res.code}:#{res.message}nMETHOD:#{req.method}nURI:#{req.path}n#{res.body}")
raise e

# define couchdb server name
server ="", "80")

# get callerid
callerid = $currentCall.callerID
if callerid.length == 10
callerid = "1" + callerid

say "welcome to tropo's call back demo"

ask "Please enter the country code and phone number of the person you are trying to reach followed by the pound sign.", {
:choices => "[8-15 DIGITS]",
:terminator => '#',
:timeout => 15.0,
:mode => "dtmf",
:interdigitTimeout => 5 ,
:onChoice => lambda { |event|

target = event.value

# check to see if record exists indicating that the called party is on another call
res = server.get("/callerback/" + target) rescue nil
jsonresp = res.body rescue nil

# phone number record will exist if called party is on the phone
if jsonresp

# if on the phone, write number to return call when available
postcallback = server.put("/callerback/" + target + "q", '{"phone":' + callerid + '}') rescue nil
say target + " is on the phone now but will return your call shortly."


# transfer call
say "Please wait while we transfer your call. Press star to cancel the transfer."

# write record to show that the dialed party is unavailable
postoncall = server.put("/callerback/" + target, "{}") rescue nil

# transfer call
transfer target, {
:playvalue => "",
:terminator => "*",
:onTimeout => lambda { |event|
# no answer
say "Sorry, but nobody answered at " + target.to_s + " please try again later."

# Transfer blocks. The code below will not be executed until the transferred call completed.

# find and delete current called party record
getcurrentrec = server.get("/callerback/" + target) rescue nil
jsongetcurrentrec = getcurrentrec.body rescue nil
currentdata = JSON.parse(jsongetcurrentrec)
deletecurrent = server.delete("/callerback/" + target + "?rev=" + currentdata["_rev"].to_s )

# check to see if a number exists to callback and delete it
getcallback = server.get("/callerback/" + target + "q") rescue nil
jsoncallback = getcallback.body rescue nil

# If someone called while we were on the phone, let's call them back!
if jsoncallback

# find and delete their callback number
callbackdata = JSON.parse(jsoncallback)
callerid = callbackdata["phone"]
deletecallback = server.delete("/callerback/" + target + "q?rev=" + callbackdata["_rev"].to_s )

# Call the 2 numbers and bridge the new call using conference

# create unique conference room based on timestamp
timeVar =
conferenceID = timeVar.strftime("%Y%H%M%S")

# set conference options

threads = []

# Call First Leg (User)
call 'tel:+' + target, {
:callerID => callerid.to_s,
:onAnswer => lambda{|event|
log "@"*5 + "User has answered"

#Create second thread for second leg (Operator)
threads << do
log "@"*5 + "Start second thread"
call 'tel:+' + callerid.to_s, {
log "@"*5+"Operator answered join conference"
newCall2 = confevent.value
#announce caller
newCall2.say("You have a call from " + target.to_s)
#join operator to conference
end #thread

newCall = event.value
newCall.say("Please hold while we connect you to " + callerid.to_s)


threads.each { |t| t.join }

end #jsoncallback

end #jsonresp

:onBadChoice => lambda { |event|
say "We did not recognize that phone number"

Leave a Reply