Introduction
Greenhouse integrates with many candidate testing platforms, including code testing, video interviewing, personality testing, and more. We've created the Assessment Partner API to allow our customers to seemlessly integrate our Partners' assessments into their Greenhouse interview workflow. This document outlines the end-user experience with the integration and the technical details of how to implement it.
Working with Greenhouse to implement the integration
To begin the integration process, please send the following information to us at partners@greenhouse.io:
- URL for your
list_tests
API call - URL for your
send_test
API call - URL for your
test_status
API call - URL for your
response_error
API call - A sample API key
The Partnerships team will configure endpoint URLs for creating assessment stages and provide next steps on receiving access to a Sandbox account to test the integration. If you are building an integration for use by mutual customers, we will need documentation on the integration for the Greenhouse Help Center.
Workflow
The Assessment Partner will provide an org-level API key to the customer. The organization will provide this API key to their Greenhouse Account Manager, who will input it into our system.
Selecting the Test
Once Greenhouse enters the API key for the organization, a new partner interview stage will be available for use. The user can add this stage to the Hiring Plan of any job that has access to the new Assessment Partner stage. Greenhouse will then make an API call to the List Tests endpoint to determine what tests the organization has configured.
Sending the Test
When a candidate reaches this Interview Stage, the user will click the "Send Test" button to send the test to the candidate via the Send Test endpoint. Greenhouse will send the Test ID and candidate email to the Assessment Partner, who will email the test to the candidate. The Assessment Partner will then send Greenhouse the ID for this unique test instance.
Receiving the Test Results
Greenhouse will periodically poll the Test Status endpoint to retrieve the candidate's test status and results. When the candidate completes the test, Greenhouse will notify the appropriate user that the test is complete. The user will be able to view the candidate's score, navigate to the partner site to see more details, and make an advance or reject decision within Greenhouse. The user will also be able to filter candidates by score and advance or reject candidates in bulk.
Alternatively, Greenhouse's Assessment API now includes the ability to notify Greenhouse of completed tests via the PATCH - Mark Test as Completed endpoint to avoid long polling!
Note: You can only update test statuses for active, unhired candidates.
Authentication
Every request Greenhouse sends to a Assessment Partner’s API will utilize HTTP Basic Authentication over HTTPS. As such, we require each of the API endpoints to use HTTPS.
When an organization decides to utilize a Assessment Partner’s integration, they will provide their Greenhouse Account Manager with their API key for that Assessment Partner.
Greenhouse will then make all requests for the organization using that API key as the username in Basic Authentication. Greenhouse will append a : (colon) to the API token and then Base64 encode the resulting string.
Note: The API key sent to Greenhouse must be less than 171 characters.
Upon receiving a request, the Assessment Partner should inspect the API key to determine whether the request should be permitted and which data should be returned.
Example Situation
- Assessment Partner A provided Customer 1 with an API key.
- Customer 1 provided this key to Greenhouse.
Assessment Partner A provided the following URL for its
list_tests
endpoint:https://www.testing-partner-a.com/api/list_tests
Greenhouse would make the following request to retrieve the list of available tests:
GET https://www.testing-partner-a.com/api/list_tests Authorization: Basic < base-64-encoded-credentials >
General considerations
Unless otherwise specified, API methods generally conform to the following:
- Properties without a value will use
null
instead of being undefined - "Snake Case" is used for attribute names (e.g.
first_name
) - We reserve the right to add more properties to objects, but will never change or remove them
Assessment API Change Log
The timestamps below are Eastern Time.
Date | Description |
---|---|
Oct 4, 2024 3:30:00PM | Updated guidelines around API key character length in Introduction |
Sep 18, 2024 10:45:00AM | Added sent_by to the Send Test request example |
Oct 19, 2023 12:30:00PM | Clarified use of Assessment API for active, unhired candidates in Introduction and Test Status |
Oct 13, 2023 3:00:00PM | Added URL for response_error as a requirement in Introduction |
Aug 22, 2023 3:00:00PM | Fixed URL expiry timing in Send Test |
Aug 21, 2019 2:00:00PM | Added Change Log and General Consideration sections to the Assessment API documentation |
Aug 21, 2019 2:00:00PM | Added PATCH - Mark Test as Completed endpoint |
List Tests
Greenhouse will first need to retrieve the list of tests from the Assessment Partner using the list_tests
API endpoint. We will show the list of available tests to the user, who will to select the appropriate test for a given candidate.
GET https://www.testing-partner.com/api/list_tests
curl 'https://www.testing-partner.com/api/list_tests'
-H "Authorization: Basic MGQwMzFkODIyN2VhZmE2MWRjMzc1YTZjMmUwNjdlMjQ6"
Request
Greenhouse will make a GET request to the list_tests
endpoint specified by the Assessment Partner.
Response
API Response
[
{
"partner_test_id": "12345",
"partner_test_name": "My First Test"
},
{
"partner_test_id": "54321",
"partner_test_name": "My Second Test"
}
]
The Assessment Partner’s response should include a JSON payload containing a list of test objects for the organization. Each test object should contain the keys partner_test_id
and partner_test_name.
Property Name | Type | Required | Description |
---|---|---|---|
partner_test_id | String | Yes | Identifies a test available to an organization. |
partner_test_name | String | Yes | A descriptive title for the test. We will use this value our UI as the test’s label. |
Send Test
When a Greenhouse user sends a test to a candidate, Greenhouse will send a request to the Assessment Partner's send_test
API endpoint. The Assessment Partner will then email the specified candidate the specified test.
Request
curl -X POST 'https://www.testing-partner.com/api/send_test'
-H "Authorization: Basic MGQwMzFkODIyN2VhZmE2MWRjMzc1YTZjMmUwNjdlMjQ6"
{
"partner_test_id": "12345",
"candidate": {
"first_name": "Harry",
"last_name": "Potter",
"resume_url": "https://hogwarts.com/resume",
"phone_number": "123-456-7890",
"email": "hpotter@hogwarts.edu",
"greenhouse_profile_url": "https://app.greenhouse.io/people/17681532?application_id=26234709"
},
"sent_by": "test_sender@example.org",
"url": "https://app.greenhouse.io/integrations/testing_partners/take_home_tests/12345"
}
Greenhouse will initiate the process by sending a POST request to the send_test
endpoint specified by the Assessment Partner. The body of the POST request will contain a JSON payload.
Property Name | Type | Required | Description |
---|---|---|---|
partner_test_id | String | Yes | Identifies a test available to an organization. Initially provided as a response to the List Tests request. |
first_name | String | Yes | The first name of the candidate. |
last_name | String | Yes | The last name of the candidate. |
resume_url | String | No | A URL to the candidate’s resume. This URL will expire 7 days after the request. |
phone_number | String | No | The candidate’s phone number. |
String | Yes | The candidate’s email address. The test should be sent to this address. | |
greenhouse_profile_url | String | Yes | URL to the candidate’s Greenhouse application. Allows the partner to link back to Greenhouse. |
sent_by | String | No | Test sender's email address |
url | String | Yes | URL to which to send the PATCH Completed Test request, if using |
Response
The API Response
{
"partner_interview_id": "98765"
}
The response to the send_test
request should contain a JSON payload in its body. This payload should be a single object that contains a single key: partner_interview_id
.
Property Name | Type | Required | Description |
---|---|---|---|
partner_interview_id | String | Yes | Identifies a candidate’s test. |
PATCH - Mark Test as Completed
When a candidate completes a test, send this request to the URL sent in the initial Send Test request to signal Greenhouse that the test has been completed. Upon this, Greenhouse will send a request to your Test Status endpoint.
PATCH https://app.greenhouse.io/integrations/testing_partners/take_home_tests/12345
Request
curl -X PATCH 'https://app.greenhouse.io/integrations/testing_partners/take_home_tests/12345'
-H "Authorization: Basic MGQwMzFkODIyN2VhZmE2MWRjMzc1YTZjMmUwNjdlMjQ6"
No parameters are necessary with this request.
Response
The response will return only the HTTP status code.
Sending Updates to Greenhouse
If you have implemented the polling option:
After a successful send_test
request, Greenhouse will check whether the test instance has been completed by polling the test_status
endpoint hourly. We will discontinue polling the test_status
endpoint after the candidate is marked as hired, after we receive a partner_status
of complete
, or after 8 weeks have passed since the test was sent.
If you have implemented the PATCH Completed Test option:
After a successful send_test
request, you can alert Greenhouse to updates of the test's status by sending a PATCH Completed Test request to the URL found in the url
field of the send_test
request. This will trigger a Test Status request from Greenhouse. Active, unhired candidates will show the completed test status.
Test Status
Tells Greenhouse the current status of a take home test.
GET https://www.testing-partner.com/api/test_status?partner_interview_id=12345
Request
curl 'https://www.testing-partner.com/api/test_status?partner_interview_id=12345'
-H "Authorization: Basic MGQwMzFkODIyN2VhZmE2MWRjMzc1YTZjMmUwNjdlMjQ6"
Greenhouse will send a GET
request to the test_status
endpoint provided by the Assessment Partner. The GET
request will contain a single query string parameter: partner_interview_id
.
Parameter Name | Type | Required | Description |
---|---|---|---|
partner_interview_id | String | Yes | Identifies a test instance for a candidate. Initially provided as a response to the Send Test request. |
Response
API Response
{
"partner_status": "complete",
"partner_profile_url": "http://example.com/tests/12345",
"partner_score": 81,
"metadata":
{
"Started At": "10:15 AM 26 March 2014",
"Completed At": "10:15 AM 26 March 2014",
"Notes": "This candidate did extremely well!"
}
}
The response to a test_status
request should contain a JSON object in its body with up to four keys:
partner_status
, partner_profile_url
, partner_score
, and metadata
.
Property Name | Type | Required | Description |
---|---|---|---|
partner_status | String | Yes | Describes the current state of the test instance. If the test has been completed and results are available, this value should be "complete". We will continue to poll until the status is "complete", or until 8 weeks has passed since the test was sent. |
partner_profile_url | String | Required only if status is complete. | URL to the candidate’s page on the Test Partner’s website. |
partner_score | Number | No | Numerical score reflecting the candidate’s performance on the test. |
metadata | Object | No | A non-nested object containing keys and values that will be displayed in our test results. All of the values must be Javascript primitives. |
Response Error
When Greenhouse receives a malformed response for any of Assessment Partner's API endpoints, we would like to report the errors to the Assessment Partner. As such, each Assessment Partner should provide an API endpoint to ingest this information.
POST https://www.testing-partner.com/api/request_errors
Request
curl -X POST 'https://www.testing-partner.com/api/request_errors'
-H "Authorization: Basic MGQwMzFkODIyN2VhZmE2MWRjMzc1YTZjMmUwNjdlMjQ6"
{
"api_call": "test_status",
"errors": ["partner_status is 'complete' but partner_profile url is missing"],
"partner_test_id" : "12345",
"partner_test_name": "Personality Test",
"partner_interview_id": "299506",
"candidate_email": "hpotter@hogwarts.edu"
}
After receiving a malformed response, Greenhouse will provide the Assessment Partner with the details of the failed response. Each time an invalid response arrives, Greenhouse will send a POST request to the response_error
API endpoint.
The body of the request will contain as much information as Greenhouse has at the moment of failure.
For example, if a list_tests
request fails, Greenhouse can only provide the api call (in this case, ‘list_tests’) and the assorted errors (missing keys, unexpected data types, etc.). However, if a test_status
request fails, we can provide more information (partner_test_id, partner_interview_id, etc.) that may prove useful for debugging purposes. Assessment Partners can always expect to receive api_call
and errors
in the JSON body.
Property Name | Value | Required | Description |
---|---|---|---|
api_call | String | Yes | The name of the API call that generated the malformed response. |
errors | Array | Yes | An array of strings which describe an error that prevented the response from validating. |
partner_test_id | String | No | Identifies a test available to an organization. Initially provided as a response to the List Tests request. |
partner_test_name | String | No | A human-readable string that identifies the test. Initially provided as a response to the List Tests request. |
partner_interview_id | String | No | Identifies a candidate’s test. |
candidate_email | String | No | The candidate’s email address. The test should be sent to this address. |
Response
API Response
{
"status": 200
}
The response to a successful response_errors
request should contain a response code of 200.
Errors
Successful requests should generate a response with a 200-level status code. Unsuccessful requests should generate a response with one of the following responses:
Status Code | Description |
---|---|
401 | Unsuccessful authentication with the provided API key. |
404 | The requested resource could not be found. |