Checking Future-nine rates in your dialplan

Catalog of dial plans
Post Reply
MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Checking Future-nine rates in your dialplan

Post by MikeTelis » Tue Nov 10, 2009 11:41 am

I've always wanted to make my dialplan check on calling rates and notify me if there's any change. My default (and primary) VoIP provider is Future-nine and like many others, they do not notify customers by e-mail of coming or committed changes to their rate plan.

F9's website has a page where you can type in a phone number and check their rates for the number, for example:

http://www.future-nine.com/A2BCustomer_ ... 2125551212

My first intention was to get that page with sys.WebGet and retrieve the rate from there, but that was before I discovered that sys.WebGet truncates the result to 1024 bytes which is not enough to reach to the rate. Then I decided to use YQL (Yahoo Query Language) to convert the output into JSON (more compact) and get rid of everything but the destination name and the rate using XPath. Copy the following link and paste it into browser to try corresponding query in YQL console:

http://developer.yahoo.com/yql/console/ ... D'%2F%2Fem'

(Unfortunately, phpBB doesn't accept long URLs)

Select "JSON" and click on "Test"... you'll see the destination ("us and canada") and rate ("$0.01") in console output window. The whole JSON string is less than 650 bytes, so it fits into 1024-byte limitation imposed by sys.WebGet.

Now it was the time to do some coding. Suppose we have dial string in dials, like this:

dials = '0312125551212@F9'

where 03 is Future-nine's dialprefix specifying 'white' rate (00 and 02 - grey rate and 04 - premium rate), 12125551212 - the number you wish to dial and finally, @F9 specifies SIP provider's name. Here is the code:

Code: Select all

F9_key = 'insert key value here'

  if dials =~ /^(00|02|03|04)(.*)@F9/
    sys.ExtendScriptTimeout(10)
    plan = { '00' => 'grey', '02' => 'grey', '03' => 'white', '04' => 'premium' }[$1]; num = $2
    url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D'http%3A%2F%2Fwww.future-nine.com%2FA2BCustomer_UI%2Frates.php%3Fwhichrate%3D#{plan}%26called%3D#{num}%26key%3D#{F9_key}'%20and%20xpath%3D'%2F%2Fem'&format=json"
    js = sys.WebGet(url,6).to_s
    if js =~ /"em":\["(.*)","(.*)"\]/
      sys.Log("Future-nine '#{plan}' rate for #$1 is #$2")
      sys.Respond(100,"Rate is #$2")
    end
  end

  sys.Dial(dials)
sys.ExtendScriptTimeout is needed because sys.WebGet takes 1-2 seconds to execute and sometimes you may run into a problem with "long running dialplan terminated". URI and JSON modules are not available in SS version of Ruby, that's why I had to encode the URL manually (actually, copied it from YQL console and inserted 'plan' and 'num' where necessary) and primitively parse JSON output with regular expression. Try running the above code in your dialplan and you'll see destination name and rate in Console log. The rate will also appear in your softphone (if it can process call progress messages; I'm running SJPhone and it can do it).

Seeing call rates on the screen is good enough for most uses, but I decided to make one step further and have my dialplan report of changing rates by e-mail. Basic idea was to save current rate in a database key named like:

F9_Rate_USANDCANADA

and send e-mail to myself whenever current rate is different from the one in
database. Resulting code:

Code: Select all

F9_key = 'insert key value here'

  if dials =~ /^(00|02|03|04)(.*)@F9/
    sys.ExtendScriptTimeout(10)
    plan = { '00' => 'grey', '02' => 'grey', '03' => 'white', '04' => 'premium' }[$1]; num = $2
    url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D'http%3A%2F%2Fwww.future-nine.com%2FA2BCustomer_UI%2Frates.php%3Fwhichrate%3D#{plan}%26called%3D#{num}%26key%3D#{F9_key}'%20and%20xpath%3D'%2F%2Fem'&format=json"
    js = sys.WebGet(url,6).to_s
    if js =~ /"em":\["(.*)","(.*)"\]/
      dest = $1; rate = $2    # save for the future
      sys.Log("Future-nine '#{plan}' rate for #$1 is #$2")
      sys.Respond(100,"Rate is #$2")
      key = 'F9_Rate_' + dest.upcase.gsub(/[^A-Z0-9]/,'')
      if (oldrate = sys.DBRead(key).to_s).empty?
        sys.DBWrite(key,rate)
        sys.Email('myemail@addr.com',"F9 '#{plan}' rate for #{dest} is #{rate}","Called number: #{num}")
      else
        if oldrate != rate
          sys.Email('myemail@addr.com',"F9 '#{plan}' rate for #{dest} changed #{oldrate} => #{rate}", 'As %subj')
          sys.DBWrite(key,rate)
        end
      end
    end
  end

  sys.Dial(dials)
The only problem I can foresee is that after a while you'll get quite a number of database records with keys "F9_Rate_xxxx" and, should you decide to delete them, it will be a pain. I hope that Aaron will notice this thread and add some tools for the job, like sys.DBDelete(/Pattern/) or even (wishful thinking!) a page where we could see, edit and delete database records for our accounts.
Last edited by MikeTelis on Mon Mar 29, 2010 9:54 am, edited 2 times in total.

trav
Posts: 120
Joined: Tue Sep 08, 2009 8:34 pm

Post by trav » Tue Feb 02, 2010 6:12 am

hey mike, thanks for this topic--have u noticed how some voip providers ie. callcentric/callwithus may have cheaper rates than f9? i was using like all 3 in the mix (and manually adjusting as needed), but are you still using your fare comparer? it might be too much work to save .001 cents...:)

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Post by MikeTelis » Tue Feb 02, 2010 8:23 am

I spent some time creating this code, it works... why should I stop using it? :)

trav
Posts: 120
Joined: Tue Sep 08, 2009 8:34 pm

Post by trav » Thu Feb 11, 2010 8:49 pm

MikeTelis wrote:I spent some time creating this code, it works... why should I stop using it? :)
i was seeing if you were still interested in comparing fares. overall, i think f9 has best costs with CWU in close second, but i was gonna start managing maybe 3-4 people's ata's and wanted to do it under one roof, which CWU helps with. for f9, they told me i had to set up separate accounts for each person :(

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Post by MikeTelis » Fri Feb 12, 2010 3:21 am

I guess you're asking if I was going to develop similar code for other providers; in particular, for CallWithUs. No, it's not on my todo list; you'll have to do it yourself. I can give you a couple of tips, though :)

CallWithUs provides with API, you can use it to get the rates. The problem is that the API requires POST method not directly available in YQL. Thanks to Chris Heilmann, there is a solution. His open table htmlpost is available, check YQL Console / Community tables / Data.

trav
Posts: 120
Joined: Tue Sep 08, 2009 8:34 pm

Post by trav » Fri Feb 12, 2010 9:09 am

haha..no, i think i have enough on my plate to learn about managing multi accounts before trying to tackle cost comparisons. i don't have heavy usage (yet), so i'll worry about the differences when they start adding up. but it is kinda interesting to think about while i'm learning more about voip.

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Re: Checking Future-nine rates in your dialplan

Post by MikeTelis » Sat Mar 27, 2010 8:06 pm

Future-nine disabled rate-checking by scripts, because (I quote) "Multiple users basically ran scripts to load up the entire world during the middle of the day resulting in a server crash". I'm trying to persuade them to allow reasonable usage of this interface (say, 50 queries per user per day) and I hope they will listen to my arguments. Anyway, rate-checking is inoperative at the moment.

beaver
Posts: 241
Joined: Tue Feb 09, 2010 5:32 am
Location: Beaverton USA (PST, GMT - 8)

Re: Checking Future-nine rates in your dialplan

Post by beaver » Sat Mar 27, 2010 9:53 pm

F9 nitzan is quite negative on Sipsorcery. Possibly this is just an excuse to block your access from Sipsorcery.

http://www.dslreports.com/forum/r23947681-

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Re: Checking Future-nine rates in your dialplan

Post by MikeTelis » Sun Mar 28, 2010 8:45 am

beaver wrote:F9 nitzan is quite negative on Sipsorcery. Possibly this is just an excuse to block your access from Sipsorcery.
It's a pity because F9 is my "VSP of choice" for many destinations. Anyway, I don't think it has something to do with nitzan's position towards Sipsorcery, because:

1. I observed the same behavior when trying run the script on my own laptop. That is, it's not "blocking by IP address" or alike.
2. I doubt someone was using my code to render "whole world rates", there are more appropriate tools for that. I'm definitely making less than 50 calls per day via F9 and it couldn't possibly cause any concern on their side.

I haven't heard back from F9 techies yet and I don't know whether my suggestion's accepted or not. Will keep you posted; in the meantime, I suggest that you comment out this chunk of code (it doesn't work, anyway).

MikeTelis
Posts: 1582
Joined: Wed Jul 30, 2008 6:48 am

Re: Checking Future-nine rates in your dialplan

Post by MikeTelis » Mon Mar 29, 2010 9:51 am

Update: F9 accepted and already implemented my proposal (YES!!!). Everybody who wants to use a script retrieving the rates must contact F9 technical support and ask for API key. API key must be inserted into HTTP request in form:

&key=value

New URL:

Code: Select all

    url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D'http%3A%2F%2Fwww.future-nine.com%2FA2BCustomer_UI%2Frates.php%3Fwhichrate%3D#{plan}%26called%3D#{num}%26key%3D#{F9_key}'%20and%20xpath%3D'%2F%2Fem'&format=json"
and you must define API key in the "header" of your Ruby dialplan, like this:

F9_key = 'insert key value here'

Yet I noticed an increase in request processing time, it takes a bit less than 5 sec to get a responce. That's why I changed sys.WebGet time-out from 4 to 6 seconds:

Code: Select all

    js = sys.WebGet(url,6).to_s
Just in case, I changed the code in the beginning of this topic, so it should be okay to paste and copy it. Don't forget to insert API key, though! :)

So, what they need the key for? The number of rate requests is limited (no more than N requests per day per key). I'm not sure of exact value of N (was asking about 50 requests per day) but I think this number is big enough for most users.

Post Reply