Unified.to
All articles

ATS to Vector DB: How to Power Talent Intelligence with Real-Time Data


October 14, 2025

With Unified, you can a build talent intelligence application that work with your customers' preferred ATS platform, such as Lever and Greenhouse.

With a single API integration, you can fetch candidate records, normalize and embed resumes, and then push those embeddings into a vector database like Pinecone for real-time search and recruiter agent workflows. This is a complete retrieval-augmented generation (RAG) pipeline for talent intelligence, powered by real-time ATS data.

This guide shows you how to go from ATS to vector DB, step by step, using Unified, GenAI, and Pinecone.

What This RAG Pipeline Does

This guide walks through a full RAG architecture:

  1. Fetch normalized candidate data from an ATS.
  2. Chunk and embed resume content.
  3. Store embeddings in a vector database.
  4. Retrieve the most relevant candidates at query time.
  5. Use retrieved context to power recruiter search, ranking, or AI agents. Unified Use Case RAG Pipelines

Unified handles ingestion and real-time updates across ATS providers; embeddings and vector storage remain in your infrastructure.


Prerequisites

  • Node.js (v18+)
  • Unified account with ATS integration enabled (e.g., Lever, Greenhouse)
  • Unified API key
  • Your customer's ATS connection ID
  • Unified GenAI connection ID (or OpenAI API key for embeddings)
  • Pinecone API key and environment

Step 1: Setting up your project

As always, let's get the basics out of the way!

mkdir ats-vector-demo
cd ats-vector-demo
npm init -y
npm install @unified-api/typescript-sdk dotenv @pinecone-database/pinecone openai

Add your credentials to .env:

UNIFIED_API_KEY=your_unified_api_key
CONNECTION_ATS=your_customer_ats_connection_id
CONNECTION_GENAI=your_genai_connection_id
PINECONE_API_KEY=your_pinecone_api_key
PINECONE_ENVIRONMENT=your_pinecone_env
PINECONE_INDEX=your_pinecone_index

Step 2: Initialize the SDKs

import 'dotenv/config';
import { UnifiedTo } from '@unified-api/typescript-sdk';
import { Pinecone } from '@pinecone-database/pinecone';

const {
  UNIFIED_API_KEY,
  CONNECTION_ATS,
  CONNECTION_GENAI,
  PINECONE_API_KEY,
  PINECONE_ENVIRONMENT,
  PINECONE_INDEX
} = process.env;

const sdk = new UnifiedTo({
  security: { jwt: UNIFIED_API_KEY! },
});

const pinecone = new Pinecone({
  apiKey: PINECONE_API_KEY!,
  environment: PINECONE_ENVIRONMENT!,
});
const index = pinecone.Index(PINECONE_INDEX!);

Step 3: How to Get Your Customer's Connection ID

Before you can fetch candidates, your customer must authorize your app to access their ATS (e.g., Lever, Greenhouse) via Unified's embedded authorization flow.

Once authorized, you'll receive a connection ID for that customer's integration.

Store this connection ID securely and use it in all API calls for that customer.


Step 4: Fetch and Normalize Candidate Records

Fetch candidate records from the ATS and normalize their resumes for embedding. Normalizing resumes before embedding improves retrieval quality and ensures consistent embeddings across 60+ ATS providers.

export async function fetchCandidates(connectionId: string) {
  const candidatesResult = await sdk.ats.listAtsCandidates({
    connectionId,
    limit: 10,
  });
    return candidatesResult; // AtsCandidate[]
}

export function normalizeResume(candidate: any): string {
  return [
    `Name: ${candidate.name}`,
    `Email: ${candidate.emails?.[0]?.email || ""}`,
    `Title: ${candidate.title || ""}`,
    `Summary: ${candidate.summary || ""}`,
    `Experience: ${(candidate.experiences || []).map((exp: any) => `${exp.title} at ${exp.company_name}`).join("; ")}`,
    `Education: ${(candidate.education || []).map((edu: any) => `${edu.degree_name} from ${edu.institution_name}`).join("; ")}``
  ].join('\\n');
}

Step 5: Embed Resumes with GenAI

Use Unified GenAI to embed the normalized resume text.

export async function embedResume(resumeText: string) {
  const result = await sdk.genai.createGenaiEmbedding({
    connectionId: CONNECTION_GENAI!,
    embedding: {
      content: {
        text: resumeText,
      },
      model_id: 'text-embedding-3-small',
      maxTokens: 1024,
      enconding_format: 'FLOAT'
    },
  });
  return result.embeddings;
}

Keeping the Vector Index Up to Date

To keep your RAG pipeline current, subscribe to ATS webhooks for candidate create or update events. When a resume changes, re-fetch the candidate, re-embed the content, and update the vector index. Unified Use Case RAG Pipelines

This ensures your talent intelligence reflects the latest application data in real time.


Step 6: Push Embeddings to Pinecone

export async function upsertCandidateToPinecone(candidate: any, embedding: number[]) {
  await index.upsert([
    {
      id: candidate.id,
      values: embedding,
      metadata: {
        name: candidate.name,
        email: candidate.emails?.[0]?.email || "",
        candidate_id: candidate.id,
      },
    },
  ]);
}

Step 7: Simple Retrieval Flow

Given a recruiter query, embed it and search Pinecone for the most relevant candidates.

export async function searchCandidates(query: string) {

  const result = await sdk.genai.createGenaiPrompt({
    connectionId: CONNECTION_GENAI!,
    prompt: {
      messages: [{ role: "USER", content: `Embed this query:\\n${query}` }],
      maxTokens: 1024,
      temperature: 0.0,
      responseFormat: "embedding",
    },
  });
  const queryEmbedding = result.choices?.[0]?.message?.embedding || [];


  const pineconeResults = await index.query({
    vector: queryEmbedding,
    topK: 5,
    includeMetadata: true,
  });

  return pineconeResults.matches;
}

Step 8: Example Usage

async function main() {

  const candidates = await fetchCandidates(CONNECTION_ATS!);
  for (const candidate of candidates) {
    const resumeText = normalizeResume(candidate);
    const embedding = await embedResume(resumeText);
    await upsertCandidateToPinecone(candidate, embedding);
  }


  const matches = await searchCandidates("Senior Python developer with fintech experience");
  console.log("Top matches:", matches);
}

main();

What just happened?

  • And just like that you can fetch candidate records from any ATS (Lever, Greenhouse, etc.) using a single API.
  • You can then normalize and embed resumes with Unified GenAI, push them into Pinecone, and power a RAG-based recruiter search layer.
  • Recruiters can then search for talent using natural language, and retrieve the most relevant candidates instantly.

Happy Building! 🎉

All articles