Summary

Bullhorn Data Hub is a flexible data structure to store data for reporting and analytics across Bullhorn, marketplace partners, and external sources.

Prerequisites

All Data Hub API calls must be made with a valid BH REST Token (either via OAuth client API authentication or within a valid Bullhorn REST API Session within the ATS application).

Schema definition and setup must be enabled for the Bullhorn corporation that is sending data (whether data is sent via client or directly from a custom application owned by the client).

API Endpoints

Type Endpoint Inputs (request body or url params) Description
POST data-hub/data Request Body:
- sourceSystem
- entityType
- schemaVersion
- Items (Up to 100 items allowed in payload)
Upserts data to datahub. Payload must be formatted according to schema definition setup for that corp.
POST data-hub/data/find Request Body:
- sourceId
- entityType.name or entityType.id
Must be built using Adaptive Query format, see example
Find is used to query data for viewing with adaptive query constraints.

Using Data Hub

Endpoint

Type: POST

  • {rest-url}/data-hub/data

Example Request Body:

[
    {
        "sourceSystem": "sourceSystemName",
        "entityType": "entityTypeName",
        "schemaVersion": "schemaVersionName",
        "items": [
            {
                "sourceId": 1,
                "dateAddedInSourceSystem": "2024-11-31T17:48:17.182+00:00",
                "dateLastModifiedInSourceSystem": "2024-11-31T17:48:17.182+00:00",
                "payload": "{ \"name\": \"bob\", \"age\": 25, \"address\": { \"street\": \"789 Main St\", \"city\": \"New York\", \"state\": \"NY\", \"postalCode\": \"10001\" }, \"hobbies\": [\"reading\", \"running\"] }",
                "isDeleted": false,
                "placementId": 107,
                "candidateId": 123,
                "clientContactId": 55,
                "clientCorporationId": 55,
                "jobOrderId": 123,
                "jobSubmissionId": 123,
                "leadId": 123,
                "opportunityId": 465,
                "corporateUserId": 123,
                "noteId": 123,
                "appointmentId": 123,
                "payableChargeId": 123,
                "billableChargeId": 134
                // up to 100 items
            }
        ]
    }
]

Example 200 Response:

{
    "statusCode": 200,
    "messages": [],
    "data": [
        {
            "entityType": "entityTypeName",
            "sourceSystem": "sourceSystemName",
            "totalSuccessfulItems": 1,
            "successfulItems": [
                {
                    "sourceId": "1",
                    "dataId": 1234
                }
            ]
        }
    ]
}


Endpoint

Type: POST

  • {rest-url}/data-hub/data/find

Example Request Body:

{
    "criteria": {
        "and": [
            {
                "entityType.name": {
                    "equalTo": "entityTypeName"
                }
            },
            {
                "sourceId": {
                   "in": ["2","7"] 
                }
            },
            {
                "entityType.sourceSystem.name": {
                    "equalTo": "sourceSystemName"
                }
                // add whatever other constraints you want
            }
        ]
    }
}

Example 200 Response:

{
    "statusCode": 200,
    "messages": null,
    "data": {
        "start": 0,
        "count": 1,
        "total": 1,
        "data": [
            {
                "dataId": 1234,
                "sourceId": "2",
                "entityType": {
                    "entityTypeId": 241,
                    "name": "sourceSystemName"
                },
                "entityTypeSchemaVersion": {
                    "entityTypeSchemaVersionId": 441,
                    "name": "schemaVersionName"
                },
                "dateAdded": "2025-01-10T22:56:18.012+00:00",
                "dateLastModified": "2025-01-10T22:56:18.012+00:00",
                "dateAddedInSourceSystem": "2024-12-01T17:48:17.000+00:00",
                "dateLastModifiedInSourceSystem": "2024-12-01T17:48:17.000+00:00",
                "payload": "{ \"name\": \"Update Again\", \"age\": 25, \"address\": { \"street\": \"789 Main St\", \"city\": \"New York\", \"state\": \"NY\", \"postalCode\": \"10001\" }, \"hobbies\": [\"reading\", \"running\"] }",
                "isDeleted": false,
                "candidateId": 123,
                "clientContactId": 10,
                "clientCorporationId": 1105,
                "jobOrderId": 123,
                "jobSubmissionId": 123,
                "placementId": 123,
                "leadId": 123,
                "opportunityId": 123,
                "corporateUserId": 123,
                "noteId": 123,
                "appointmentId": 123,
                "payableChargeId": 123,
                "billableChargeId": 134,
                "entityId": 1234
            }
        ]
    }
}

By following these steps, Data Hub can effectively be used, assuming the schema is already set up for the user’s corporation.

Data Hub Error Scenarios

Below are some examples of error scenarios that can occur when making the POST /data-hub/data request.

206 Status Code

The request has only partially succeeded. One or more of the records in the request failed to be stored in Data Hub.

Example 206 Response:

{
    "statusCode": 206,
    "messages": [
        "Some items were successfully processed, but there were also some errors persisting data.  One or more items were not processed due to an error, see ‘failedItems’ attribute for more details",
        "Total Item Failures: 2",
        "Failing Entity Types: [entityTypeName]"
    ],
    "data": [
        {
            "entityType": "entityTypeName",
            "sourceSystem": "sourceSystemName",
            "totalBatchFailures": 2,
            "totalSuccessfulItems": 1,
            "successfulItems": [
                {
                    "sourceId": "3",
                    "dataId": 5678
                }
            ],
            "failedItems": [
                {
                    "errorType": "SCHEMA_VALIDATION",
                    "errorMessage": "[$: required property 'name' not found]",
                    "failingSourceIds": [
                        "1"
                    ]
                },
                {
                    "errorType": "MISSING_REQUIRED_FIELD",
                    "errorMessage": "Missing payload",
                    "failingSourceIds": [
                        "2"
                    ]
                }
            ]
        }
    ]
}

400 Status Code

All records failed to be processed.

Example 400 Response:

{
    "statusCode": 400,
    "messages": [
        "There were errors persisting data.  One or more batches were not processed due to an error, see ‘failedItems’ attribute for more details",
        "Total Item Failures: 3",
        "Failing Entity Types: [entityTypeName]"
    ],
    "data": [
        {
            "entityType": "entityTypeName",
            "sourceSystem": "sourceSystemName",
            "totalBatchFailures": 3,
            "totalSuccessfulItems": 0,
            "successfulItems": [],
            "failedItems": [
                {
                    "errorType": "SCHEMA_VALIDATION",
                    "errorMessage": "[$: required property 'name' not found]",
                    "failingSourceIds": [
                        "1"
                    ]
                },
                {
                    "errorType": "MISSING_REQUIRED_FIELD",
                    "errorMessage": "Missing payload",
                    "failingSourceIds": [
                        "2"
                    ]
                },
                {
                    "errorType": "MISSING_REQUIRED_FIELD",
                    "errorMessage": "Missing dateAddedInSourceSystem",
                    "failingSourceIds": [
                        "3"
                    ]
                }
            ]
        }
    ]
}

413 Status Code

The request has more than 100 items and Data Hub will only process 100 records at a time.

Example 413 Response:

{
    "statusCode": 413,
    "messages": [
        "Please send 100 or less records per API call"
    ],
    "data": null
}