How to Classify Resumes and Job Applications with AI

Manually screening hundreds of applications for a single role wastes recruiter time and introduces inconsistency. AI classification gives every application a structured label the moment it arrives - so your team spends time interviewing, not reading.

The screening bottleneck

A typical job posting for a mid-level role attracts 200 to 400 applications. A recruiter reading each one for three minutes would spend 10 to 20 hours on a single role before scheduling a single interview. Most teams don't have that time, so they skim - and skimming introduces inconsistency. The same candidate reviewed on a Monday morning gets a different read than one reviewed at the end of a long Friday.

Existing ATS keyword filters help, but they're brittle in the opposite direction. They flag candidates based on exact phrase matches, which means a strong applicant who writes "built REST services" instead of "REST API development" falls through the cracks. You end up rejecting good candidates and wasting time on marginal ones who happened to use the right vocabulary.

AI classification doesn't replace recruiter judgment on promising candidates. It handles the easy part - the 60 to 70 percent of applications that are clearly a strong fit, clearly the wrong role, or clearly not ready for the level - so human review time concentrates on the candidates who actually warrant it.

Designing your fit categories

Application classification categories should map to the queues and actions in your hiring workflow, not to abstract quality levels. The goal is to produce a label that tells the next person exactly what to do.

A practical starting set:

  • strong_fit - meets or exceeds the role requirements, should move to recruiter review immediately
  • possible_fit - meets most requirements with some gaps, worth a closer look
  • weak_fit - missing key requirements, route to a soft rejection or hold queue
  • wrong_role - applied to the wrong position entirely (overqualified for level, completely different function)
  • needs_review - too ambiguous, sparse, or unusual to classify with confidence

For high-volume roles you may want role-specific sub-categories. A software engineering role might add missing_technical_requirements and senior_mismatch to distinguish between someone who doesn't have the skills and someone who is clearly applying to the wrong level. Add specificity once you see where the ambiguity actually lives in your data.

What to send as input

You don't need to send a full resume as a document. The most reliable input is a structured text summary: the job title applied for, the candidate's current title and years of experience, a brief skill or background summary, and any cover letter text. This fits easily within the input limit and gives the classifier enough signal to work with.

Example input constructed from an application:

Role applied for: Senior Backend Engineer (Python, distributed systems)

Candidate summary:
- Current title: Software Engineer II at a Series B fintech startup (3 years)
- Previous: Junior Developer at a consulting firm (2 years)
- Skills listed: Python, FastAPI, PostgreSQL, some AWS experience
- Cover letter: "I've spent the last three years building payment processing
  pipelines and I'm ready to take on more architectural ownership.
  Your infrastructure challenges look like a great fit for where
  I want to grow."

You send this to classifaily:

curl -X POST https://api.classifaily.com/v1/classify \
  -H "Authorization: Bearer cai_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "Role applied for: Senior Backend Engineer (Python, distributed systems)\n\nCandidate summary:\n- Current title: Software Engineer II at a Series B fintech startup (3 years)\n- Previous: Junior Developer at a consulting firm (2 years)\n- Skills listed: Python, FastAPI, PostgreSQL, some AWS experience\n- Cover letter: I'\''ve spent the last three years building payment processing pipelines and I'\''m ready to take on more architectural ownership.",
    "categories": ["strong_fit", "possible_fit", "weak_fit", "wrong_role", "needs_review"],
    "explain": true
  }'

Response:

{
  "label": "possible_fit",
  "confidence": 0.84,
  "reasoning": "Candidate has relevant Python and backend experience in a production environment, but 5 total years is light for a Senior role, and distributed systems experience is not evidenced beyond general AWS mention. Cover letter signals motivation and growth mindset. Warrants recruiter review rather than automatic advancement or rejection.",
  "request_id": "req_04tr..."
}

This lands in the recruiter's review queue with context rather than in a rejection pile. The recruiter spends two minutes confirming the classifier's reasoning rather than 10 minutes reconstructing it from scratch.

Processing applications at scale

When a role closes and you have 300 applications to triage, use the batch endpoint to process them all in a scheduled job rather than one at a time:

curl -X POST https://api.classifaily.com/v1/batch \
  -H "Authorization: Bearer cai_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "id": "app_1001", "input": "Role: Senior Backend Engineer. Candidate: 8 years Python, led infrastructure team at unicorn startup..." },
      { "id": "app_1002", "input": "Role: Senior Backend Engineer. Candidate: 1 year experience, recent bootcamp graduate, no production systems..." },
      { "id": "app_1003", "input": "Role: Senior Backend Engineer. Candidate: 6 years Java, no Python mentioned, strong distributed systems background..." }
    ],
    "categories": ["strong_fit", "possible_fit", "weak_fit", "wrong_role", "needs_review"]
  }'

Each item gets its own label and confidence score. Sort by label, then by confidence within each label, and your recruiter's queue is pre-organized before they open their laptop on Monday morning.

Integrating with your ATS

Most ATS platforms expose webhooks that fire when a new application arrives. Greenhouse, Lever, and Ashby all support this pattern. The integration is straightforward: receive the webhook, extract the relevant application fields, construct your input text, call the classify endpoint, and write the label back to the application record as a custom field or tag.

From there, ATS automation rules can act on the custom field - moving strong_fit applications to a recruiter review stage automatically and sending weak_fit applications to a holding stage. Your ATS handles the workflow transitions; the classification is just a structured signal feeding into it.

Using schemas for consistency across roles

If you're hiring for multiple roles at once, save your fit categories as a named schema in classifaily and reference the schema ID across all integrations:

{
  "input": "...",
  "schema_id": "sch_hiring_fit_v1"
}

When you refine your categories - adding a senior_mismatch label after noticing a pattern in your data - all roles pick up the change automatically. Your historical data stays interpretable because the category taxonomy evolves in one place.

Getting started

The free plan includes 100 classification requests per month. If you're running a current search, export your last 100 applications, construct input text from each one, and run them through the batch endpoint. Compare the labels against how you actually routed them. That calibration exercise will tell you whether your category design is accurate before you connect it to your ATS.

Full API reference and batch documentation is in the API documentation.

Spend recruiter time on interviews, not inbox triage.

Free plan. 100 requests per month. No credit card required.

Get started free