Frequently Asked Questions (FAQ)

Have a question about Bullhorn's HTTP based APIs? You've found the right place.

API Update [posted on December 13, 2012]:

This version of the Bullhorn APIs should no longer be used.

All new work should be done using Bullhorn's REST or Web Services APIs. For more information please visit:

Bullhorn REST API provides a simpler and faster way for developers to build applications that interact with the Bullhorn platform and is used by Bullhorn Inc. to develop features of the Bullhorn ATS/CRM application.

Of the BullhornSTAFFING HTTP API interfaces listed below, our analysis shows that the following are most commonly used by developers:

Resume Parsing API
Published Job Data (XML)
The interface to these will continue to work as is because Bullhorn will replace the back end to use REST API. The URLs for these 2 specific APIs may change in the 2nd half of 2013; developers may require to update their applications to use the new URLs.

Moderators: StaffingSupport, s.emmons

Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Frequently Asked Questions (FAQ)

Post by cseibert » Mon Apr 16, 2007 11:04 am

What is the Bullhorn API?

The Bullhorn API allows our clients complete flexibility when integrating your corporate websites with Bullhorn. It allows you to keep the look and feel of your existing website.
You own the code, and the code resides on your servers. It will be up to you to maintain any changes or updating of the code.

With an experienced web developer, you should not need much assistance from Bullhorn to build your own web integration. You build the pages and you own them. You can retrieve, insert and update almost all relevant data in Bullhorn, which allows the ability to build almost any functionality you are looking for.

There is no charge for use of the API tools since you will need a developer of your own to actually build the integration.

Is the Bullhorn API the right solution for me?

Implementing the Bullhorn API on your website requires that you have web developers in house that are proficient in some dynamic web language (PHP, ColdFusion, JSP, ASP, ASP.NET), AND who have experience making HTTP GETs and POSTs from their code AND who have experience generating and parsing XML.

Alternatively, you can pay a third party vendor to implement the API for you.

Depending on where you fall in this spectrum, the Bullhorn API may not be a good solution for you. Be advised that there is a fully developed, supported and FREE feature called "Career Portal" that will meet many client's needs.

For for information on the Bullhorn Career Portal, see:

What is some of the terminology used to talk about the Bullhorn API?
  • API - Application Programming Interface
    XML -Extensible Markup Language – Widely used format for transmitting data over the web.
    API Encryption Key - Randomly generated “password” created by Bullhorn. Needed for extracting data out of their instance.
    HRXML -Staffing Industry Standard XML data format
What is the general process for using the Bullhorn API?

The developer will write code that passes a private label ID that will provide to you. The common component to all the API tools is the use of Form Posts. The clients’ web pages post parameters and filters to certain Bullhorn URL’s, depending on what API tool they are using, to pass and receive data. The Bullhorn URLs either add new records, update existing records or return data for the page to use and display to the user.

How can I get updates on what code changes are happening in Bullhorn, including the API?

Please subscribe to our product mangement RSS feed at

Where can I see a list of all the Bullhorn APIs?

Are there third party vendors that can help us implement the API?
See the seperate "Third Party Vendors" post.

How do I get started with the API?

1. Contact Bullhorn Support at to get your private label ID and API encryption key.

2. Go to the following URL:

3. Look at code examples in this FAQ.
Last edited by cseibert on Thu Aug 30, 2007 9:56 am, edited 2 times in total.

Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Apr 16, 2007 6:09 pm

Do you offer code samples for calling the Bullhorn API?

In general, we don't offer code samples of specific APIs. There are two particular APIs that generate HTML (the Candidate and Contact Capture APIs). For these, you can use the generated HTML as-is, or change it to suit your purpose formatting wise.

Depending on what you're doing, it's likely that the other APIs wil require a server-side scripting language, such as PHP, ColdFusion, ASP, JSP, etc.

See bellow for basic examples of each.
Last edited by cseibert on Wed Apr 18, 2007 11:29 am, edited 1 time in total.

Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Wed Apr 18, 2007 10:46 am

How do you perform basic HTTP requests in various languages?


Code: Select all

<CFHTTP method="POST" url="">
   <CFHTTPPARAM type="Formfield" name="privateLabelID" value="1234">
   <CFHTTPPARAM type="Formfield" name="encryptedAPIKey" value="%A%B%C%D%E%F%G">
   <CFHTTPPARAM type="Formfield" name="userID" value="5678">

<CFDUMP var="#cfhttp#">

PHP (using libcurl)

Code: Select all

$postfields = array();
$postfields['privateLabelID'] = urlencode('1234');
$postfields['encryptedAPIKey'] = urlencode('%A%B%C%D%E%F%G');
$postfields['userID'] = urlencode('5678');

$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_URL, '');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);


Note: There is an issue when uploading a resume via the PHP CURL module. The content sub type on the file is not set properly to "msword" or another token which the resume parser can identify as a parsable file.

This only effects the AttachFileAPI.cfm API, when using the updateResumeOverview parameter. The resume parsing API is unaffected.

Java (and JSP)

Code: Select all

	HttpConnection conn = null;

               String encodedData = URLEncoder.encode(\"privateLabelID\", \"UTF-8\") + \"=\" + URLEncoder.encode(\"1234\", \"UTF-8\"); 
               encodedData += \"&\" + URLEncoder.encode(\"encryptedAPIKey\", \"UTF-8\") + \"=\" + URLEncoder.encode(\"%A%B%C%D%E%F%\", \"UTF-8\") ;
                encodedData +=  \"&\" + URLEncoder.encode(\"userID\", \"UTF-8\") + \"=\" + URLEncoder.encode(\"5678\", \"UTF-8\") ;

	try {
		conn = (HttpConnection)"");
		conn.setRequestProperty("User-Agent", "Mozilla/4.0");
		conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		conn.setRequestProperty("Content-Length", encodedData.length());

		OutputStream os = conn.openOutputStream();
    		int rc = conn.getResponseCode();

		... // process it

	catch( IOException e ){

		// handle the error here

C# (aka ASP.NET, can be converted to VB.NET)

Code: Select all

HttpWebResponse resp = null;	
HttpWebRequest  request = (HttpWebRequest) WebRequest.Create("");

//url encode the encryped api key            
String encryptedapiKey = HttpUtility.UrlEncode("%A%B%C%D%E%F%G%");

byte[] postDataBytes = Encoding.UTF8.GetBytes("privateLabelID=1234&encryptedAPIKey=" + encryptedapiKey);

request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postDataBytes.Length;

Stream requestStream = request.GetRequestStream();
requestStream.Write(postDataBytes, 0 ,postDataBytes.Length);


resp = (HttpWebResponse) request.GetResponse();
StreamReader responseReader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8);



Code: Select all

var parameters = 'privateLabelID=' + encodeURIComponent('1234') 
    + '&encryptedAPIKey=' + encodeURIComponent('%A%B%C%D%E%F%G')
    + '&userID=' + encodeURIComponent('5678');

var ajaxObj = new ActiveXObject("Microsoft.XMLHTTP");"POST", "", true);

ajaxObj.onreadystatechange = function() { 

   if (ajaxObj.readyState == 4
      && ajaxObj.status != 200) {


ajaxObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
ajaxObj.setRequestHeader("Content-length", parameters.length);
ajaxObj.setRequestHeader("Connection", "close");


Code: Select all

use HTTP::Request::Common qw(POST);
use LWP::UserAgent;

my $browser = LWP::UserAgent->new();

my $responde = HTTP::Request->new(POST => "");


Classic VB

This may not be possible without redirecting the actual user's browser. If you have an example, post it!

Code: Select all

    Dim strPostData As String
    Dim strHeader As String
    Dim varPostData As Variant
    'Make the Post Data String
	strPostData ="privateLabelID=1234&encryptedAPIKey=%A%B%C%D%E%F%G&userID=5678"
    'Pack the post data into a byte array
    BuildPostData bytpostdata(), strPostData
    'Write the byte into a variant
    varPostData = bytpostdata
    'Create the Header
    strHeader = "Content-Type: application/x-www-form-urlencoded" + Chr(10) + Chr(13)
    'Post the data
    Web.Navigate2 "", 0, "", varPostData, strHeader

Note: if you have a small example from a language we don't have, post it in a new thread and we'll add it!
Note: these examples are simply to get you started. Many were taken from web tutorials. The syntax may not be 100% correct.
Last edited by cseibert on Mon Aug 20, 2007 11:51 am, edited 3 times in total.

Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Apr 30, 2007 4:39 pm

From Jessica, an example of how to download a file from the API in ASP:

Code: Select all

   Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP") "GET", strFileURL, false
    If objXMLHTTP.Status = 200 Then
      Set objADOStream = CreateObject("ADODB.Stream")
      objADOStream.Type = 1 'adTypeBinary
      objADOStream.Write objXMLHTTP.ResponseBody
      objADOStream.Position = 0    'Set the stream position to the start
      Set objFSO = Createobject("Scripting.FileSystemObject")
        If objFSO.Fileexists(strHDLocation) Then objFSO.DeleteFile strHDLocation
      Set objFSO = Nothing
      objADOStream.SaveToFile strHDLocation
      Set objADOStream = Nothing
    End if
    Set objXMLHTTP = Nothing

Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Thu May 24, 2007 9:35 am

Added a new thread for the candidate capture and resume parsing APIs.

Bullhorn Employee
Posts: 392
Joined: Wed Dec 31, 1969 8:00 pm

Post by cseibert » Mon Jul 09, 2007 3:04 pm

File Upload from C#:

Taken from


Code: Select all

CookieContainer cookies = new CookieContainer();
//add or use cookies
NameValueCollection querystring = new NameValueCollection();
string uploadfile;// set to file to upload
uploadfile = "c:\\test.jpg";

//everything except upload file and url can be left blank if needed
string outdata = UploadFileEx(uploadfile, 
     "http://localhost/test.php","uploadfile", "image/pjpeg", 

Code: Select all

public static string UploadFileEx( string uploadfile, string url, 
    string fileFormName, string contenttype,NameValueCollection querystring, 
    CookieContainer cookies)
    if( (fileFormName== null) ||
        (fileFormName.Length ==0))
        fileFormName = "file";

    if( (contenttype== null) ||
        (contenttype.Length ==0))
        contenttype = "application/octet-stream";

    string postdata;
    postdata = "?";
    if (querystring!=null)
        foreach(string key in querystring.Keys)
            postdata+= key +"=" + querystring.Get(key)+"&";
    Uri uri = new Uri(url+postdata);

    string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
    HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
    webrequest.CookieContainer = cookies;
    webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
    webrequest.Method = "POST";

    // Build up the post message header
    StringBuilder sb = new StringBuilder();
    sb.Append("Content-Disposition: form-data; name=\"");
    sb.Append("\"; filename=\"");
    sb.Append("Content-Type: ");

    string postHeader = sb.ToString();
    byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

    // Build the trailing boundary string as a byte array
    // ensuring the boundary appears on a line by itself
    byte[] boundaryBytes = 
           Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

    FileStream fileStream = new FileStream(uploadfile, 
                                FileMode.Open, FileAccess.Read);
    long length = postHeaderBytes.Length + fileStream.Length + 
    webrequest.ContentLength = length;

    Stream requestStream = webrequest.GetRequestStream();

    // Write out our post header
    requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

    // Write out the file contents
    byte[] buffer = new Byte[checked((uint)Math.Min(4096, 
    int bytesRead = 0;
    while ( (bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0 )
        requestStream.Write(buffer, 0, bytesRead);

    // Write out the trailing boundary
    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
    WebResponse responce = webrequest.GetResponse();
    Stream s = responce.GetResponseStream();
    StreamReader sr = new StreamReader(s);

    return sr.ReadToEnd();