Recreating the Recruiting Activity Report (REST API)

Forum for users and developers of Bullhorn's API service.

Moderators: StaffingSupport, s.emmons, BullhornSupport

Post Reply
Posts: 2
Joined: Thu Aug 22, 2019 2:22 pm

Recreating the Recruiting Activity Report (REST API)

Post by DanielRodriguez » Fri Aug 30, 2019 5:41 pm


Hello, good day everybody

Recently I struggled trying to replicate the information for the Recruiting Activity Report, and had a lot of doubts and questions. We had great support from the Bullhorn team that helped us to get the information, and I wanted to share a summary of the process, as well as the queries that may help you to get this. Note that I've noticed that the configuration of the queries may change depending on your workflow, but I think that this can be a helpful guide trying to understand the nature of the report.

First of all, looking at the Canvas of the report is pretty helpful. When you open the canvas inside the bullhorn app, and click on any of the columns, you can view the kind of query that you are going to be needing to get the exact same information. The canvas doesn't tell you exactly how to write the queries, but it helps greatly on understanding which entities you need to use.


For this, we used the next:

- Private Server
- Postman to test queries


You can perform a query to get all the recruiters that you want to be included in the report, or you can define them as you wish. I decided to get a list of users, and keep them in an array, but you can do it as you wish.

*IMPORTANT*When you query a CorporateUser, you may see a TimeZone field. Try to save this into the array for each recruiter, since this may change the results in the queries. Our recruiters are in the Mountain Time Zone, and adding -6 it's what worked the best for us.

Then, with an array of Corporate users like this:

Code: Select all

$recruiters = array( id_recruiter => array(name_recruiter, timeoff), id_recruiter => array(name_recruiter, timeoff) );

I looped with a foreach using key array:

foreach($recruiters as $recruiter=>$info){



You can start to run your queries


I used CURL with the following queries, and parsed the respones like this:

Code: Select all

$ch =                                  curl_init($URL); //URL with the query
curl_setopt                         ($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt                         ($ch, CURLOPT_MAXREDIRS, 0);
curl_setopt                         ($ch, CURLOPT_RETURNTRANSFER, true);
$response =                         curl_exec($ch); //This is an array with the information
$response =                         json_decode($response, true);
$array_of_results =              $response["data"];
Before including this into your php code, you can test the urls on postman. This saves a lot of time trying to debug the info. you get.

Adding the &showTotalMatched=true string to your query can save you a lot of time too, since this is an integer total of the records found.

The variables included are:

Code: Select all

$recruiter //an id of the recruiter
$from_date //the start date I want to search from
$to_date //the end date I want to search from
$recruiter_offsetTime //defined by the timezone of the recruiter
$BHRestToken //Token that you get after creating a connection to the API
You can define the from and to dates however you want. We've been thinking on adding a form in a website where the user can select distinct ranges of dates.

Pre Screens

Code: Select all

*Note* The bullhorn official guide says that you should include also the "Screened" action. This was not useful for my organization, but may be for yours


Code: Select all

Client Submissions

Code: Select all


Client Interviews

This query is the one that caused us the most of troubles, since we couldn't match the quantity in the report with the API for one of the recruiters, while the others were correct. This happened because the recruiter was creating the interviews as private.

Code: Select all

Offers Extended

We also had a discrepancy by one. One of the candidates had two offers for the same jobOrder. I created a loop for each of the results of this query, concatenated the name of the candidate with the name of the job, and deleted any duplicates. This is the way the canvas deletes duplicates, and you can view this inside the app.

Code: Select all


Code to avoid counting duplicates

Code: Select all

$ofertas = array(); //Create an array to store unique values
foreach($offers as $offer){ //Loop trough the array of results
            $candidato =                        $offer['jobSubmission']['candidate']; //The candidate you get in the response
            $nombre =                           $candidato['firstName']." ".$candidato['lastName']." ".$offer['jobSubmission']['jobOrder']['title']; //Concatenate the name of the candidate and jobOffer to create unique records
            if(!in_array($nombre, $ofertas)){ //If the concatenated name is not in the unique values' array
                array_push($ofertas, $nombre); //Push it into the array
                $job_offers++; //Add +1 to the recruiters offers

Code: Select all


Code: Select all

As you can see, this is basically the same query used for hires, but it includes the status 'Approved' and instead of searching for dateAdded, this searches by dateBegin.

Useful tools

- Go and google an URL decoder. Paste one of these queries I posted here, and these will be converted without all the weird characters.
- Also, find an epoch converter. Some dates are given in integers, and you can convert them to dates with one of them.
- Use postman!

I just finished with this some hours ago after some weeks, and I'm sure that you can find ways to make this easier and faster. This is just to give you all (and myself in the future) a guideline on how to replicate the information. I hope you can find a use on this :D

Thank you!

Special thanks to the BH help department!
Last edited by DanielRodriguez on Wed Sep 04, 2019 2:31 pm, edited 1 time in total.

Posts: 3
Joined: Fri Aug 30, 2019 9:58 am

Re: Recreating the Recruiting Activity Report (REST API)

Post by danmorris » Tue Sep 03, 2019 6:29 am

Hi DanielRodriguez,

Thanks for creating and posting this here, I'm sure many others will find this very useful!

Post Reply