218 of 312 Applicants Rejected Before a Human Looked

Abstract tech illustration: 218 of 312 Applicants Rejected Before a Human Looked

Every recruiting AI demo shows the same three things: source, screen, schedule. Nobody shows you the tier that actually saves the hours — the guilt-driven manual review of obvious no's. Here's the exact n8n flow that killed 218 of 312 applications on one role before a recruiter wasted a minute.

The 9-hour leak nobody automates

One role. Mid-level ops position. 312 applications in 11 days. The recruiter I built this for was spending roughly nine hours per week opening CVs, reading the first paragraph, and closing them again because the candidate was in the wrong country, wanted double the salary band, or didn't hold the license the role legally requires. Zero hires from that pile.

That's the actual leak. And it's the one nobody automates, because every founder-influencer is busy building outreach bots for the top of the funnel where it looks impressive on a demo.

We flipped it. Automated the rejection tier first. Here are the real numbers after 11 days on one role:

Metric Before After
Applications 312 312
Auto-rejected with reason code 0 218
Promoted to human review 312 94
Recruiter time ~9 hrs/week ~90 min/week
Token cost (Claude Haiku) $0 $0.41
False negatives (month 1) n/a 2 out of ~600

That's the whole pitch. Now the build.

Step 1: Hard-fail criteria, not scoring models

This is where most teams ruin the pipeline before they start. Do not build a scoring model. Start with hard-fail criteria — binary gates that a person could defend in writing to a candidate, a lawyer, or a labor board.

For this ops role, we encoded six:

  • Work authorization for the country of hire
  • Physical location within commuting distance of the office
  • Minimum years of relevant experience (role-specific)
  • Salary expectation inside the posted band
  • A specific professional license required by the role
  • Language fluency at working level

No culture fit. No "communication skills." No vibes. Soft signals belong later, after a human is already in the loop.

The reason this matters is legal and operational. Soft scoring produces disputes. Hard criteria produce receipts. When a candidate emails back asking why they were rejected, the recruiter points at one line: "You indicated Berlin as your base. The role requires on-site presence in Lisbon." That reply writes itself.

In the US, the EEOC's guidance on AI in employment decisions is clear that automated tools can create disparate impact liability under Title VII. Binary, role-relevant criteria with evidence snippets are defensible. Opaque 1-10 scores are not.

Step 2: The n8n trigger and CV extraction

Every application lands in a shared Gmail inbox. The ATS forwards there. A Gmail label — new-application — fires the n8n workflow.

The flow is boring on purpose:

Gmail Trigger (label: new-application)
  → Extract email body + sender
  → Download attachment (PDF/DOCX)
  → PDF-to-text node (pdf-parse)
  → Merge: {email_body, cv_text, applicant_id}
  → HTTP Request → Anthropic Messages API (claude-haiku)
  → Parse JSON response
  → IF any_fail == true → Airtable: reject_queue
  → ELSE → Airtable: human_review + Gmail label: needs-review

Model choice matters. I use Claude Haiku, not Sonnet, not Opus. We're not writing poetry — we're checking six checkboxes. Haiku runs at roughly $0.25 per million input tokens and $1.25 per million output tokens (check Anthropic's current pricing before you scale). A typical CV + cover email + prompt clocks in around 3,500 input tokens and 400 output tokens per call. That's how 312 applications came in at 41 cents total.

Sonnet would have cost roughly 12x more with zero accuracy gain on binary extraction. Save Sonnet for the tasks where reasoning actually matters.

Step 3: The prompt structure (criterion-by-criterion, not holistic)

Do not ask the model for a holistic score from 1 to 10. That's the single biggest failure mode in every hiring AI I've audited. Ask criterion by criterion, demand a quoted evidence snippet, and force a strict JSON schema.

Here's the shape of the prompt:

SYSTEM = """You evaluate a candidate against exactly six binary criteria.
For each criterion return:
  verdict: "pass" | "fail" | "unclear"
  evidence: exact quoted sentence from the CV or cover email
            that led to your decision, or null if none exists
  confidence: "high" | "low"

Do not infer. Do not guess. If the CV does not explicitly state
the fact needed to evaluate a criterion, return "unclear".
Return only valid JSON matching the provided schema."""

USER_TEMPLATE = """
CRITERIA:
1. work_authorization: Candidate has legal right to work in {country}.
2. location: Candidate is based within {radius_km} km of {city}.
3. experience: Candidate has at least {min_years} years in {domain}.
4. salary: Candidate's stated expectation is within {band_low}-{band_high} {currency}.
5. license: Candidate holds a valid {license_name}.
6. language: Candidate is fluent (B2 or higher) in {language}.

CV TEXT:
{cv_text}

COVER EMAIL:
{email_body}

Return JSON: {{"criteria": [{{"name": "...", "verdict": "...", "evidence": "...", "confidence": "..."}}]}}
"""

The routing logic that follows is trivial:

// n8n Function node
const results = JSON.parse($json.claude_response).criteria;
const hard_fail = results.some(c => c.verdict === "fail" && c.confidence === "high");
const has_unclear = results.some(c => c.verdict === "unclear");

return {
  route: hard_fail ? "reject_queue" : "human_review",
  triggered_by: hard_fail
    ? results.find(c => c.verdict === "fail" && c.confidence === "high").name
    : null,
  results
};

Notice what's not there. No "score > 7 means promote." No weighting. If any single hard criterion fails with high confidence, the candidate goes to the silent-reject queue. Unclear or all-pass goes to a human. That's the whole decision tree.

Step 4: The Airtable logging schema that makes it auditable

This is what turns the flow from a black box into a tool a non-technical recruiter can actually trust and tune.

Every decision — pass or fail — writes a row to Airtable. Three columns matter most:

Column Example
applicant_id 2026-ops-0184
triggered_criterion location
evidence_snippet "Currently based in Berlin, open to remote roles across EU."
verdict_full_json {...} (full 6-criteria response)
route reject_queue
timestamp 2026-08-05T14:22:11Z
model_version claude-haiku-2026-xx

Once a week, the recruiter opens Airtable, sorts by triggered_criterion, and asks two questions:

  • Are we rejecting on the right things?
  • Are the evidence snippets actually saying what the model thinks they're saying?

If the answer is no, they don't touch the prompt. They adjust the criteria list for that role — the role config, in Airtable, in plain English. The prompt stays generic. Criteria are config. That separation is what lets a non-technical recruiter tune this weekly without calling me.

Step 5: The shadow-review layer (don't skip this)

Three times a week, the workflow randomly pulls one CV from the reject pile and forwards it to the recruiter anyway, flagged as a shadow review. The recruiter reads it in 90 seconds and either confirms the rejection or flags a false negative.

// n8n Cron: Mon/Wed/Fri 09:00
const rejects = await airtable.list("reject_queue", {
  filterByFormula: "AND(IS_AFTER(timestamp, DATEADD(NOW(), -2, 'days')), NOT({shadow_reviewed}))"
});
const sample = rejects[Math.floor(Math.random() * rejects.length)];
await gmail.send({
  to: recruiter,
  subject: `[SHADOW REVIEW] ${sample.applicant_id} — rejected on ${sample.triggered_criterion}`,
  body: buildShadowReviewEmail(sample)
});

Over the first month we caught two false negatives out of roughly 600 rejections. Both were candidates whose CVs were poorly formatted — one was a PDF that was actually an image scan, the other used a two-column layout that scrambled during text extraction. The model wasn't wrong. The input was garbage.

We fixed the extraction step (added an OCR fallback for image PDFs, added a layout-aware parser for multi-column), not the model. If you don't have a shadow-review layer, you'll drift and you won't know you're drifting until a great candidate posts a screenshot on LinkedIn.

What to actually measure

  • False negative rate (target: <1%)
  • % of rejections triggered by each criterion (spot skew)
  • Extraction failure rate (CVs where >2 criteria return "unclear")
  • Time-to-decision per applicant (should be <30 seconds)

Step 6: The bot never sends the rejection email

Hard rule. The bot does not send the rejection email. Ever.

Several jurisdictions have disclosure requirements for automated hiring decisions. New York City's Local Law 144 requires bias audits and candidate notification for automated employment decision tools. Illinois has the AI Video Interview Act. The EU AI Act classifies most hiring AI as high-risk. The last thing a small business needs is a discrimination complaint over an email nobody read before it went out.

What we do instead: the silent-reject queue sits in Airtable. Once a week, the recruiter reviews it in bulk, spot-checks the evidence snippets, and then sends rejection emails from their own inbox using a templated response that quotes the specific criterion. A human clicks send. That's the compliance line, and it's cheap to hold.

Why bizflowai.io helps with this

We build these silent-reject pipelines for recruiter clients as a standard workflow — the Gmail trigger, the Claude Haiku evaluator, the Airtable audit log, the shadow-review sampler, and the role-config sheet that a non-technical recruiter can edit weekly. Most clients go live in under a week and see their manual CV-reading time drop by 70-85% on the first role they migrate. The pattern is the same across ops, sales, and support roles — only the six criteria change.


Want more like this?

I publish practical AI automation, GenAI engineering, and faceless content workflows on YouTube every week.

Subscribe to bizflowai.io on YouTube — never miss a new tutorial.

Planning an AI automation project or need a second opinion on your architecture?

Connect with me on LinkedIn — Lazar Milicevic, GenAI Engineer & bizflowai.io Founder.

Visit bizflowai.io for our services, case studies, and AI consulting.

Frequently asked questions

What is CV auto-rejection with Claude Haiku?

CV auto-rejection is an AI workflow that screens job applications against hard-fail criteria before a recruiter sees them. In one real case, 312 applications for an ops role were processed: 218 were auto-rejected with reason codes and 94 promoted to human review. Total cost on Claude Haiku was 41 cents, and recruiter review time dropped from nine hours per week to about ninety minutes.

How do I build an AI CV screening pipeline in n8n?

Route applications into a Gmail inbox with a 'new-application' label that triggers an n8n workflow. n8n extracts the email body, converts the CV attachment from PDF to text, then sends everything to Claude Haiku with six binary criteria. The model returns pass/fail/unclear per criterion with evidence snippets. Fails go to a silent-reject queue; passes or unclears are promoted to the recruiter's inbox. Every decision is logged to Airtable.

Why should you use hard-fail criteria instead of a scoring model for CV screening?

Hard-fail criteria produce receipts, while soft scoring produces disputes. Binary gates like visa status, location, salary band, licenses, minimum experience, and language fluency give recruiters a defensible reason for every rejection. If a candidate asks why they were rejected, the recruiter can point to one specific line, such as 'you're based in Berlin, the role requires on-site in Lisbon.' Soft skills and culture fit belong later, after a human is involved.

When should I use Claude Haiku vs Sonnet or Opus for recruiting automation?

Use Claude Haiku for binary criteria evaluation like CV screening, where you're checking checkboxes rather than generating nuanced content. Haiku is fast, cheap, and accurate enough for pass/fail decisions against explicit criteria. Reserve Sonnet or Opus for tasks requiring reasoning, writing, or holistic judgment. In the ops role example, screening 312 CVs against six criteria with Haiku cost only 41 cents total.

How should I structure prompts for AI CV screening?

Do not ask for a holistic one-to-ten score. Instead, provide the CV text, cover email, and a list of criteria, then instruct the model to return pass, fail, or unclear for each criterion, along with the exact sentence from the CV that justified the decision. This returns a small JSON object with per-criterion verdicts and evidence snippets, making decisions auditable and letting recruiters verify the model's reasoning.