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:
Trigger : an applicant gets updated ⇒ the employee gets updated
See the full example on GitHub .
Flow diagram
Highlevel flow
Detailed flow
Scenario
Apideck monitors the ATS system for changes
Apideck detects an update for a candidate
Apideck broadcasts a webhook event ats.applicant.updated
Client application receives webhook event ats.applicant.updated
Client requests “applicant details ” via Unify API
Client transforms the applicant details into an employee model
Client executes a “update employee” request via Unify API
Screenshots
Teamtailer - Updated applicant
https://app.teamtailor.com/companies/YTf4HVdoBks/candidates/segment/all/candidate/31066324
Client - handling the incoming applicant trigger and starting the update employee process based on a webhook.
Humaans - Updated employee
https://app.humaans.io/
Client POC Application
Create a new folder
Place the files below in the folder
Execute the command npm install , this will install all the dependencies
Configure the correct API key & other settings in the .env file
Execute the command npm run start , to start the client application, which will run on: 127.0.0.1:7777
Simulate the Webhook event using this CURL command or via Postman
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
{
"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
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
import dotenv from 'dotenv'
import express from 'express'
import { Apideck } from '@apideck/unify'
dotenv.config()
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)
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' )
const day = String (currentDate.getDate()).padStart(2 , '0' )
const formattedDate = `${year} -${month} -${day} `
app.all('/*' , async function (req, res ) {
let employee = null
const msg = {
message : 'Thank you for the message'
}
const webhook_id = req?.body?.payload?.entity_id || 31066324
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)
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)
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)
}
}
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.
Goto Humaans > People https://app.humaans.io/
Goto “Amelia Earhart” > “Full Profile”
Offboard “Amelia Earhart”
Click “Offboarding” from the sidebar
Click “Confirm and Schedule offboarding
Next click “Delete this profile”