# Sync Applicant (ATS) to Employee Onboarding (HRIS)

This guide provides a step-by-step procedure for integrating an ATS with an HRIS to automate the transfer of applicant data as soon as an applicant is marked as hired to the employee onboarding system.

This is a common use case for ATS tools that integrate with HRIS platforms. For the purposes of this guide, we are using connectors available on our Unified APIs:

- [**Teamtailor**](https://developers.apideck.com/apis/ats/teamtailor) as ATS provider
- [**Humaans**](https://developers.apideck.com/apis/hris/humaans-io) as HRIS destination

**Trigger**: an applicant gets updated ⇒ the employee gets updated

See the full example on [GitHub](https://github.com/apideck-samples/ats-to-hris).

## Flow diagram

**Highlevel flow**

![High-level sequence diagram of Apideck syncing an applicant from an ATS connector to an HRIS connector](/guides/sync-applicant/mermaid.png)

**Detailed flow**

![Untitled](/guides/sync-applicant/Untitled.png)

## Scenario

1. Apideck monitors the ATS system for changes
2. Apideck detects an update for a candidate
3. Apideck broadcasts a [webhook event](https://developers.apideck.com/apis/ats/reference#operation/applicantUpdated) `ats.applicant.updated`
4. Client application receives webhook event `ats.applicant.updated`
5. Client requests “[applicant details](https://developers.apideck.com/apis/ats/reference#operation/applicantsOne)” via Unify API
6. Client transforms the applicant details into an employee model
7. Client executes a “update employee” request via Unify API

## Screenshots

**Teamtailer - Updated applicant**

[https://app.teamtailor.com/companies/YTf4HVdoBks/candidates/segment/all/candidate/31066324](https://app.teamtailor.com/companies/YTf4HVdoBks/candidates/segment/all/candidate/31066324)

![Untitled](/guides/sync-applicant/Untitled%201.png)

**Client** - handling the incoming applicant trigger and starting the update employee process based on a webhook.

![Untitled](/guides/sync-applicant/Untitled%202.png)

**Humaans - Updated employee**

[https://app.humaans.io/](https://app.humaans.io/)

![Untitled](/guides/sync-applicant/Untitled%203.png)

### Client POC Application

1. Create a new folder
2. Place the files below in the folder
3. Execute the command `npm install`, this will install all the dependencies
4. Configure the correct API key & other settings in the `.env` file
5. Execute the command `npm run start`, to start the client application, which will run on: 127.0.0.1:7777
6. Simulate the Webhook event using this CURL command or via Postman

```bash
curl --location --request POST '127.0.0.1:7777/start' \
--header 'Content-Type: application/json' \
--data-raw '{
  "payload": {
    "event_type": "ats.applicant.updated",
    "unified_api": "ats",
    "service_id": "teamtailor",
    "consumer_id": "test-consumer",
    "event_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "entity_id": "31066324",
    "entity_url": "https://unify.apideck.com/ats/applicants/31066324",
    "entity_type": "applicant",
    "occurred_at": "2023-09-22T00:00:00.000Z"
  }
}'
```

**Files**

_package.json_ file

```json
{
  "name": "app-ats-hris",
  "version": "1.0.0",
  "description": "Sample webhook listener for ATS to HRIS app",
  "scripts": {
    "start": "node app.mjs"
  },
  "dependencies": {
    "@apideck/unify": "latest",
    "concurrently": "^8.2.1",
    "dotenv": "^16.3.1",
    "express": "^4.18.1",
    "ngrok": "^5.0.0-beta.2"
  }
}
```

_.env_ file

```bash
APP_ID="<YOUR_APP_ID>"
API_KEY="<YOUR_API_KEY>"
CONSUMER_ID="test-consumer"
SERVICE_ID_ATS="teamtailor"
SERVICE_ID_HRIS="humaans-io"
```

_app.msj_ file

```jsx
import dotenv from 'dotenv'
import express from 'express'
import { Apideck } from '@apideck/unify'

dotenv.config()

// Initiate Unify SDK
const apideck = new Apideck({
  apiKey: process.env.API_KEY ?? '',
  appId: process.env.APP_ID ?? '',
  consumerId: process.env.CONSUMER_ID ?? ''
})

console.log('APP_ID: ' + process.env.APP_ID)
console.log('CONSUMER_ID: ' + process.env.CONSUMER_ID)
console.log('SERVICE_ID_ATS: ' + process.env.SERVICE_ID_ATS)
console.log('SERVICE_ID_HRIS: ' + process.env.SERVICE_ID_HRIS)

// Set listener
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
const port = process.env.port || 7777

//
const currentDate = new Date()
const year = currentDate.getFullYear()
const month = String(currentDate.getMonth() + 1).padStart(2, '0') // Months are 0-indexed
const day = String(currentDate.getDate()).padStart(2, '0')

const formattedDate = `${year}-${month}-${day}`

app.all('/*', async function (req, res) {
  // Initiate variables
  let employee = null

  // Build the response
  const msg = {
    message: 'Thank you for the message'
  }

  // Process the request
  const webhook_id = req?.body?.payload?.entity_id || 31066324

  // Lookup the ATS candidate
  if (webhook_id) {
    try {
      const { data } = await apideck.ats.applicants.get({
        id: webhook_id,
        serviceId: process.env.SERVICE_ID_ATS
      })
      console.log('ATS - applicantsOne called successfully', data)
      // Set the employee object
      employee = {
        first_name: data.first_name,
        last_name: data.last_name,
        title: 'Product Manager',
        employment_start_date: formattedDate,
        employee_number: data?.id,
        employment_status: 'active',
        employment_role: {
          type: 'employee',
          sub_type: 'full_time'
        },
        gender: 'female',

        phone_numbers: data?.phone_numbers,
        emails: data?.emails,
        addresses: [
          {
            type: 'primary',
            city: 'Antwerp',
            country: 'BE'
          }
        ]
      }
      console.log('employee data:', employee)

      // Buildup the response
      msg.ats_candidate = {
        id: data.id,
        first_name: data?.first_name || '-',
        last_name: data?.last_name || '-'
      }
    } catch (error) {
      console.error('ATS error:', error)
    }
  }

  if (employee) {
    try {
      const { data } = await apideck.hris.employees.update({
        employee: employee,
        serviceId: process.env.SERVICE_ID_HRIS
      })
      console.log('HRIS - employeesUpdate called successfully', data)
      msg.hris_employee = {
        id: data?.id,
        url: `https://app.humaans.io/?profile=${data?.id}`
      }
    } catch (error) {
      console.error('HRIS error:', error)
    }
  }

  // console.log("-------------- New Request --------------");
  // console.log("Headers:",req.headers);
  // console.log("Body:", req.body);
  res.json(msg)
})

app.listen(port, function () {
  console.log(`Unify app listening at ${port}`)
})
```

### Troubleshooting

Humaans has a unique employee validation based on the email address, so make sure that the employee “Amelia Earhart” does not exist in Humaans.

1. Goto Humaans > People [https://app.humaans.io/](https://app.humaans.io/)

1. Goto “Amelia Earhart” > “Full Profile”

   ![Untitled](/guides/sync-applicant/Untitled%204.png)

![Untitled](/guides/sync-applicant/Untitled%205.png)

1. Offboard “Amelia Earhart”
   1. Click “Offboarding” from the sidebar
   2. Click “Confirm and Schedule offboarding
   3. Next click “Delete this profile”

![Untitled](/guides/sync-applicant/Untitled%206.png)

![Untitled](/guides/sync-applicant/Untitled%207.png)

![Untitled](/guides/sync-applicant/Untitled%208.png)

![Untitled](/guides/sync-applicant/Untitled%209.png)
