Bob ATS flow

Overview

The bob ATS flow allows external ATS to push new hire information to bob so that newly hired candidates can be imported as employees into bob.

The steps of the flow are as follows:

  1. The bob integration administrator configures the ATS integration
  2. A new hire is performed in the ATS
  3. The ATS performs a callback to bob to notify the details of the new hire
  4. bob processes the new hire information and notifies the recipients of the ATS flow about the new hire
  5. The bob employees responsible with new hires click the new hire notification, which opens up the bob employee New Hire Wizard. The New Hire Wizard is already filled in with the information from the new hire callback. If needed, additional information is filled in and the employee is created.

New hire notifications

After a new hire callback event is processed, bob will send both email and in-app notifications. The recipients of the notifications can be configured in bob Settings > Integrations > Recruitment Integration in the Who Should be Notified? section.

Below is a sample email notification for a new hire:

And here is an in-app notification for a new hire:

New Hire Wizard

After the user clicks the new hire notification, the bob New Hire Wizard will be opened:

The new employee information received from the new hire callback event will be automatically filled in the new hire form.

Develop a HireAPI webhook

Webhook URL & Secret

Before you start, please contact bob support to set up a new HireAPI integration. You will receive a callback URL and a secret that will be needed in the following sections.
As an example:

Authentication

All API calls made to bob's webhook URL need to be authenticated. For this, we expect a HMAC-SHA256  signature in the X-Bob-HireAPI-Signature  header. More details can be found in the How to compute signature section below.

Replay attack protection

Within the X-Bob-HireAPI-Timestamp  header, each request must contain an epoch value (in seconds) that is no older than 5 minutes from the current time. 

How to compute signature

Each request made to the webhook endpoint must be authenticated using a HMAC-SHA256  signature. The signature is computed as follows:

message = epochValue + requestBody
signature = HAMC-SHA256(message, SecretKey)

Note: There is no character between the epochValue  and the requestBody . The above +  sign represents concatenation.

In the above signature,

  • epochValue  is the value received in X-Bob-HireAPI-Timestamp  header
  • requestBody  is the request body that will be sent to bob
  • SecretKey  is the secret obtained when setting-up the HireAPI integration

See the example below:

You can use https://codebeautify.org/hmac-generator for debugging signature-related problems.

Request JSON

The payload you send to bob should comply with the following JSON structure:

{
  "email": "joe.doe@sample.com",
  "firstName": "Joe",
  "lastName": "Doe",
  "recruiterEmails": [
    "recruiter1@sample.com",
    "recruiter2@sample.com"
  ],
  "work": {
    "title": "Account Manager",
    "department": "Distribution",
    "site": "Cluj-Napoca",
    "reportsTo": "finley.day_39028@samplebob.com",
    "startDate": "2019-10-21"
  },
  "financial": {
    "employmentContract": "Full Time",
    "employmentType": "Permanent",
    "payPeriod": "Annual",
    "salary": 12500.5,
    "salaryCurrency": "USD"
  },
  "about": {
    "privatePhone": "021343536",
    "mobilePhone": "021444555",
    "linkedinProfile": "http://linkedin.com/in/joe-doe",
    "facebookProfile": "http://facebook.com/joedoe2",
    "twitterProfile": "http://twitter.com/jd2"
  },
  "documents": [
    {
      "name": "CV.pdf",
      "url": "https://www.bellevue.edu/student-support/career-services/pdfs/resume-samples.pdf"
    },
    {
      "name": "cover_letter.pdf",
      "url": "http://skcnedu.in/uploads/files/document43.pdf"
    }
  ],
  "customFields": [
    {
      "id": "text_field_1",
      "displayName": "moto",
      "fieldType": "text",
      "value": "Blue, Yellow and Red"
    },
    {
      "id": "number_field_1",
      "displayName": "Favorite Number",
      "fieldType": "number",
      "value": 123.56
    },
    {
      "id": "currency_field_1",
      "displayName": "poker - best win",
      "fieldType": "currency",
      "value": {
        "value": 12.33,
        "currency": "USD"
      }
    },
    {
      "id": "date_field_1",
      "displayName": "Birthday",
      "fieldType": "date",
      "value": "2019-11-15"
    },
    {
      "id": "timestamp_field_1",
      "displayName": "Favorite Moment",
      "fieldType": "timestamp",
      "value": "2019-10-15T22:49:14Z"
    },
    {
      "id": "boolean_field_1",
      "displayName": "Boolean Field",
      "fieldType": "boolean",
      "value": true
    },
    {
      "id": "multi_list_field_1",
      "displayName": "Favorite Sports",
      "fieldType": "multilist",
      "values": [
        "Football",
        "Handball",
        "value3"
      ]
    },
    {
      "id": "table_type_list_field_1",
      "displayName": "Table Type Field",
      "fieldType": "tableType",
      "values": [
        [
          {
            "id": "c11",
            "displayName": "C 11",
            "fieldType": "text",
            "value": "1"
          },
          {
            "id": "c12",
            "displayName": "C 12",
            "fieldType": "text",
            "value": "2"
          }
        ],
        [
          {
            "id": "c21",
            "displayName": "C 21",
            "fieldType": "text",
            "value": "3"
          },
          {
            "id": "c22",
            "displayName": "C 22",
            "fieldType": "text",
            "value": "4"
          }
        ]
      ]
    }
  ]


Request Fields

Note: none of the JSON fields are mandatory, so it’s up to the integration developer to decide which information to send into bob. For best results, we recommend providing values for as many fields as you can.

Custom Fields

Custom fields are fields that are not known at development time. There are two benefits to adding custom fields:

  1. If a custom field has the same exact display name as an existing bob field, the two fields will be mapped automatically and the value will be populated in the bob new hire wizard.
  2. Through manual mapping, these custom fields can be mapped to the desired bob field. Please contact bob support if manual mapping is required.

Field types

Webhook status codes

If a request is successful, then the bob webhook will reply with a status code of 200.

In case of error, Bob will return an appropriate error response like:

{
  "message": "The requested resource could not be found!",
  "error": "The requested resource could not be found!"
}

and one of the following status codes:

400  - if the request is missing any of the required headers.
Solution
:
provide the X-Bob-HireAPI-Signature  and X-Bob-HireAPI-Timestamp  headers

401  - if the difference between the current time and supplied epoch value is greater than 5 minutes, or if the signature provided doesn’t match the computed one.
Solution
:
provide correct values for epoch and signature

404  - if the token parameter value from the webhook URL can’t be found in bob.
Solution
:
make sure the webhook URL is correct

Example

You can see below an example of a valid request made using cURL:

curl -X POST \

  'https://app.hibob.com/api/provisioning/api/integrations/ats/hire?token=70512D2AFAB9C0F4A46111459847269E28E1FEE0' \

  -H 'Content-Length: 3654' \
  -H 'Content-Type: application/json' \
  -H 'X-Bob-HireAPI-Signature: 3ab5b0fedbc7cd18ce20d0d3408cc1f2582ec0df264da5bcf63bba36d3ee88fe' \
  -H 'X-Bob-HireAPI-Timestamp: 1576763272' \

  -d '{
  "email": "joe.doe@sample.com",
  "firstName": "Joe",
  "lastName": "Doe",
  "recruiterEmails": [
    "recruiter1@sample.com",
    "recruiter2@sample.com"
  ],
  "work": {
    "title": "Account Manager",
    "department": "Distribution",
    "site": "Cluj-Napoca",
    "reportsTo": "finley.day_39028@samplebob.com",
    "startDate": "2019-10-21"
  },
  "financial": {
    "employmentContract": "Full Time",
    "employmentType": "Permanent",
    "payPeriod": "Annual",
    "salary": 12500.5,
    "salaryCurrency": "USD"
  },
  "about": {
    "privatePhone": "021343536",
    "mobilePhone": "021444555",
    "linkedinProfile": "http://linkedin.com/in/joe-doe",
    "facebookProfile": "http://facebook.com/joedoe2",
    "twitterProfile": "http://twitter.com/jd2"
  },
  "documents": [
    {
      "name": "CV.pdf",
      "url": "https://www.bellevue.edu/student-support/career-services/pdfs/resume-samples.pdf"
    },
    {
      "name": "cover_letter.pdf",
      "url": "http://skcnedu.in/uploads/files/document43.pdf"
    }
  ],
  "customFields": [
    {
      "id": "text_field_1",
      "displayName": "moto",
      "fieldType": "text",
      "value": "Blue, Yellow and Red"
    },
    {
      "id": "number_field_1",
      "displayName": "Favorite Number",
      "fieldType": "number",
      "value": 123.56
    },
    {
      "id": "currency_field_1",
      "displayName": "poker - best win",
      "fieldType": "currency",
      "value": {
        "value": 12.33,
        "currency": "USD"
      }
    },
    {
      "id": "date_field_1",
      "displayName": "Birthday",
      "fieldType": "date",
      "value": "2019-11-15"
    },
    {
      "id": "timestamp_field_1",
      "displayName": "Favorite Moment",
      "fieldType": "timestamp",
      "value": "2019-10-15T22:49:14Z"
    },
    {
      "id": "boolean_field_1",
      "displayName": "Boolean Field",
      "fieldType": "boolean",
      "value": true
    },
    {
      "id": "multi_list_field_1",
      "displayName": "Favorite Sports",
      "fieldType": "multilist",
      "values": [
        "Football",
        "Handball",
        "value3"
      ]
    },
    {
      "id": "table_type_list_field_1",
      "displayName": "Table Type Field",
      "fieldType": "tableType",
      "values": [
        [
          {
            "id": "c11",
            "displayName": "C 11",
            "fieldType": "text",
            "value": "1"
          },
          {
            "id": "c12",
            "displayName": "C 12",
            "fieldType": "text",
            "value": "2"
          }
        ],
        [
          {
            "id": "c21",
            "displayName": "C 21",
            "fieldType": "text",
            "value": "3"
          },
          {
            "id": "c22",
            "displayName": "C 22",
            "fieldType": "text",
            "value": "4"
          }
        ]
      ]
    }
  ]
}
'

Did this answer your question?