This package of tools is provided by Greenhouse for customers who use PHP. There are three tools provided.
- Job Board Service: Used to embed iframes in your template or view files.
- Job API Service: Used to fetch data from the Greenhouse Job Board API.
- Application Service: Used to send applications in to Greenhouse.
- Harvest Service: Used to interact with the Harvest API.
- PHP Version
- 5.6 or greater for V1.
- 7.3 or greater for V2.
- Composer. You should be using Composer to manage this package.
Due to the EOL on PHP 5 and Guzzle 6, this package was upgraded to require PHP 7.3. We will no longer be supporting V1. Going forward, new features will be added exclusively to the 2.0 branch. You should update to 2.0 as soon as reasonably possible.
This is available on Packagist. Install via Composer. Add the following to your requirements:
"grnhse/greenhouse-tools-php": "~2.0"
- Represents a minor version upgrade from Guzzle 7.1 to 7.5.
- Adds support for versions of Greenhouse endpoints beyond v1.
In order to support Greenhouse's new Inclusion URLs, we dropped a requirement that an $id be included for some URLs. Previously, a URL like getActivityFeedForUser()
would throw a Greenhouse Exception with a message that id was required. Now, that method will just translate to user/activity_feed
and return a 404 Not Found response. We did this in order to support Greenhouse's new Inclusion URLs. In the previous version getQuestionsSetsForDemographics()
, (found here), would have thrown an "id required" exception instead of correctly routing to demographics/question_sets
.
Support for PHP 5.6, 7.0, 7.1, and 7.2 were dropped in order to support the latest version of Guzzle.
The Greenhouse Service is a parent service that returns the other Greenhouse Services. By using this service, you have access to all the other services. The Greenhouse service takes an array that optionally includes your job board URL Token (found here in Greenhouse) and your Job Board API Credentials (found here in Greenhouse). Create a Greenhouse Service object like this:
<?php
use \Greenhouse\GreenhouseToolsPhp\GreenhouseService;
$greenhouseService = new GreenhouseService([
'apiKey' => '<your_api_key>',
'boardToken' => '<your_board_token>'
]);
?>
Using this service, you can easily access the other Greenhouse Services and it will use the board token and client token as appropriate.
This service generates the appropriate HTML tags for use with the Greenhouse iframe integration. Use this service to generate either links to a Greenhouse-hosted job board or the appropriate tags for a Greenhouse iframe. Access the job board service by calling:
<?php
$jobBoardService = $greenhouseService->getJobBoardService();
// Link to a Greenhouse hosted job board
$jobBoardService->linkToGreenhouseJobBoard();
// Link to a Greenhouse hosted job application
$jobBoardService->linkToGreenhouseJobApplication(12345, 'Apply to this job!', 'source_token');
// Embed a Greenhouse iframe in your page
$jobBoardService->embedGreenhouseJobBoard();
?>
Use this service to fetch public job board information from our job board API. This services does not require an API key. This is used to interact with the GET endpoints in the Greenhouse Job Board API. These methods can be found here. Access this service via:
$jobApiService = $greenhouseService->getJobApiService();
The methods in this service are named in relation to the endpoints, so to use the GET Offices endpoint, you'd call:
$jobApiService->getOffices();
And to get a specific office:
$jobApiService->getOffice($officeId);
The only additional parameters used in any case are for the "content" and "questions" parameters in the Jobs endpoint. These are managed with boolean arguments that default to false
in the getJobs
and getJob
methods. To get all jobs with their content included, you'd call:
$jobApiService->getJobs(true);
while to get a job with its questions included, you'd call:
$jobApiService->getJob($jobId, true);
Use this service to post Applications in to Greenhouse. Use of this Service requires a Job Board API key which can be generated in Greenhouse. Example usage of this service follows:
<?php
$appService = $greenhouseService->getApplicationApiService();
$postParams = array(
'id' => 82354,
'first_name' => 'Johnny',
'last_name' => 'Test',
'email' => 'jt@example.com',
'resume' => new \CURLFile('path/to/file.pdf', 'application/pdf', 'resume.pdf'),
'question_12345' => 'The answer you seek',
'question_123456' => array(12345, 23456, 34567)
);
$appService->postApplication($postParams);
?>
The Application will handle generating an Authorization header based on your API key and posting the application as a multi-part form. This parameter array follows the PHP convention except for the case of multiselect submission (submitting parameters with the same name). While the PHP docs want users to submit multiple values like this:
'question_123456[0]' => 23456,
'question_123456[1]' => 12345,
'question_123456[2]' => 34567,
The Greenhouse packages requires you to do it like this:
'question_123456' => array(23456,12345,34567),
This prevents issues that arise for systems that do not understand the array-indexed nomenclature preferred by Libcurl.
Use this service to interact with the Harvest API in Greenhouse. Documentation for the Harvest API can be found here. The purpose of this service is to make interactions with the Harvest API easier. To create a Harvest Service object, you must supply an active Harvest API key. Note that these are different than Job Board API keys.
<?php
$harvestService = $greenhouseService->getHarvestService();
?>
Via the Harvest service, you can interact with any Harvest methods outlined in the Greenhouse Harvest docs. Harvest URLs fit mostly in to one of the following five formats:
https://harvest.greenhouse.io/v1/<object>
: This is the most common URL format for GET methods in Greenhouse. For endpoints in this format, the method will look like$harvestService->getObject()
. Examples of this are$harvestService->getJobs()
or$harvestService->getCandidates()
https://harvest.greenhouse.io/v1/<object>/<object_id>
: This will get the object with the given ID. This is expected to only return or operate on one object. The ID will always be supplied by an parameter array with a key namedid
. For instance:$harvestService->getCandidate($parameters);
https://harvest.greenhouse.io/v1/<object>/<object_id>/<sub_object>
: URLs in this format usually mean that you want to get all the sub_objects for the object with the object id. Examples of this are$harvestService->getJobStagesForJob(array('id' => 123))
and$harvestService->getOffersForApplication(array('id' => 123))
https://harvest.greenhouse.io/v1/<object>/<object_id>/<sub_object>/<sub_object_id>
: URLs in this format usually mean you are performing an operation on an individual sub-object. An example of this is$harvestService->deleteTagsForCandidate(array('id' => 123, 'second_id' => 234))
https://harvest.greenhouse.io/v1/<object>/<opbject_id>/<sub_object>/<qualifier>
: Urls in this format usually mean you are trying to act on a limited universe of a type of sub-object. An example of this is$harvestService->deletePermissionForJobForUser(array('id' => 123));
which deletes the designated permission on a job from a user.
Some method calls and URLs do not fit this format, but the methods were named as close to fitting that format as possible. These include:
getActivityFeedForCandidate
: Get a candidate's activity feedpostNoteForCandidate
: Add a note to a candidateputAnonymizeCandidate
: Anonymize some fields on a candidategetCurrentOfferForApplication
: Get only the current offer for a candidatepostAdvanceApplication
: Advance an application to the next stagepostMoveApplication
: Move an application to any stage.postTransferApplicationToJob
: Move an application to a new job.postRejectApplication
: Reject an applicationpostUnrejectApplication
: Unreject an applicationpostMergeCandidates
: Merge a duplicate candidate to a primary candidate.getCandidateTags
: Returns all candidate tags in your organization.postCandidateTags
: Create a new candidate tag in your organization.getTagsForCandidate
: Returns all tags applied to a single candidate.getCustomFields
: Returns all custom fields: Note for this method, the id argument will contain the type of custom field you want to retrieve.$harvestService->getCustomFields(array('id' => 'job'));
will return all the job custom fields in your organization. Leaving this argument blank will return all custom fields.getTrackingLinks
: Return a specific traking link for the supplied token.: Note for this link, the token will be provided in the 'id' argument.$harvestService->getTrackingLink(array('id' => '<token>'));
patchEnableUser
: Enable a disabled user from accessing Greenhouse.patchDisableUser
: Disable a user from accessing Greenhouse.getQuestionSetsForDemographics
: List all demographic question sets.getQuestionSetsForDemographics(['id' => 12345])
: Fetch demographic question set with the id 12345getQuestionsForDemographics
: List all demographic questions.getQuestionsForDemographics(['id' => 12345])
: List demographic question with id 12345.getQuestionsForQuestionSetsForDemographics(['id' => 12345])
: Fetch all demographic questions for question set with id 12345getAnswerOptionsForDemographics
: List all demographic answer options.getAnswerOptionsForDemographics(['id' => 12345])
: List demographic answer option with id 12345.getAnswerOptionsForQuestionsForDemographics(['id' => 12345])
: Fetch all answer option for demographic question with id 12345getAnswersForDemographics
: List all demographic answers.getAnswersForDemographics(['id' => 12345])
: List demographic answer with id 12345.getDemographicAnswersForApplications(['id' => 12345])
: List demographics answers for the application with id 12345
You should use the parameters array to supply any URL parameters and headers required by the harvest methods. For any items that require a JSON body, this will also be supplied in the parameter array.
$parameters = array(
'id' => $applicationId,
'headers' => array('On-Behalf-Of' => $auditUserId),
'body' => '{"from_stage_id": 123, "to_stage_id": 234}'
);
$harvestService->moveApplication($parameters);
Note you do not have to supply the authorization header in the headers
array. This will be appended to the headers array automatically presuming the supplied API key is valid.
The parameters array is also used to supply any paging and filtering options that would normally be supplied as a GET query string. Anything that is not in the id
, headers
, or body
key will be assumed to be a URL parameter.
Ex: Getting a page of applications
$parameters = array(
'per_page' => 100,
'page' => 2
);
$harvestService->getApplications($parameters);
// Will call https://harvest.greenhouse.io/v1/applications?per_page=100&page=2
If the ID key is supplied in any way, that will take precedence.
Ex: Adding a candidate to Greenhouse
A note on paging: As mentioned in the Harvest documentation, Greenhouse supports two methods of paging depending on the endpoint. The next page is returned in a Link header. The next page link is accessible in the Harvest Service at:
$harvestService->nextLink();
The link returned by this method will give you the next page of objects on this endpoint. Depending on which paging method the endpoint supports, the link returned will look like one of the following:
https://harvest.greenhouse.io/v1/<object>?page=2&per_page=100
https://harvest.greenhouse.io/v1/<object>/?since_id=161963
If the nextLink() method returns nothing, you have reached the last page.
Greenhouse includes several methods in Harvest to POST new objects. It should be noted that the creation of candidates and applications in Harvest differs from the Application service above. Documents via Harvest can only be received via binary content or by including a URL which contains the document. As such, the Harvest service uses the body
parameter in Guzzle instead of including POST parameters.
$candidate = array(
'first_name' => 'John',
'last_name' => 'Doe',
'phone_numbers' => array(
array('value' => '310-555-2345', 'type' => 'other')
),
'email_addresses' => array(
array('value' => 'john.doe@example.com', 'type' => 'personal')
),
'applications' => array(
array(
'job_id' => 146855,
'attachments' => array(
array(
'filename' => 'resume.pdf',
'type' => 'resume',
'url' => 'http://example.com/resume.pdf',
'content_type' => 'application/pdf'
)
)
)
)
);
$parameters = array(
'headers' => array('On-Behalf-Of' => 12345),
'body' => json_encode($candidate)
)
$harvest->postCandidate($parameters);
All Greenhouse Harvest methods that use Post will follow this convention. In short, the JSON body as described in Greenhouse's provided documentation should be sent in the body
parameter.
A note on custom fields: getCustomFields
and getCustomField
are different than the rest of the Harvest service. getCustomFields
takes a text id to limit the response to just the custom fields for a specific set of objects. For example, you'd use id => 'job'
to return only custom fields for a job. While getCustomField
takes a normal numeric id to retrieve a single custom field.
A note on future development: The Harvest package makes use PHP's magic __call
method. This is to handle Greenhouse's Harvest API advancing past this package. New endpoint URLs should work automatically. If Greenhouse adds a GET https://harvest.greenhouse.io/v1/widgets
endpoint, calling $harvestService->getWidgets()
should be supported by this package.
Greenhouse also now supports DELETE methods via the API service, which requires the id
of the object being deleted and the id of the user on whose behalf we are deleting the object.
// DELETE an application
$parameters = array(
'id' => $applicationId,
'headers' => array('On-Behalf-Of' => $auditUserId)
);
$harvestService->deleteApplication($parameters);
All Greenhouse deletion events via Harvest will follow this convention.
All exceptions raised by the Greenhouse Service library extend from GreenhouseException
. Catch this exception to catch anything thrown from this library.