Neil Bowers


WebService::BambooHR - interface to the API for


 use WebService::BambooHR;

 my $bamboo = WebService::BambooHR->new(
                  company => 'foobar',
                  api_key => '...'

 $id        = $bamboo->add_employee({
                  firstName => 'Bilbo',
                  lastName  => 'Baggins',

 $employee  = $bamboo->employee($id);

 $bamboo->update_employee($employee->id, {
     dateOfBirth => '1953-11-22',
     gender      => 'Male',


NOTE: this is very much an alpha release. The interface is likely to change from release to release. Suggestions for improving the interface are welcome.

WebService::BambooHR provides an interface to a subset of the functionality in the API for BambooHR (a commercial online HR system: lets a company manage employee information, handle time off, etc).

To talk to BambooHR you must first create an instance of this module:

 my $bamboo = WebService::BambooHR->new(
                  company => 'mycompany',
                  api_key => $api_key,

The company field is the domain name that you use to access BambooHR. For example, the above company would be accessed via You also need an API key. See the section below on how to create one.

Having created an instance, you can use the public methods that are described below. For example, to display a list of all employees:

 @employees = $bamboo->employee_list();
 foreach my $employee (@employees) {
     printf "Hi %s %s\n", $employee->firstName,

Note that the print statement could more succinctly have been written as:

 print "Hi $employee\n";

The employee class overloads string-context rendering to display the employee's name.

Generating an API key

To get an API key you need to be an admin user of BambooHR. Ask the owner of your BambooHR account to make you an admin user. Once you are, login to Bamboo and generate an API key: Look for the entry "API Keys" in the drop-menu under your name.



Returns a list of all employees in BambooHR for your company:

 @employees = $bamboo->employee_list();

Each employee is an instance of WebService::BambooHR::Employee. See the documentation for that module to see what information is available for each employee. You can find out more information from the BambooHR documentation.

This will return both active and inactive employees: check the status field if you only want to handle active employees:

 foreach my $employee ($bamboo->employee_list) {
    next if $employee->status eq 'Inactive';

If you're only interested in specific employee fields, you can just ask for those:

 @fields    = qw(firstName lastName workEmail);
 @employees = $bamboo->employee_list(@fields);

All other fields will then return undef, regardless of whether they're set in BambooHR.


Used to request a single employee using the employee's internal id, optionally specifying what fields should be populated from BambooHR:

 $employee = $bamboo->employee($id);

This returns an instance of WebService::BambooHR::Employee. If no fields are specified in the request, then all fields will be available via attributes on the employee object.

As for employee_list() above, you can specify just the fields you're interested in:

 @fields   = qw(firstName lastName workEmail);
 $employee = $bamboo->employee($id, @fields);


Add a new employee to your company, specifying initial values for as many employee fields as you want to specify. You must provide firstName and lastName:

 $id = $bamboo->add_employee({
           firstName => 'Bilbo',
           lastName  => 'Baggins',
           jobTitle  => 'Thief',

This returns the internal id of the employee.


This is used to update one or more fields for an employee:

 $bamboo->update_employee($employee_id, {
     workEmail => '',
     bestEmail => 'bilbo@bag.end',


Request a specific company report, which you need to have defined via the BambooHR web interface.

 $report_data = $bamboo->company_report($report_id);

The $report_id is an integer, the internal id for the report definition. You can find out the id by looking at the report in the web interface and checking the URL, which will end in:


This method returns the data as returned by Bamboo, rather than massaging it in any way. You get back a hashref with two keys in it:

  • fields - an array of hashrefs, each of which gives the definition of one entry in report. Each hashref has 3 keys: name is the title of the field (what appears in the header when you look at the report in Bamboo); id is the internal id string, which appears in the employees hash described below; type is a string that gives the type of the Bamboo field.

  • employees - the data of the report. An array of hashrefs, one per employee. The keys in each hashref are the id fields from the fields hashref.

To illustrate this, here's how you'd show each employee in turn, using the name of the field rather than the id:

 my $report_data  = $bamboo->company_report($report_id);
 my $fieldsref    = $report_data->{fields};
 my $employeesref = $report_data->{employees};
 my %fieldmap     = map { ($_->{id}, $_->{name} } @$fieldsref;

 foreach my $employee (@$employeesref) {
   print "\nNext employee:\n";
   foreach my $id (keys %$employee) {
     printf "  %s: %s\n", $fieldmap{$id}, $employee->{$id} // '';


Request an employee's photo, if one has been provided:

 $photo = $bamboo->employee_photo($employee_id);

This returns a JPEG image of size 150x150, or undef if the employee doesn't have a photo.


Returns a list of objects that identifies employees whose BambooHR accounts have been changed since a particular date and time. You must pass a date/time string in ISO 8601 format:

 @changes = $bamboo->changed_employees('2014-01-20T00:00:01Z');

The list contains instances of class WebService::BambooHR::EmployeeChange, which has three methods:

  • id

    The internal id for the employee, which you would pass to the employee() method, for example.

  • action

    A string that identifies the most recent change to the employee. It will be one of 'Inserted', 'Updated', or 'Deleted'.

  • lastChanged

    A date and time string in ISO 8601 format that gives the time of the last change.

In place of the 'action' method, you could use one of the three convenience methods (inserted, updated, and deleted), which are named after the legal values for action:

 print "employee was deleted\n" if $change->deleted;

The list of changes is return sorted from oldest to most recent.

Employee objects

A number of methods return one or more employee objects. These are instances of WebService::BambooHR::Employee. You can find out what fields are supported from the BambooHR documentation. The methods are all named after the fields, exactly as they're given in the doc. So for example:

 print "first name = ", $employee->firstName, "\n";
 print "work email = ", $employee->workEmail, "\n";

If you use an object in a string context, you'll get the person's full name. So the following lines produce identical output:

 print "name = $employee\n";
 print "name = ", $employee->firstName, " ", $employee->lastName, "\n";


This module throws exceptions on failure. If you don't catch these, it will effectively die with an error message that identifies the method being called, the line in your code, and the error that occurred.

You can catch the exceptions using the eval built-in, but you might also choose to use Try::Tiny. For example, you must have permission to get a list of employees:

 try {
     $employee = $bamboo->employee($id);
 } catch {
     if ($_->code == 403) {
         print "You don't have permission to get that employee\n";
     } else {

The exceptions are instances of WebService::BambooHR::Exception. Look at the documentation for that module to see what information is available with each exception.


The full BambooHR API is not yet supported. I'll gradually fill it in as I need it, or the whim takes me. Pull requests are welcome: see the github repo below.


BambooHR API documentation



Neil Bowers <>


This software is copyright (c) 2014 by Neil Bowers <>.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.