FreshBooks API Blog
You may have noticed that we recently released the FreshBooks Time Tracker widget. What you may not have noticed beneath its shiny exterior, is this fantastic helper library called jQuery. Here are some excellent reasons for using it…
Portability
While the FreshBooks widget is currently only for OSX’s Dashboard, a lot of the HTML element access and glitzy fades are pure jQuery, and should be portable to other widget facilities, and the FreshBooks website itself. It’s also nice to be able to use the same skills in widget creation as webpage creation.
Power
The $() construct is much, much more powerful than it at first appears. Take a closer look at the full power of selectors to see what I mean. And the skills you learn are re-usable, since jQuery implements CSS3-style selectors. When browsers get around to fully supporting them, you’ll already be at home. In addition, jQuery also makes dealing with XML (as returned by the FreshBooks API) and Ajax in general a whole lot easier!
Conciseness
jQuery also leads to shorter, more concise JavaScript. $("#submit") is so much easier to type than document.getElementById("submit"), and infinitely more flexible when you want to, say, operate on all of the images in a page with $("img"). You “chain” together various jQuery commands, such as css() and show() simply by applying them to the returned “wrapped set”, like $("img").css('opacity',0.5).
Peer Pressure
Apparently I’m not the only one who thought this would be a good idea. I just recently noticed an awesome SVN notifier widget which also includes jQuery. Perhaps the idea is catching on…
Howdy folks - a couple of small API changes to announce:
- invoice.get and invoice.list now return <recurring_id/>
- project.list can now be filtered by <task_id/>
- time_entry.create rounds hour values to hundredths of an hour (just like the web interface)
- Raised maximum request limit to 5000 requests/day
- A handful of other bug fixes and tweaks
As always, if you have questions or comments, please let us know on the developer forums.
The other day I was investigating an odd error using our development version of FreshBooks in Safari. Lines in an invoice were being reset in an odd way, and I couldn’t add more lines to an invoice as I was creating it. This worked perfectly in FireFox, but not in Safari.
Of course, the first step was to look at the page source. However, the page source looked entirely correct. All of the form elements were defined in the correct places, with the expected order. This is where fantastic tools like Web Inspector (found in the Safari Debug menu) and Firebug come in handy. On reproducing the bug, I managed to SEE the offending tag in its new location in the Web Inspector view. A whole set of input tags sitting at the start of a table!
It turns out that if you replace a table inside a div tag, Safari does some reparsing of your provided HTML. Say, you put a hidden input tag within a tr, but outside of a td. Normally this works fine, and document.forms[0].elements[] shows up in the way you’d expect. But when replacing the table via something like innerHTML, it barfs because the ONLY things allowed in a tr tag are th or td. Thus speaks the XHTML 1.0 transitional DTD:
<!ELEMENT tr (th|td)+>
What appears to happen, is that any input elements outside of a td get bubbled up the DOM until they find a place where they are allowed…in this case, immediately before the enclosing table.
Hence, you get strange results with:
myDiv.innerHTML = "<table border='1'><tbody>" +
"<tr><td><input type='text' value='First'></td>" +
" <input type='text' value='Second'></tr>" +
"</tbody></table>";

But not with:
myDiv.innerHTML = "<table border='1'><tbody>" +
"<tr><td><input type='text' value='First'>" +
" <input type='text' value='Second'></td></tr>" +
"</tbody></table>";

Hence, when adding form elements improperly, programmatically, and referencing them with document.forms[].elements[], you get Very Strange results.
So please, for your own sanity’s sake, nest your elements properly!
As you may know, I started at FreshBooks at the start of this year. You’ll see me posting random programming-related things as I hit them in my move from systems C programming into the world of PHP and web programming.
Yesterday I was merrily coding away, creating Cool New Features for you, our FreshBooks users. After adding 4 innocent lines of code, I started to see raw JavaScript instead of the beautifully formatted FreshBooks interface we all love. This led me through the following hoops:
- There’s no trailing <script> tag in the page source. So that’s why I saw raw JavaScript.
- Apache’s error.log showed dying processes!
- Reconfiguring Apache to use only one child thread, I attached gdb and recreated it…and caught PHP dying of a segmentation fault!
- At this point I think I’ve found a bug in PHP (since progams should never ever segfault).
- Then I discovered I made the classic error of pasting-without-looking, and inadvertently created an infinite recursion!, and found a bug report that indicates that this is “working as designed” in PHP. *cough*
To wit, I proceeded to see how other scripting languages handle infinite recursion. Here are the results…
PHP
$ php -r “function f(){f();}f();”
Segmentation fault
Dies an untimely death, because each function invocation recursively calls execute():
In my opinion, a well-behaved program should NEVER segfault, because a segmentation is only rarely the first bad thing that’s happened (it’s just the most fatal one to the process in question). But let’s see if anyone else does better…
Perl
$ perl -e “sub f{&f;}&f;”
Killed
Runs the system out of memory (all 256MB RAM + 400MB swap in my Linux VMWare image).
While this is horrible from a denial-of-service perspective, it’s easy to prevent by setting ulimit on the server processes. And it shows that Perl isn’t artificially limiting recursion depth; if you’ve got the RAM, you can go to infinity (almost).
Python
$ python -c “def f(): f()
f()”
Traceback (most recent call last):
File “<string>”, line 2, in <module>
File “<string>”, line 1, in f
…
RuntimeError: maximum recursion depth exceeded
YAY! A useful result. Of course it indicates that you may have problems recursing deeply. See below for alternatives…
Ruby
$ ruby -e “def f
f()
end
f()”
-e:2:in `f’: stack level too deep (SystemStackError)
from -e:2:in `f’
from -e:4
Also an excellent, useful error message!
Tail Recursion
Of course, if you wanted to loop infinitely, you’d be much better off using a language that supports tail call optimization. Something like Scheme, Lua, Erlang, etc. Even better, you can write your own language that supports tail call optimization (take a look at the last chapter of Structure and Interpretation of Computer Programs, and section 5.1.4 in particular). However, since choosing (or writing) a different language is not always feasible, people are always coming up with creative solutions in languages that don’t support TCO!
For those with a practical bent
Not willing to give this up just yet, here’s a set of less artificial examples:
<?
//php
function f($x) {
if ($x == 1) return 1;
return ($x + f($x-1));
}
echo f(1) . "\n";
echo f(10) . "\n";
echo f(100) . "\n";
echo f(1000) . "\n";
echo f(10000) . "\n";
echo f(100000) . "\n"; // Segmentation fault
?>
#perl
sub f {
my $x = shift;
if ($x == 1) {return 1;}
return ($x + f($x-1));
}
print(f(1) . "\n");
print(f(10) . "\n");
print(f(100) . "\n");
print(f(1000) . "\n");
print(f(10000) . "\n");
print(f(100000) . "\n");
print(f(1000000) . "\n");
print(f(10000000) . "\n"); # malloc: *** mmap(size=351752192) failed
#python
def f(x):
if x == 1: return 1
return x + f(x-1)
f(1)
f(10)
f(100)
f(1000) # maximum recursion depth exceeded
#ruby
def f(x)
x == 1 ? x : x + f(x-1)
end
puts f(1)
puts f(10)
puts f(100)
puts f(1000)
puts f(10000) # stack level too deep
By
Ben - January 10/2008 ()
Afternoon gang! We’ve got a couple new API feature announcements to kick off 2008 - just 3 weeks after our last release.
Paging Metadata
Now when you submit an API request that returns more than one object (i.e. all *.list methods), you’ll also be returned paging metadata that describes the result set. This should help you better navigate large data sets returned by the API.
Here’s a sample new response from invoice.list:
<?xml version="1.0" encoding="utf-8"?>
<response status="ok">
<invoices page="2" per_page="5" pages="8" total="37">
<invoice>...</invoice>
<invoice>...</invoice>
<invoice>...</invoice>
<invoice>...</invoice>
<invoice>...</invoice>
</invoices>
</response>
Now, we think this is a swell improvement, and our users have been pining for it. But it comes at a small cost – the introduction of these new top-level paging nodes could break existing integration code. This issue leads into our next announcement:
API Version Numbers
Now when you submit your API requests, you can optionally specify a version number as part of the request URL.
Old URL:
http://mycompany.freshbooks.com/api/xml-in
New URL:
http://mycompany.freshbooks.com/api/2.1/xml-in
To take advantage of these new response formats, you must specify version 2.1 as part of the request URL. If you do not specify a version number, the API will return the old, less-descriptive response format (version 2.0).
Deprecation Warning!
We will support both versions (2.1 and 2.0) until March 1st, 2008. This will give you nearly 8 weeks to migrate your applications to the new schema.
If you have questions, comments or concerns, please contact us.
By
Ben - December 20/2007 ()
Hey everyone – long time no see!
After almost three months of silence on this blog, I’m proud to announce that Timesheets (including Projects and Tasks) and Estimates have been added to the FreshBooks API, along with a slew of other features and minor tweaks. Below is a quick summary of the big ones:
Timesheets
Timesheets exposes three new data types – projects, tasks and time entries. Between the three of these, you’ll be able to create new time entries remotely, query for all time entries between a given date, filter down by project or task, and more.
Estimates
Finally, you can interact with estimates just like their older big brother (read: invoices). You can perform basic CRUD operations, poll for estimate URLs, and send them off via e-mail.
Editable invoice and estimate numbers
As of version 4.2, invoice and estimate numbers are now editable. The API is no exception – the <number> parameter will now hold the invoice/estimate number, as opposed to to <invoice/estimate_id>.
Start and stop recurring profiles
You can now start/stop recurring profiles via the API using the <stopped> parameter. Deleting would have the same effect, but you couldn’t get the profile back - now you’re golden.
By
Ben - August 29/2007 ()
Version 4.0 of FreshBooks is here, and along with it comes a number of changes/additions to the FreshBooks API.
Recurring Profiles
It’s been a long time coming – you can finally create and manage recurring profiles via the API.
Bigger Search Results
You can now pull up to 100 records from an individual list request, using a per_page value of 100. If left unsupplied, per_page will default to 25.
New Filters
You can now retrieve any invoices generated from a recurring profile using the invoice.list method.
Furthermore, invoice.list will now let you filter search results by status – i.e. ‘draft’, ‘paid’ and so on.
Misc Bug Fixes
If you create a new client via the API, and supply that client’s username and password, they won’t be prompted again for their account details after they’ve logged in. This should help FreshBooks users who are trying to synchronize client account data.

Interested in viewing your invoices and collected revenue in a nice looking graph? Now you can with our new graph generator.
A few months ago, we released our redesigned API which gave you the ability to access and update your FreshBooks information for your custom solutions.
At that time, I release a nice little tool to import your items to your FreshBooks account from comma delimited text. This month, I made this easy to use graph generator with the help of the LastXgraph PHP library and the FreshBooks API.

All you have to do is enable your API for your system and enter your API credentials. Next, click the large submit button and, presto!, a nice graphical representation of your invoices and collected revenue.
The source code is written in PHP is available in the sample code section of our developers section.
Symfony users rejoice: there’s now an easy-to-use plugin for integrating your Symfony applications with the FreshBooks API. In case you’re not familiar, Symfony is a web development framework for PHP:
… symfony aims to speed up the creation and maintenance of web applications, and to replace the repetitive coding tasks by power, control and pleasure.
Much appreciation to the author, Ian Ricketson, for sharing his work. In case you missed it, users have also contributed Ruby and Perl libraries.
If you’re a Ruby or Rails developer looking to get started with the FreshBooks API, I recommend taking a look at the latest sample code we’ve put together: invoice_getter.rb.
It uses FreshBooks.rb, a Ruby wrapper I’ve written, to fetch a particular invoice’s details and render it as HTML. A call to invoice.list populates a select box letting you choose from your last 25 invoices. It might be a useful starting point for businesses that want to customize and style their invoice formats.
For fun, I’ve coded invoice_getter.rb using Rack, the modular web server interface, so it can be either launched traditionally using Apache/CGI, or using Ruby’s WEBrick server. As a Rails enthusiast, I love working with WEBrick – you can quickly launch and re-start your app from the command-line, skipping the messiness of an Apache conf file.
If you’ve already got Ruby and RubyGems installed, you can quickly install Rack and launch invoice_getter.rb like so:
# gem install rack -–include-dependencies
...
Successfully installed rack-0.2.0
Installing ri documentation for rack-0.2.0…
Installing RDoc documentation for rack-0.2.0
# ruby invoice_getter.rb
[2007-07-09 10:50:34] INFO WEBrick 1.3.1
[2007-07-09 10:50:34] INFO ruby 1.8.6 (2007-03-13) [i386-mswin32]
[2007-07-09 10:50:34] INFO WEBrick::HTTPServer#start: pid =3944, port=3000
Now, fire up your web browser to http://localhost:3000 and you’re good to go.
In case you missed the link above, you can download the sample code here.