---
title: "Extracting Employee Data with the BambooHR API: Practical Examples"
description: "This article explains one possible way of using the BambooHR API to retrieve employee data using Python. Having done that, you'll be able to use your existing knowledge to route the data to a different system with which you're integrating BambooHR."
author: "Jura Gorohovsky"
published: "2024-07-30T16:00+02:00"
updated: "2025-07-23T21:03:31.138Z"
url: "https://www.apideck.com/blog/extracting-employee-data-with-the-bamboohr-api-practical-examples"
category: "HRIS"
tags: ["HRIS", "Unified API", "Guides & Tutorials"]
---

# Extracting Employee Data with the BambooHR API: Practical Examples

Human Resource Information System (HRIS) platforms are software services that integrate HR functions and streamline HR activities. These activities may include employee data management, recruitment, onboarding and offboarding, performance management, leave and vacation tracking, processing employee feedback, analytics, and reporting. HRIS platforms also often include self-service portals for employees to access important information and track attendance.

[BambooHR](https://www.bamboohr.com/) is a popular cloud-based HRIS platform that's pretty powerful by itself, but it also serves as a common target with which other services can integrate. To enable this, BambooHR provides [125-plus prebuilt integrations](https://www.bamboohr.com/integrations/) on its Marketplace. If there's no existing integration for a given service, BambooHR also provides a [REST API](https://documentation.bamboohr.com/docs/getting-started) to access and update employee data programmatically.

This article explains one possible way of using the BambooHR API to retrieve employee data using Python. Having done that, you'll be able to use your existing knowledge to route the data to a different system with which you're integrating BambooHR.

## What is the BambooHR API

The [BambooHR API](https://documentation.bamboohr.com/docs/getting-started) is a RESTful API for integrating other applications into BambooHR. It focuses on synchronizing employee data and generating employee reports. The API provides [a variety of endpoints](https://documentation.bamboohr.com/reference/) that can retrieve and update employee records and files, company-wide data, benefits, job descriptions and applications, employee training types, and records.

You can access the API using a specific API key if you're developing an integration on behalf of a single customer or use [OpenID Connect](https://documentation.bamboohr.com/page/authenticate-integration) for authorization if you're serving multiple BambooHR customers.

BambooHR API is particularly useful when your company is a power user of BambooHR, allowing you to automate workflows and customize the platform to perfectly meet your specific needs, such as payroll or [employee onboarding](https://developers.apideck.com/guides/onboard-and-offboard-employees-hris-api). You may want to use state-of-the-art payroll processing or onboarding software as a service (SaaS) that better suits your needs. In this case, if the BambooHR Marketplace doesn't provide an existing integration, your best bet is to use the BambooHR API to synchronize employee data with the other service that you're using.

What if you're working with a SaaS vendor that's not using but developing a state-of-the-art SaaS for onboarding or payroll? If so, you absolutely need to provide integrations with BambooHR and other HRIS platforms using their respective APIs.

## How to Extract Employee Data with the BambooHR API

Whatever motivates you to explore the BambooHR API, chances are that your integration efforts start with getting employee information from BambooHR. Let's see how exactly you can retrieve employee data from your BambooHR instance using the BambooHR API and Python.

To follow along, you need two things:

1. The latest [Python 3](https://www.python.org/downloads/) installed on your machine.
2. A BambooHR account.

### Signing Up for a BambooHR Account

If you don't have a BambooHR account, [sign up for a free trial](https://www.bamboohr.com/signup/f2).

After filling out the free trial form, create a name for your BambooHR domain (it's going to be used for your instance's subdomain, as in `https://your-bamboohr-domain.bamboohr.com/`) and then log in.

Your trial BambooHR account is pre-populated with sample employee records, so you don't need to worry about coming up with data to follow this tutorial.

### Getting Your API Key

To make calls to the BambooHR API, you need to create and copy an API key from your BambooHR account. Here's what you should do:

1. In BambooHR's navigation menu, click the user icon on the far right. In the pop-up menu that appears, click **API Keys**:

![Navigating to the API key management in BambooHR](https://i.imgur.com/6FYtNrG.png)

2. In the **My API Keys** view, click **Add New Key**.
3. In the **Add New API Key** view, enter `bamboohr-python` as the key name and then click **Generate Key**.
4. When BambooHR displays your newly generated API key, click **Copy Key** and then click **Done**.
5. When the API key is shown, copy and paste it to a safe place as BambooHR won't show it again.

### Setting Up a Python Application

You need to set up some boilerplate for the Python application that grabs data from the BambooHR API.

Open the terminal and then create and go to a directory called `bamboohr` that hosts your application:

```python
mkdir bamboohr && cd bamboohr
```

Inside the `bamboohr` directory, create a new Python virtual environment that is hosted in the `env` subdirectory. If you're on macOS or Linux, use the following command:

```shell
python3 -m venv env
```

On Windows, run this instead:

```shell
python -m venv env
```

Activate the new virtual environment in your terminal.

To do this on macOS or Linux, run the following:

```shell
source env/bin/activate
```

If you're on Windows, run the following activation script instead:

```shell
env\Scripts\activate.bat
```

You need Python's `requests` package to send API requests. Install it by running the following command:

```shell
pip install requests
```

Finally, create a Python file to host the source code that you'll write shortly:

```shell
touch main.py
```

### Getting Employee Data from the BambooHR API

Open your newly created `main.py` file in your favorite code editor.

Once inside the file, start by adding your needed `import` statements:

```python
from pathlib import Path
import requests
import json
```

These statements import the following:

1. The `requests` package that you've recently installed to make requests to the BambooHR API.
2. The built-in `json` module to parse the data you are getting from the API. Write it into a file.
3. The `Path` class from the built-in `pathlib` module that helps you create a directory to save the file to.

Next, let's define the base URL that you'll be reusing in your API calls. Paste the following code into your Python file:

```python
domain = 'your-bamboohr-domain'
base_url = f'https://api.bamboohr.com/api/gateway.php/{domain}/v1'
```

Make sure to replace `your-bamboohr-domain` with the actual BambooHR domain that you specified when creating your BambooHR account. It's used as the subdomain in the URL of your BambooHR instance: `https://your-bamboohr-domain.bamboohr.com/`.

The `base_url` uses your domain name to form your individual base BambooHR API URL that you need to make specific API requests later on.

Let's now save your BambooHR API key to the `api_key` constant. You also define another constant for authentication in the format that the `requests` package needs it to be in:

```python
api_key = 'your-api-key'
auth = (api_key, '')
```

Remember to replace `your-api-key` with your actual BambooHR API key that you generated and stashed earlier. Note that in the `auth` tuple, the second value is an empty string: the BambooHR API [uses basic HTTP authentication](https://documentation.bamboohr.com/docs/getting-started#authentication) where the API key is used as the username and the password can be any string, including an empty string.

The last thing you do to prepare for sending API requests is to declare a `headers` object that sets the `Accept` HTTP header to JSON. If you don't do this, BambooHR will return the results as XML by default:

```python
headers = {
    'Accept': 'application/json'
}
```

Now, let's add stubs for the three functions that perform the main steps of your program:

```python
def get_all_employees():
    pass

def print_all_employees(employees_json):
    pass

def save_all_employees_to_file(employees_json):
    pass

all_employees = get_all_employees()

```

`get_all_employees()` makes an API call and returns text data. `print_all_employees()` displays formatted data in the console output. `save_all_employees_to_file()` saves the data to a file.

You're also calling the first of these functions and saving whatever it returns to the `all_employees` variable.

Let's now fill the stub of the `get_all_employees()` function with code that makes an API request for the list of employees in the BambooHR directory. Update `get_all_employees()` to read the following:

```python
def get_all_employees():
    try:
        response_all_employees = requests.request('GET', f'{base_url}/employees/directory', headers=headers, auth=auth)
        if response_all_employees.status_code == 200:
            return response_all_employees.text
        else:
            print(
                f'Something went wrong when trying to get the requested info from the API server. Status code: {response_all_employees.status_code}. Message: {response_all_employees.reason}')
    except Exception as e:
        print("An error occurred while performing the API call: ", e)

```

Here's what happens inside the updated function:

1. The `request` function from the `requests` package makes a GET HTTP request to the BambooHR API's [Get Employee Directory](https://documentation.bamboohr.com/reference/get-employees-directory-1) endpoint. It uses string interpolation to combine the base URL that you've defined earlier with the path of the endpoint. The `headers` and `auth` constants are passed as respective arguments. The result of the call is saved into the `response_all_employees` variable.
2. The `response_all_employees` is a [`Response` object](https://requests.readthedocs.io/en/latest/api/#requests.Response). The `request` function returning this object may throw [several exceptions](https://requests.readthedocs.io/en/latest/api/#exceptions), so the code in the function is wrapped into a `try…except` block to provide basic handling for these.
3. The check for status code `200` verifies if your request has been successfully fulfilled, provided that no exceptions occur. If it's successful, then you return the textual employee data that arrived from the API, which is available through the `text` property of the `response_all_employees` object.
4. The status code and error message that the API has returned are simply printed if the status code of the response is anything other than `200`.

The employee directory data that the API returns looks something like this:

```json
{
  "fields": [
    {
      "id": "displayName",
      "type": "text",
      "name": "Display name"
    },
    {
      "id": "firstName",
      "type": "text",
      "name": "First name"
    },
    // more field definitions
  ],
  "employees": [
    {
      "id": "4",
      "displayName": "Charlotte Abbott",
      "firstName": "Charlotte",
      "lastName": "Abbott",
      "preferredName": null,
      "jobTitle": "Sr. HR Administrator",
      "workPhone": "801-724-6600",
      "mobilePhone": "801-724-6600",
      "workEmail": "cabbott@efficientoffice.com",
      "department": "Human Resources",
      "location": "Lindon, Utah",
      "division": "North America",
      "linkedIn": "www.linkedin.com",
      "instagram": "@instagram",
      "pronouns": null,
      "workPhoneExtension": "1272",
      "supervisor": "Jennifer Caldwell",
      "photoUploaded": true,
      "photoUrl": "https:\/\/images7.bamboohr.com\/619596\/photos\/4-6-4.jpg?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9pbWFnZXM3LmJhbWJvb2hyLmNvbS82MTk1OTYvKiIsIkNvbmRpdGlvbiI6eyJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTcyMDAxMTM2MH0sIkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzIyNjAzMzcwfX19XX0_&Signature=Ewi31wP5h7aoUEQSEmWEj7vAvo7GTVNXIjk4iJQ9XKGiczzwlUR~EJLrtaClvCxxsvxq0~cdVQ1yJO1fLe0loSP1t5BE48bOZQ0biOqawfMToqTmCBEV7ADxdvqs0rMnGVm9cV6F~p7LewXfp51lgW7u6A2TTudkWCbJN5btsJVp~1UaVyMBsZFwujYvFgrXxXLYxfb4WsvW3bVsnfnmMO8eHq5SIZw~joaII7sEJdzHKaMdsNaMP9GCUY-Mrs~~Gt9JcV3rt8M-YxXH8Rxmo18xmqCqePDML8ETWDWkhzjrDSNv6shU9PjuxhujxDJ6e0BVZ8XYKMn5sTUf9tlltQ__&Key-Pair-Id=APKAIZ7QQNDH4DJY7K4Q",
      "canUploadPhoto": 1
    },
    {
      "id": "5",
      "displayName": "Ashley Adams",
      "firstName": "Ashley",
      "lastName": "Adams",
      "preferredName": null,
      "jobTitle": "HR Administrator",
      "workPhone": "+44 207 555 4730",
      "mobilePhone": "+44 207 555 6671",
      "workEmail": "aadams@efficientoffice.com",
      "department": "Human Resources",
      "location": "London, UK",
      "division": "Europe",
      "linkedIn": "www.linkedin.com",
      "instagram": "@instagram",
      "pronouns": null,
      "workPhoneExtension": "130",
      "supervisor": "Jennifer Caldwell",
      "photoUploaded": true,
      "photoUrl": "https:\/\/images7.bamboohr.com\/619596\/photos\/5-6-4.jpg?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9pbWFnZXM3LmJhbWJvb2hyLmNvbS82MTk1OTYvKiIsIkNvbmRpdGlvbiI6eyJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTcyMDAxMTM2MH0sIkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzIyNjAzMzcwfX19XX0_&Signature=Ewi31wP5h7aoUEQSEmWEj7vAvo7GTVNXIjk4iJQ9XKGiczzwlUR~EJLrtaClvCxxsvxq0~cdVQ1yJO1fLe0loSP1t5BE48bOZQ0biOqawfMToqTmCBEV7ADxdvqs0rMnGVm9cV6F~p7LewXfp51lgW7u6A2TTudkWCbJN5btsJVp~1UaVyMBsZFwujYvFgrXxXLYxfb4WsvW3bVsnfnmMO8eHq5SIZw~joaII7sEJdzHKaMdsNaMP9GCUY-Mrs~~Gt9JcV3rt8M-YxXH8Rxmo18xmqCqePDML8ETWDWkhzjrDSNv6shU9PjuxhujxDJ6e0BVZ8XYKMn5sTUf9tlltQ__&Key-Pair-Id=APKAIZ7QQNDH4DJY7K4Q",
      "canUploadPhoto": 1
    },
    // more employee records
  ]
}
```

The response data consists of two arrays: `fields` and `employees`. The former lists the [fields](https://documentation.bamboohr.com/docs/list-of-field-names) that the response data contains, along with their [types](https://documentation.bamboohr.com/docs/field-types). Fields are important as you can use them in API calls to exactly define what kind of data you want to be returned. However, in this simple scenario, you don't need them: what you're after is the `employees` array.

### Printing and Saving Employee Data

You'll save the entire `employees` array to a file later on. For now, let's display basic information about each employee in the console.

Start by replacing the stub of the `print_all_employees()` function with the following:

```python
def print_all_employees(employees_json):
    for entry in employees_json:
        print(
            f'{entry["displayName"]}: {entry["jobTitle"]} at {entry["department"]}, based in {entry["location"]} ({entry["division"]})')
```

This function now goes over all employee entries and prints a quick summary that includes each employee's full name, job title, department, location, and division.

Now, at the end of the file, following the `all_employees` declaration, add this piece of code:

```python
if all_employees is not None:
    all_employees_json = json.loads(all_employees)['employees']
    print_all_employees(all_employees_json)
```

Initially, you're checking whether `all_employees` is null, which is possible if the prior API call has returned an error. If it's not null, you parse employee data as JSON and save the `employees` array from the resulting JSON object, thus stripping away the `fields` array. You then pass the JSON object to the `print_all_employees()` function.

If you call your program now by running `python main.py` in the terminal, you'll see something like this:

```shell
Charlotte Abbott: Sr. HR Administrator at Human Resources, based in Lindon, Utah (North America)
Ashley Adams: HR Administrator at Human Resources, based in London, UK (Europe)
Christina Agluinda: HR Administrator at Human Resources, based in Sydney, Australia (Asia-Pacific)
Shannon Anderson: HR Administrator at Human Resources, based in Vancouver, Canada (North America)
Maja Andev: VP of Product at Product, based in Lindon, Utah (North America)
Eric Asture: VP of IT at IT, based in Lindon, Utah (North America)
Cheryl Barnet: VP of Customer Success at Customer Success, based in Lindon, Utah (North America)
Jake Bryan: VP Learning and Development at Operations, based in Lindon, Utah (North America)

```

Finally, let's save the full set of employee data to a JSON file. At the end of `main.py`, following the call to `print_all_employees`, add a call to `save_all_employees_to_file`:

```python
save_all_employees_to_file(all_employees_json)
```

Then replace the stub of the `save_all_employees_to_file` function with the following:

```python
def save_all_employees_to_file(employees_json):
    destination_dir = 'data'
    Path(destination_dir).mkdir(parents=True, exist_ok=True)
    json_file = f'{destination_dir}/all_employees.json'
    with open(json_file, 'w', encoding='utf-8') as target_file:
        json.dump(employees_json, target_file, ensure_ascii=False, indent=4)
    print(f"Data saved to {json_file}.")
```

This function now creates the `data` directory if it doesn't exist, writes employee data to a JSON file in this directory, and reports a status update to the console.

If you want to see what your `main.py` file should look like by the end of this exercise, check out this ["Extracting Employee Data with the BambooHR API" example](https://github.com/apideck-samples/blog-examples/blob/main/extracting-employee-data-with-the-bamboohr-api-in-python/main.py).

If you're developing a product that relies on integrations with many different HRIS systems, you need to create and maintain multiple integrations that are going to be more sophisticated than the one shown earlier. The product would probably include authentication and authorization that are more advanced than those that use a single API key, handle error codes and retries, have a database layer instead of employee data dumped into JSON files, and more. After working through a few, chances are you'll realize that's probably not what you want to spend your development resources on.

Instead, consider using a [unified HRIS API](https://www.apideck.com/hris-api) like the one that [Apideck](https://www.apideck.com/unified-apis) provides. The unified HRIS API is a single API that enables pulling and pushing employee data from and to more than fifty HRIS platforms in real time. You can save valuable development time and resources instead of spending them on developing and maintaining all the integrations in-house.

## Summary

After reading this article, you now know how to write a proof-of-concept Python application that gets basic employee information from a BambooHR instance using the BambooHR API. See the ["Extracting Employee Data with the BambooHR API" example](https://github.com/apideck-samples/blog-examples/blob/main/extracting-employee-data-with-the-bamboohr-api-in-python/main.py) for the source code of `main.py` that results from performing the instructions given earlier.

In a real-life integration, you need to worry about many other things, such as managing authentication and authorization, handling client- and server-side error codes, implementing retry policies, and monitoring API versions to prevent service interruptions.

Doing this for one HRIS service is fine, but if you're integrating with dozens of them, your development team can get overwhelmed quickly. If you don't want this to happen, start simplifying your HRIS integrations today by [signing up to Apideck](https://platform.apideck.com/api/auth/login?product=unify&screenHint=signup&connector=bamboohr).
