Data Hub Custom Schemas
Overview
Data Hub is designed to store data from across your Bullhorn platform in one place, unlocking powerful new opportunities for reporting and analytics. Oftentimes, this data originates from non-Bullhorn applications that complement your recruitment workflow.
Read this article to find step-by-step guidance on how to create data definitions that enable you to send data from these external applications into the Data Hub for use in analytics and reporting.
Part 1: Getting Started
The Basics
The Data Hub uses JSON schemas to define its data structures. JSON is an industry standard that enables easy interoperability at scale.
This document assumes familiarity with JSON schemas. If this concept is new to you, please reach out to Bullhorn Professional Services for additional assistance.
Before you start building your first Data Hub schema, you'll need to gather some information.
First, define what entities and properties you want to store in the Data Hub.
Let's say we wanted to capture and analyze survey response data that was sent from an external application. Let's call this collection of data Survey. We would define a model for sending and storing this data into something that is roughly equivalent to a database table.
Other examples of data that could be stored in Data Hub might be "Referrals", "Timesheets", or a collection of financial data. Each of these would be defined with their own unique model or schema. The properties of each are roughly like columns in a table or a spreadsheet.
Moving forward, we'll refer to your collection of data as an "entity".
Data Types
Each field or property within your entity has a defined type. The following are the core data types supported within the Data Hub:
- string
- integer
- number (aka decimal)
- Boolean
Extra formats supported for string data type:
- date-time
- uuid
We will be defining a data type for each property within our entities to match one from the list above.
Navigate to Custom Attributes on Data Hub Schema Definitions for additional custom attributes.
Property Relationships
Each entity should have a relationship to one or more Bullhorn Entities. Examples of relationships that your entity may be related to include:
- candidateId
- clientCorporationId
- clientContactId
- jobOrderId
- corporateUserId
- leadId
- opportunityId
- placementId
- appointmentId
- noteId
- payableChargeId
- billableChargeId
Now that we understand the basics, let’s fill out the worksheet below with the properties of your first entity.
Defining your First Data Hub Custom Entity
Bullhorn strongly recommends you start with one simple entity from an external application with a few simple properties so you can become familiar with the entire process end to end. Once you’ve run an initial successful test, proceed with augmenting your schemas with more advanced configurations.
Custom Entity Basic Properties
Your Entity Name (no spaces): ____________________
Related to Bullhorn Entity: ____________________
Table 1: Your Custom Entity
FieldName | User Friendly Label | FieldType |
---|---|---|
Sample: surveyName | Sample: Survey Name | String |
Sample: surveyName | Sample: Survey Name | String |
Sample: surveyName | Sample: Survey Name | String |
Sample Record (for testing)
Next, let’s define a sample record that will enable you to validate that the schema definition is correct. A sample record would simply represent the payload of your data with all fields and relationships.
For example, a sample record for our Survey entity might look like the example below. In this example, we are saying that we are creating a sample survey that includes:
- A survey id of “123” (this value should represent the unique identifier from the source system that the data originated from)
- A survey name of “Feedback on assignment”
- A survey record is linked to a job that has an id of “4569900” and a candidate that has an ID of “7659900” in the ATS
- Other properties for illustration
Sample 1 (the Payload portion):
{
"sourceId": 123,
"name": "Feedback on Assignment",
"url": "https://bullhorn.com.test/mysurvey"
"customerId": 4,
"candidateID": 7659900,
"bullhornJobID": 4569900
}
Sample 1 (as part of full API body):
In the above example, you’ll notice that the Payload was structured with backslashes to escape the double quotes so that it interprets the JSON entity within the JSON body of the API call correctly.
Additionally, notice the square brackets around both the entire body and items portion of the body - this is because each API call can contain a batch of records of different entity types so each sourceSystem and entity type can each contain a batch of items.
[{
"sourceSystem": "HelloWorld",
"entityType": "MyCustomObject",
"schemaVersion": "1",
"items": [{
"sourceId": 123,
"dateAddedInSourceSystem": "2023-11-27T15:05:57.7369920Z",
"dateLastModifiedInSourceSystem": "2024-06-28T22:01:00.8857286Z",
"isDeleted": false,
"candidateId": 7659900,
"jobOrderId": 4569900
“Payload”: “{\"name\": \"Feedback on Assignment\",
\"url\": \"https://bullhorn.com.test/mysurvey\",
\"customerId\": 4,
\"candidateID\": 7659900,
\"bullhornJobID\": 4569900}”
}]
}]
Enter a sample record for your entity in the table below, with one property for each of the rows you defined in your custom entity table above. You will use it later for testing that your schema is valid.
MySampleRecord:
{
}
You are now ready to build your custom schema.
Building your Custom Schema
Each of the fields defined in Table 1 should also be added to the schema definition. For example, for our sample entity of “Survey”, a starter schema would look like this:
Be careful to validate all open/close brackets and quotes.
Sample Schema 1a: Survey - part 1
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"sourceIdType": "integer",
"properties": {
"Id": {
"type": "integer",
"label": "Id"
},
"Url": {
"type": "string",
"label": "URL"
},
"Name": {
"type": "string",
"label": "Survey Name"
},
"CustomerId": {
"type": "integer",
"label": "Customer Id"
},
"DateCreated": {
"type": "string",
"format": "date-time"
}
}
}
Next, augment your schema by adding links to one or more Bullhorn entities as shown below. In this case, our record is associated with the Jobs entity in Bullhorn.
You can include the data under BullhornJobId
for the ATS record linking in the payload, but the best practice is to include it outside of the payload itself. But if you define the schema with it as a property and include the promoteTo
value correctly, it will also successfully reference the ATS entity.
Schema 1b
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"sourceIdType": "integer",
"properties": {
"Id": {
"type": "integer",
"label": "Id"
},
"Url": {
"type": "string",
"label": "URL"
},
"Name": {
"type": "string",
"label": "Survey Name"
},
"CustomerId": {
"type": "integer",
"label": "Customer Id"
},
"DateCreated": {
"type": "string",
"format": "date-time"
},
"BullhornJobId": {
"type": "integer",
"promoteTo": "jobOrderId",
"link": {
"type": "ATS",
"entity": "JobOrder"
}
}
}
}
Perform the same steps for the properties from your custom entity table. Enter your custom schema below, using the data from Table 1. Ensure to include a relationship to one or more Bullhorn entities.
MyFirstSchema:
{
}
You're now ready to run some tests.
Creating Records in the Data Hub with Your Custom Schema
Register your Schema in the Data Hub
The schema definition should be documented so you can refer to it internally (like a specification document). Before you send data to Data Hub via the API, the schema definition must be registered and set up with Bullhorn. This process is initiated through a support ticket (refer to Step 7 in Adding External Data to the Data Hub). Bullhorn's support team will then set up the schema definitions that you have provided. Once completed, they will inform you that you can begin pushing data into the Data Hub.
Bullhorn's support team performs a basic validation of the schema to confirm that it’s valid JSON, but they are not responsible for understanding the specific data you are sending nor for validating that it is the “right” data for the metrics you are interested in receiving.
Create your First Record
Bullhorn recommends using Postman or an equivalent tool to interact with the Data Hub API using the Data Hub API Integration Reference Guide. The payload for your request should match your sample record “MySampleRecord” above.
Part 2: Advanced Use Cases
If one custom entity should reference another Data Hub entity, you can add metadata that defines where the linked record is stored. Supported link types are:
- DATA_HUB for self-referential data. The metadata defines the sourceSystemName and entityTypeName they link to.
- ATS for standard entities in the ATS. The metadata defines the ATS entity they link to e.g. JobOrder or Candidate.
- EXTERNAL for links to external systems like Pardot, Sendgrid. The metadata defines a URL template string to be populated with the row ID.
Examples of linked records include:
SurveyQuestion
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"sourceIdType": "integer",
"properties": {
"Text": {
"type": "string",
"label": "Text"
},
"Scale": {
"type": "string",
"isType": true,
"label": "Scale"
},
"DisplayOption": {
"type": "string",
"isType": true,
"label": "Display Option"
},
"Survey_Id": {
"type": "integer",
"link": {
"type": "DATA_HUB",
"sourceSystem": "Automation",
"entityType": "Survey"
}
},
"Id": {
"type": "integer",
"deprecated": true
}
}
}
Additional Examples of Custom Schemas/Records for Reference
- Defines
status
asisType
for fast filtering in Analytics. This is acceptable becausestatus
will not have a large number of unique values. - Uses the
format
ofdate-time
for thepaid_on
field to indicate it should be treated as a date field instead of a normal string. - Defines
retainer_fee
as a monetary field withisMonetary
and an explicit currency field ofretainer_currency
. - Defines
extras_fee
andtotal_fee
as monetary fields without explicit currency fields, they will fallback tocurrency
because it’s marked withisDefaultCurrency
. - Links to the candidate entity in ATS with
candidateId
. - Links to a user entity in ATS with
userId
and has it marked withisOwner
so that Analytics sees this as the overall. - Links to another Data Hub entity with
automationSurveyId
, an Automation Survey Submittal.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"sourceIdType": "uuid",
"properties": {
"status": {
"type": "string",
"isType": true,
"label": "Status"
},
"paid_on": {
"type": "string",
"format": "date-time",
"label": "Paid On"
},
"retainer_fee": {
"type": "number",
"isMonetary": true,
"currencyField": "retainer_currency",
"label": "Retainer Fee"
},
"retainer_currency": {
"type": "string",
"isCurrencyField": true,
"label": "Retainer Currency"
},
"extras_fee": {
"type": "number",
"isMonetary": true,
"label": "Extras Fee"
},
"total_fee": {
"type": "number",
"isMonetary": true,
"label": "Total Fee"
},
"currency": {
"type": "string",
"isCurrencyField": true,
"isDefaultCurrency": true,
"label": "Currency"
},
"candidateId": {
"type": "integer",
"label": "Candidate",
"promoteTo": "candidateId",
"link": {
"type": "ATS",
"entity": "Candidate"
}
},
"userId": {
"type": "integer",
"isOwner": true,
"label": "Owner",
"promoteTo": "corporateUserId",
"link": {
"type": "ATS",
"entity": "CorporateUser"
}
},
"automationSurveyId": {
"type": "integer",
"label": "Automation Survey",
"link": {
"type": "DATA_HUB",
"sourceSystem": "Automation",
"entityType": "SurveySubmittal"
}
}
}
}
For ATS Link Types, navigate to Bullhorn REST API Entity Names to see what allowable values are included:
REST Entity Name | Reference Column (ID) |
---|---|
Candidate | candidateID |
Client Corporation | clientCorporationId |
Client Contact | clientContactId |
Job Order | jobOrderId |
CorporateUser | corporateUserId |
Lead | leadId |
Opportunity | opportunityId |
Placement | placementId |
Appointment | appointmentId |
Note |
noteId |
Payable Charge |
payableChargeId |
Billable Charge |
billableChargeID |