Field Stories9 min read

The 40,000 Candidates a Staffing Agency Forgot It Had

By Ergini, Software & AI Developer

A composite story. The company and the people in it are invented. The problem, the rules and the system are real, and the full blueprint is in the use case library.

TL;DR

A composite story: an Amsterdam IT contracting agency with 40,000 candidates in Bullhorn pays for job ads and InMails while a contractor it placed twice rolls off and signs with a competitor. The workflow I would build watches placement end dates and new job orders, filters candidates on hard rules and contact limits, finds the closest profiles by similarity, explains each fit with evidence and drafts outreach in the recruiter's own mailbox. Recruiters choose who to contact, send every message and decide every submission.

Record 31877, created in 2014

The record is born on a Tuesday in 2014, when a junior SAP consultant called Marloes uploads her CV to a job board and the agency's import pulls it into Bullhorn. Skills field: SAP FI, CO. A recruiter phones her that spring and leaves a note: good communicator, too junior for now, stay in touch.

Nobody does, for five years. In 2019 she sends a new CV with her first S/4HANA migration on it. In 2023 Femke, one of the senior recruiters, places her for fourteen months at a manufacturer in Brabant, and the placement closes with a line from the client's finance lead in the notes: would have her back tomorrow. In 2025 Femke places her again, at a logistics company in Rotterdam, on a contract that ends on the last Friday of September 2026.

In April 2026 Femke leaves the agency. Her candidates stay in Bullhorn, which is the point of an ATS. Her habit of ringing them a month before their contracts end leaves with her.

By September the record holds everything anyone could need: twelve years of CVs, two placements, a client who would hire her again, and a placement with an end date. Its dateAvailable field says 1 March 2024.

The agency is invented: an IT contracting agency in Amsterdam placing SAP, data and cloud contractors with clients in the Netherlands and Germany, with 14 recruiters and about 40,000 candidates collected over twelve years. Record 31877 is invented too. Anyone who has run a contracting desk will recognize its shape.

The week the record mattered

On the Monday of that last week of September, Joost, who took over part of Femke's desk, gets a new order: an SAP FI/CO consultant for an S/4HANA finance migration, six months, mostly remote, two days a week on site in Eindhoven. He searches Bullhorn, gets about 700 results, recognizes nobody in the first three pages, and does what the desk always does. The role goes on two job boards, and by lunch he has sent twenty InMails from LinkedIn Recruiter to strangers.

Marloes is somewhere in those 700. Keyword search cannot tell Joost that one of them was placed twice by his own agency, that a client would have her back tomorrow, or that she is free on Friday. Her skills field still says what she typed in 2014, and her availability is two and a half years out of date.

On Wednesday a recruiter from another agency calls her. On Thursday she accepts a role through them, starting in October. On Friday she finishes in Rotterdam. Sander, who manages that account, has known since August that there will be no extension. It is in his own pipeline sheet, which nobody on the desk ever sees.

The next Monday, Joost is still waiting for replies to his InMails.

A query nobody had run

Eva, the agency's managing director, calls me about the job board invoices. She pays for sourcing every month and suspects, without being able to prove it, that some of what she pays to find is already in her own database.

Before we talk about AI at all, I ask for last quarter's placements and, for each one, whether the person was in Bullhorn before the order came in. Nobody at the agency has ever run that query. It takes her operations lead an afternoon, and several of the names on the list have records older than the recruiters who placed them.

Then I ask where the truth about a contractor actually lives. Not in the fields, it turns out. Availability dates and rates are years old, because nobody updates them when plans change. The useful signals sit in free text: interview notes, placement notes, a client's line at the end of an assignment. And whether a client will extend lives in the account managers' own sheets.

That decides what I will and will not build. The system reads all of it and puts a short list in front of the recruiter. It does not choose who is contacted, send anything by itself, put anyone forward to a client or merge a single record. Recruiters know things no ATS holds, such as who is not ready to move, and a submission commits the agency to both sides.

The rules come before the matching

The first code I write filters people out, not in. Before any model sees a candidate, rules drop anyone who fails the order's hard requirements: right to work, location or remote eligibility, a day rate inside the order's range with the margin the desk sets. They also drop anyone the agency should not contact: an opt-out on any channel, a do-not-contact flag, a record past the retention period, which is queued for deletion instead, or a message from the agency in the last two weeks.

Re-contacting past candidates usually rests on legitimate interests, which needs a documented assessment and a privacy notice the candidate actually received. The data protection officer sets those rules, and the code applies them on every run. WhatsApp is used only for candidates who opted in, with an approved template for the first message.

Some fields never enter the matching at all. Bullhorn's dateOfBirth, gender and maritalStatus stay out of the input, and remarks in the notes about health, family or personal circumstances are ignored. Matching people to jobs is recruitment AI under the EU AI Act, high-risk from 2 December 2027, so the controls from explainable candidate screening apply here too, including a monthly report on who was surfaced, contacted and put forward.

And Sander's sheet becomes a question. Six weeks before a placement ends, the workflow asks the account manager whether the client plans to extend. Until he answers, the contractor is held. Nobody approaches someone a client is about to keep.

What the record said, and what was true

Here is record 31877 on the Monday Joost searched, next to what was actually the case, and how the workflow would treat each signal.

SignalBullhorn on MondayWhat was trueHow the workflow treats it
AvailabilitydateAvailable: 1 March 2024Free from FridayUnknown after 30 days; the draft asks before describing the role
Current placementEnds the last Friday of SeptemberThe client is not extendingFound six weeks ahead by a daily date query, then held for the account manager's answer
SkillsSAP FI, CO, typed in 2014S/4HANA finance migrations since 2019Read from the CVs and notes, not the field
Day rateFrom the 2023 placementAlmost certainly higherShown as last known after 12 months; the draft asks
Client feedbackWould have her back tomorrowStill relevant to the workQuoted as evidence in the fit note
DuplicatesA second record from a 2016 import, with an old email addressThe same personGrouped by phone and profile URL, so she gets one message; the merge is proposed to a person

Everything in the right-hand column is either a rule or a date. The model's part comes after the rules. Embeddings of every profile and of the order sit in Postgres with pgvector, so a similarity search narrows the candidates who passed the filters to the closest fifty, and a CV that says "S/4 finance migration" still finds an order that says "S/4HANA FI/CO". Then a model reads each of the fifty histories and writes two lines on why the person fits, quoting the line behind every claim.

For Marloes, the two lines would quote the migration on page one of her CV and the Brabant placement note, and flag that her availability was last confirmed in 2024. The full flow, triggers and trust windows included, is in the blueprint for candidate redeployment.

Fourteen recruiters, one good contractor

Before anything goes live, the workflow runs silently over last quarter's orders, producing shortlists nobody acts on, so the desk can compare them with the people it actually placed. The first run shows a problem no model would have mentioned: the best SAP finance contractors turn up on several shortlists in the same week. Left alone, four recruiters would each have written to the same person about four different roles, and she would have stopped answering all of them.

So the contact limits live in code and read the ATS activity history: one redeployment message per candidate every two weeks, across the whole agency, and none while another recruiter has them in an active process. A recruiter who finds a candidate held can see why, and by whom.

The drafts get rules of their own. A message is short and sounds like the recruiter: the role in a line, why this person came to mind, and one question. It mentions a past placement or a client's feedback only when the candidate already knows about it. And when availability was last confirmed more than 30 days ago, the one question is about availability, not the role.

The version where somebody called

Run the same September through the workflow. In mid-August the daily query finds that Marloes's contract ends in six weeks and asks Sander about an extension. He answers the same day: no. A draft appears in Joost's Outlook, under his name:

Hi Marloes, your Rotterdam contract ends in September and I'd like to make sure you have something good lined up for October. Are you free from the start of the month, and is your day rate still where it was? Happy to call whenever suits you.

Joost changes one phrase and sends it from his own mailbox. Her reply updates dateAvailable, with the date it was confirmed, and her rate, and logs a note. When the Eindhoven order arrives, she is at the top of the list: rolling off, no extension, two lines of evidence. Joost calls her that morning, and her CV goes to the client only after she has given written consent to be put forward for that role.

The job boards are still there, for the roles the database cannot cover. And the database gets a little more accurate every week, simply because it keeps being asked.

Before the next job board renewal

If you are on Bullhorn, look at Amplify and Bullhorn Automation first. Amplify's agents cover matching from historical placement data, outreach and record enrichment, and Bullhorn Automation, formerly Herefish, runs rule-based campaigns from ATS data, such as a message before an assignment ends. If your data lives in Bullhorn and your rules are simple, buy.

A build earns its place when matching needs data Bullhorn does not hold, such as timesheets, client feedback in a VMS like SAP Fieldglass or a second ATS from an acquisition, and when the rules are your own: extension checks with account managers, rate margins per desk, contact limits shared across brands. The ATS stays the system of record either way. A first version is usually a multi-step AI workflow automation build with a recruiter approving every message. The redeployment blueprint has the rest, and it works on the same principle as a CRM update agent: the record stays current because every conversation writes back to it.

Frequently asked questions

How can a staffing agency get more placements from its existing candidate database?

Make the database speak up at the two moments that matter: when a contractor's assignment is about to end, and when a new job order arrives. A redeployment workflow filters candidates on hard rules, finds the closest profiles by similarity, has a model read their history and explain each fit with evidence, and drafts outreach for the recruiter to send. Every reply updates availability and rate in the ATS.

Can we legally re-contact old candidates under GDPR?

Usually, with care. Agencies typically rely on legitimate interests, which needs a documented assessment and a privacy notice the candidate actually received. Records past your retention period should be deleted rather than messaged about a job, opt-outs from any channel must hold everywhere, and WhatsApp needs the candidate's opt-in. Your DPO or lawyer sets these rules; the workflow enforces them in code on every run.

Is AI candidate matching high-risk under the EU AI Act?

Very likely. Annex III covers AI used to filter applications and evaluate candidates, and ranking database candidates for a job order is a way of evaluating them. The high-risk obligations apply from 2 December 2027 after the Digital Omnibus. The controls are the same as for screening: recruiters decide, criteria are documented, protected characteristics stay out of the input, and outcomes are monitored.

Should we use Bullhorn Amplify or build our own candidate matching?

Look at Amplify and Bullhorn Automation first. If your data lives in Bullhorn and your rules are simple, buying is the sensible choice. A build earns its place when matching needs data Bullhorn does not hold, such as timesheets, VMS feedback or a second ATS, or rules of your own, like extension checks and contact limits across brands. A first version usually fits the multi-step tier of workflow automation.