Greenhouse API: Guide for ATS Integration and Automation

Published on:
April 29, 2025

Getting Started with Greenhouse API

With Greenhouse’s Harvest, you can access most of your Greenhouse data!

The Harvest API was designed to allow customers to export their data from Greenhouse. However, it can also be used to:

  1. Update candidate information.
  2. Add attachments to candidate profiles.
  3. Advance, move, and reject applications.

HTTP Basic Authentication

Before interacting with Greenhouse's API, you must authenticate your requests to ensure they are secure. Greenhouse uses HTTP Basic Auth for authentication. In this setup, your Greenhouse API token is the username, and the password is left blank.

Steps to Authenticate:

1. Obtain API Credentials:

  • Navigate to your Greenhouse account
  • Go to Configure > Dev Center > API Credential Management
  • Create a new API Key of type "Harvest"
  • Assign the necessary permissions to the key, specifying which endpoints it can access.  To add or remove endpoint permissions on an API key, go to the Dev Center in Greenhouse, click "API Credential Management," then click "Manage Permissions" next to your Harvest API Key. From there, check or uncheck permissions for any endpoints.

2. Setting credentials with cURL:

  • Using curl, an example request would look like:
curl -u your_api_key: https://harvest.greenhouse.io/v1/candidates

Here, your_api_key is your API key generated in the previous step. The command, -u your_api_key: tells curl to use HTTP Basic Authentication with your API key as the username and an empty password.

3. Authorization Header:Most HTTP clients will automatically use a given username and password to generate the required Authorization header. However, you may need to explicitly set this header. The header has the following format:

Authorization: Basic <base64("username:password")>

Note: Since only a username needs to be provided in our case, you'll need to append a : (colon) to your Greenhouse API token and then Base64 encode the resulting string.

Deep Dive into Greenhouse API Endpoints

The Greenhouse Harvest API provides a range of endpoints that allow developers to access various candidates, applications, and jobs data.

Here are the most commonly used endpoints, along with practical use cases.

1. GET /v1/candidates

  • Description: List all of an organization's candidates.
  • cURL Request:
curl -X GET 'https://harvest.greenhouse.io/v1/candidates?per_page=100&page=1' \
  -H 'Authorization: Basic <base64_encoded_api_key>'
  • Parameters:
    • page: Specifies the page number of the results to retrieve. Defaults to 1 if not provided.
    • per_page: Determines the number of records per page. The maximum allowed value is 500. If you provide a value exceeding this limit, you'll receive a 422 Unprocessable Entity error.
  • Use Case: Obtain all the candidates in a company from Greenhouse into your system.

2. POST /v1/candidates

  • Description: Create a new candidate.
  • cURL Request:
curl -X POST 'https://harvest.greenhouse.io/v1/candidates'
-H "Content-Type: application/json"
-H "On-Behalf-Of: {greenhouse user ID}"
-H "Authorization: Basic <base64_encoded_api_key>"
  • Parameters:
    • greenhouse user ID: ID of the user issuing this request. Required for their auditing purposes.
  • JSON Body Parameters: The above command takes a JSON request, wherein first_name, last_name, and applications are required fields. For example, a typical JSON will be structured like this:
{
  "first_name": "John",
  "last_name": "Locke",
  "company": "The Tustin Box Company",
  "title": "Customer Success Representative",
  "is_private": false,
  "phone_numbers": [
    {
      "value": "555-1212",
      "type": "mobile"
    }
  ],
  "addresses": [
    {
      "value": "123 Fake St.",
      "type": "home"
    }
  ],
  "email_addresses": [
    {
      "value": "john.locke+work@example.com",
      "type": "work"
    },
    {
      "value": "john.locke@example.com",
      "type": "personal"
    }
  ],
  "website_addresses": [
    {
      "value": "johnlocke.example.com",
      "type": "personal"
    }
  ],
  "social_media_addresses": [
    {
      "value": "linkedin.example.com/john.locke"
    },
    {
      "value": "@johnlocke"
    }
  ],
  "educations": [
    {
      "school_id": 459,
      "discipline_id": 940,
      "degree_id": 1230,
      "start_date": "2001-09-15T00:00:00.000Z",
      "end_date": "2004-05-15T00:00:00.000Z"
    }
  ],
  "employments": [
      {
          "company_name": "Greenhouse",
          "title": "Engineer",
          "start_date": "2012-08-15T00:00:00.000Z",
          "end_date": "2016-05-15T00:00:00.000Z"
      }
  ],
  "tags": [
    "Walkabout",
    "Orientation"
  ],
  "applications": [
    {
      "job_id": 215725
    },
     {
      "job_id": 185289
    }
  ]
}
  • Use Case: Add a new candidate to an Organization using the Greenhouse system.

3. POST/v1/candidates/{id}/attachments

  • Description: Post an attachment to a candidate's profile by the candidate id.
  • cURL Request:
curl -X POST 'https://harvest.greenhouse.io/v1/candidates/{id}/attachments'
-H "Content-Type: application/json"
-H "On-Behalf-Of: {greenhouse user ID}"
-H "Authorization: Basic <base64_encoded_api_key>"
  • Parameters:
    • greenhouse user ID: ID of the user issuing this request. Required for their auditing purposes.
  • JSON Body Parameters: The above command takes a JSON request, wherein filename, type, and content_type are required fields. For example, a typical JSON will be structured like this:
{
  "filename" : "resume.pdf",
  "type" : "resume",
  "content" : "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs...",
  "content_type" : "application/pdf"
}
  • Use Case: Add an attachment to a candidate in an Organization using the Greenhouse system.

Pagination and Rate limits

Pagination

The Greenhouse Harvest API paginates responses for endpoints returning collections. Pagination details are provided in the Link response header, following the RFC-5988 standard. This header includes URLs for next, prev, and last pages. If the Link header is absent, it indicates that the response contains only a single page of results. 

Implementation Steps:

  1. Initial Request: Make a GET request to the desired endpoint, e.g., GET /v1/candidates.
  2. Inspect the Link Header: Check the Link header in the response for pagination URLs.
  3. Iterate Through Pages: Continue making requests to the next URL provided in the Link header until it is no longer present, indicating the end of the paginated results.

Example:

Suppose the Link header in the response is:

Link: <https://harvest.greenhouse.io/v1/candidates?page=2&per_page=100>; rel="next",
      <https://harvest.greenhouse.io/v1/candidates?page=10&per_page=100>; rel="last"

You would then make a request to the next URL to retrieve the subsequent page of results.

Notes:

Rate Limiting

The Greenhouse Harvest API enforces rate limits to ensure fair usage:

  • Limit: The number of allowed requests per 10-second window is specified in the X-RateLimit-Limit response header.
  • Remaining: The X-RateLimit-Remaining header indicates how many requests you have left in the current window.
  • Exceeding the Limit: If you exceed the rate limit, the API responds with an HTTP 429 status code. The response includes:
    • Retry-After Header: Specifies the number of seconds to wait before retrying.
    • X-RateLimit-Reset Header: Indicates the timestamp when the rate limit will reset.

Best Practices:

  • Monitor Headers: Always check the X-RateLimit-Remaining header to monitor your usage.
  • Implement Backoff Strategy: If you receive a 429 response, respect the Retry-After duration before making new requests.

Troubleshooting Guide

Error Handling

Harvest API can return errors for various reasons, such as invalid requests or server issues. Greenhouse uses standard HTTP status codes to indicate success or failure.

Common Status Codes:

Get Started With with Greenhouse API Using Bindbee

Integrating with Greenhouse shouldn’t feel like a battle.But for most teams, it ends up being a major time sink—draining valuable engineering resources.

Why put your developers through the grind when Bindbee can get you live with Greenhouse in just minutes?

Setting up Greenhouse connector with Bindbee

  • Sign up with Bindbee and navigate to the dashboard.
  • Create a Connector:
    • Click on Create Connector from the dashboard.
    • Select HRIS as the type of integration. Enter customer details and give your connector a unique ID (e.g., Employment_Hero_Integration).
  • Generate a Magic Link:
    • After setting up the connector, click Create Link to generate a magic link. This will allow the customer to authenticate the connection with Greenhouse.
    • Open the link and enter the necessary credentials. This step establishes the connection between Greenhouse and Bindbee.
  • Sync the Connector:
    • Once the connection is made, the connector will begin syncing data from BambooHR. This may take a few minutes depending on the size of the data. You can track the sync status in the connector section.
  • Access the Synced Data:
    • After syncing, go to the Employee section in the Bindbee dashboard and select Get Employees to retrieve employee data from BambooHR.
  • Get the API Key and Connector Token:
    • Copy the API key and the x-connector-token from the Bindbee dashboard, which you will need to make authenticated API requests.

Retrieving Employee Data with Bindbee

Once the Greenhouse data has been synced, you can retrieve employee data on to your application via the Bindbee API.

Here’s a step-by-step process for accessing synced data from BambooHR through Bindbee’s unified API:

1. Request Setup:

  1. Use the Bindbee API to send a request for employee data. You’ll need both your Bindbee API token and the x-connector-token.

2. Example  cURL Request:

curl --request GET \
  --url https://api.bindbee.com/hris/v1/employees \
  --header 'Authorization: Bearer YOUR_BINDBEE_API_KEY' \
  --header 'x-connector-token: YOUR_CONNECTOR_TOKEN'

This request will return a list of employee objects, including details like the employee’s first name, last name, job title, department, and contact information.

3. Sample Response:

{
  "items": [
    {
      "id": "018b18ef-c487-703c-afd9-0ca478ccd9d6",
      "first_name": "Kunal",
      "last_name": "Tyagi",
      "job_title": "Chief Technology Officer",
      "department": "Engineering",
      "work_email": "kunal@bindbee.dev"
    }
  ]
}

Bulk Employee Data Retrieval

For retrieving large datasets, Bindbee simplifies the process by allowing you to fetch bulk employee data from BambooHR.

The pagination feature helps manage large responses by returning results in pages.

  • Pagination Parameters:
    • Use the cursor and page_size parameters to navigate through the results. By default, Bindbee returns 50 records per page.
    • Example of a paginated request:
url = "https://api.bindbee.com/hris/v1/employees?cursor=MDE4YjE4ZWYtYzk5Yy03YTg2LTk5NDYtN2I3YzlkNTQzM2U1&page_size=50"
response = requests.get(url, headers=headers)
  • Querying for Specific Employee Data:
    • You can further refine your request by filtering based on specific fields, such as manager_id, remote_id, or company_id to get employees under a particular manager or company.

Say hello to Bindbee.

Book a demo with our experts today.

Greenhouse API: Guide for ATS Integration and Automation

Aditya

Product & Growth -
Bindbee
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.