How to build a Candidate Assessment product with Unified.to
April 11, 2024
There are two different ways that you can build a candidate assessment solution. Some ATS providers will allow for an assessment solution to register with them and then call your server with an assessment request. Unfortunately, not many ATS providers support this method, so Unified.to only supports this method that is widely supported.
In the high-paced realm of recruitment, where talent acquisition meets the evolving landscape of HR technology, the need for efficient and robust Candidate Assessment tools has never been more crucial. As companies strive to identify top talent, incorporating candidate assessment software that facilitates critical activities like background checks, skills tests, candidate analytics analysis and more not only expedites the screening process but also ensures a comprehensive and data-driven approach to talent acquisition.
This guide explore how to develop robust and scalable Candidate Assessment software by leveraging third-party integrations through Unified.to's Unified API developer platform to enhance the value of your candidate assessment solution.
Who
You have built a Candidate Assessment
solution for recruiters and hiring managers, enabling them to evaluate candidates who are applying for positions within their companies.
Why (your goal)
You need to access your customers' ATS
(application tracking systems) to automate the data flow of new applications so that your solution can test and assess their candidates.
What
You will need to integrate seamlessly with the leading ATS solutions utilized by your customers, such as Greenhouse, Lever, SmartRecruiters, SAP SuccessFactors, and more. This will provide your users with a streamlined user experience, ensuring efficient data flow and synchronization between your Candidate Assessment solution and their preferred Applicant Tracking Systems (ATS).
How to add ATS integrations to your product
Before we start, be sure to first read:
- Get an initial list of applications
- When the customer authorizes an ATS connection, read the initial set of active applications
import { UnifiedTo } from '@unified-api/typescript-sdk'; import { AtsApplication, AtsApplicationStatus } from '@unified-api/typescript-sdk/dist/sdk/models/shared'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); export async function getApplications(connectionId: string, trigger_status: AtsApplicationStatus, jobId: string, updatedGte?: Date) { const applications: AtsApplication[] = []; const limit = 100; let offset = 0; while (true) { const result = await sdk.ats.listAtsApplications({ updatedGte, jobId, offset, limit, connectionId, }); const apps = result.atsApplications || []; applications.push(...apps.filter((application) => application.status === trigger_status)); if (apps.length === limit) { offset += limit; } else { break; } } return applications; }
- When the customer authorizes an ATS connection, read the initial set of active applications
- Set up to get updated applications
- If you want to use webhooks to get new/updated applications in the future, create a webhook with that
connection_id
import { createHmac } from 'crypto'; import { UnifiedTo } from '@unified-api/typescript-sdk'; import { AtsApplication, AtsApplicationStatus, Event, ObjectType, WebhookType } from '@unified-api/typescript-sdk/dist/sdk/models/shared'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); interface IncomingWebhook { id: string; created_at: Date; updated_at: Date; workspace_id: string; connection_id: string; hook_url: string; object_type: TObjectType; interval: number; checked_at: Date; integration_type: string; environment: string; event: Event; runs: string[]; fields: string; webhook_type: WebhookType; is_healthy: boolean; page_max_limit: number; } interface IWebhookData<T> { data: T[]; // The data array will contact an array of specific objects according to the webhook's connection. (eg. CRM Contacts) webhook: IncomingWebhook; // The webhook object nonce: string; // random string sig: string; // HMAC-SHA1(workspace.secret, data + nonce) type: 'INITIAL-PARTIAL' | 'INITIAL-COMPLETE' | 'VIRTUAL' | 'NATIVE'; } export async function createApplicationsWebhook(connectionId: string, myWebhookUrl: string) { const result = await sdk.unified.createUnifiedWebhook({ webhook: { hookUrl: myWebhookUrl, objectType: ObjectType.AtsApplication, event: Event.Updated, connectionId, }, }); return result.webhook; } export async function handleUnifiedWebhook(incoming: IWebhookData<AtsApplication>, trigger_status: AtsApplicationStatus) { if (incoming.webhook.object_type !== 'ats_application') { return; // not for us } const sig = createHmac('sha1', process.env.WORKSPACE_SECRET) .update(JSON.stringify(incoming.data)) .update(String(incoming.nonce)) .digest('base64'); if (sig !== incoming.sig) { return; // Houston, we have a problem... with security } return incoming.data?.filter((application: AtsApplication) => application.status === trigger_status); }
- Alternatively, create a polling schedule to get new/updated applications, which would be similar to the code in 1a)
- If you want to use webhooks to get new/updated applications in the future, create a webhook with that
- Filter applications on a specific status
- The application has a standardized
status
across all ATS integrations, so decide which one makes sense for you to trigger the assessment - Application.Status options are
NEW
REVIEWING
SCREENING
SUBMITTED
FIRST_INTERVIEW
SECOND_INTERVIEW
THIRD_INTERVIEW
BACKGROUND_CHECK
OFFERED
ACCEPTED
HIRED
REJECTED
WITHDRAWN
. Of these,REVIEWING
,SCREENING
,FIRST_INTERVIEW
,SECOND_INTERVIEW
, orBACKGROUND_CHECK
should be considered.
- The application has a standardized
- Email the candidate with the assessment based on the job
- Read the candidate from the
Application.candidate_id
fieldimport { UnifiedTo } from '@unified-api/typescript-sdk'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); export async function readCandidate(connectionId: string, candidateId: string) { return await sdk.ats.getAtsCandidate({ id: candidateId, connectionId, }); }
- Optional: read the job from the
Application.job_id
fieldimport { UnifiedTo } from '@unified-api/typescript-sdk'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); export async function readJob(connectionId: string, jobId: string) { return await sdk.ats.getAtsJob({ id: jobId, connectionId, }); }
- Determine which test to send to the candidate based on the
Job.id
,Job.descripton
orJob.name
fields
- Read the candidate from the
- Once the candidate has completed the assessment/test, notify the hiring manager and/or recruiter
- Read the employee information based on the
Job.hiring_managers_ids
and/orJob.recruiter_ids
fields and use theEmployee.emails
field to email them the notificationimport { UnifiedTo } from '@unified-api/typescript-sdk'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); export async function readEmployee(connectionId: string, employeeId: string) { return await sdk.hris.getHrisEmployee({ id: employeeId, connectionId, }); }
- Optional: push back a PDF document into the customer's ATS that is associated with that application
import { UnifiedTo } from '@unified-api/typescript-sdk'; import { AtsDocumentType } from '@unified-api/typescript-sdk/dist/sdk/models/shared'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); export async function createDocument(connectionId: string, applicationId: string, documentUrl: string, filename: string, type: AtsDocumentType) { return await sdk.ats.createAtsDocument({ atsDocument: { applicationId, type, documentUrl, filename, }, connectionId, }); }
- Optional: update a candidate with certain
tags
import { UnifiedTo } from '@unified-api/typescript-sdk'; const sdk = new UnifiedTo({ security: { jwt: '<YOUR_API_KEY_HERE>', }, }); export async function updateCandidateTags(connectionId: string, candidateId: string, tags: string[]) { return await sdk.ats.updateAtsCandidate({ atsCandidate: { tags, }, id: candidateId, connectionId, }); }
- Read the employee information based on the
Keep learning:
- How to add a test connection
- How your customers add integrations from your application
- How to generate OAuth 2 credentials
One API to integrate them all
Unified.to is a complete solution to streamline your integration development process and power your Candidate Assessment product with critical third-party candidate data. You're reading this article on the Unified.to blog. We're a Unified API developer platform for SaaS customer-facing integrations. We're excited to continue to innovate at Unified.to and solve hard, critical integration-related problems for our customers. If you're curious about our integrations-as-a-service solution, consider signing up for a free account or meet with an integrations expert.