← Resources

Recruiting Pipeline Template (CRM-based ATS)

Six stages from Sourced to Hired, candidates as contacts, one deal per candidate per role. A complete field kit that turns any CRM into a lightweight applicant tracking system - with a copy-paste JSON artifact your agent can apply in one pass.

Who this is for

This template is for founders hiring their first 5-15 people, recruiting agencies running a handful of concurrent searches, and fractional talent partners who live inside a client's stack. In all three cases a dedicated ATS is a second system to buy, learn and keep in sync - and the actual workflow is a pipeline, which is exactly what a CRM already does well.

The honest decision rule:

SituationUse
Under ~15-20 hires/year, founder- or recruiter-ledCRM-as-ATS (this template)
Agency running searches where the placement fee is revenueCRM-as-ATS - put the fee in the deal value and your pipeline doubles as a revenue forecast
Compliance reporting (EEOC/OFCCP), consent flows at volumeReal ATS (Greenhouse, Ashby, Teamtailor)
Structured scorecards across 6+ interviewers per loopReal ATS

A real ATS is overkill precisely when its differentiators - multiposting, scorecards, compliance exports - are features you would not touch this year. What you actually need is a stage funnel, a candidate database that survives rejections, and a place to log interview feedback. That is three CRM primitives.

The data model: candidates are contacts, applications are deals

The one modeling decision that makes or breaks this setup: the deal is not the candidate - it is one candidate in process for one role.

Do not model roles themselves as deals with candidates attached - CRMs have no many-to-many between deals and contacts, so you end up with notes fields full of names and zero per-candidate stage tracking. The candidate-x-role deal is the unit that actually moves.

The six stages

Resist the urge to mirror your interview plan as stages. Stages are commitments, not calendar events - each one should have an entry criterion a reviewer can verify in five seconds.

StageKeyEntry criterionTarget time in stage
SourcedsourcedCandidate identified, deal created. No contact yet.≤ 7 days
ScreenscreenCandidate replied; screen call scheduled or done.≤ 7 days
Interview Loopinterview_loopPassed screen; loop invitations sent.≤ 14 days
OfferofferVerbal or written offer extended.≤ 7 days
HiredhiredOffer signed. Terminal.-
RejectedrejectedPassed on, withdrew, or lost to another offer. Terminal.-

Two opinionated calls baked in. First, Rejected is a stage, not a deletion - you want pass-through rates (screens per hire, loop-to-offer ratio) and those require terminal records. Second, the whole loop is one stage, not one per round; track individual rounds as activities. If your loop-stage dwell time blows past 14 days, the fix is scheduling discipline, not more columns.

The fields

Role and money live on the deal; identity and origin live on the contact. Salary is two numbers, not a text range - "90-120k" in a text field is unqueryable the day you want "everyone we can afford under 130."

ObjectFieldTypeWhy
dealrole_titletext, requiredThe role this application is for.
dealseniorityselect: junior / mid / senior / staff / leadFilterable level, no free-text drift.
dealsalary_min, salary_maxnumberCandidate's expected band, queryable.
contactsourceselect: referral / outbound / inbound / agency / eventSource-of-hire is the one recruiting metric worth computing quarterly.
contactlinkedin_urlurlCanonical identity for dedupe and re-engagement.

The kit (copy-paste artifact)

Each entry below is a literal request body for the endpoint named next to it. Applied in order against the Relm API, this builds the whole ATS - pipeline, enum groups, fields, and one automation that logs a follow-up task the moment an offer goes out. It also documents the setup for any other CRM: the shapes translate.

{
  "kit": "recruiting-pipeline",
  "version": "2026-07",
  "requests": [
    { "method": "POST", "path": "/v1/pipelines", "body": {
      "key": "recruiting", "name": "Recruiting",
      "stages": [
        { "key": "sourced", "label": "Sourced" },
        { "key": "screen", "label": "Screen" },
        { "key": "interview_loop", "label": "Interview Loop" },
        { "key": "offer", "label": "Offer" },
        { "key": "hired", "label": "Hired" },
        { "key": "rejected", "label": "Rejected" }
      ] } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "seniority", "value": "junior", "label": "Junior" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "seniority", "value": "mid", "label": "Mid" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "seniority", "value": "senior", "label": "Senior" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "seniority", "value": "staff", "label": "Staff" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "seniority", "value": "lead", "label": "Lead" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "candidate_source", "value": "referral", "label": "Referral" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "candidate_source", "value": "outbound", "label": "Outbound" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "candidate_source", "value": "inbound", "label": "Inbound" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "candidate_source", "value": "agency", "label": "Agency" } },
    { "method": "POST", "path": "/v1/enums", "body": { "group": "candidate_source", "value": "event", "label": "Event" } },
    { "method": "POST", "path": "/v1/fields", "body": { "object": "deal", "key": "role_title", "label": "Role", "data_type": "text", "required": true } },
    { "method": "POST", "path": "/v1/fields", "body": { "object": "deal", "key": "seniority", "label": "Seniority", "data_type": "select", "enum_group": "seniority" } },
    { "method": "POST", "path": "/v1/fields", "body": { "object": "deal", "key": "salary_min", "label": "Salary min", "data_type": "number" } },
    { "method": "POST", "path": "/v1/fields", "body": { "object": "deal", "key": "salary_max", "label": "Salary max", "data_type": "number" } },
    { "method": "POST", "path": "/v1/fields", "body": { "object": "contact", "key": "source", "label": "Source", "data_type": "select", "enum_group": "candidate_source" } },
    { "method": "POST", "path": "/v1/fields", "body": { "object": "contact", "key": "linkedin_url", "label": "LinkedIn", "data_type": "url" } },
    { "method": "POST", "path": "/v1/automations", "body": {
      "name": "Offer out - log 48h follow-up",
      "trigger_event": "deal.stage_changed",
      "conditions": [
        { "field": "pipeline", "op": "eq", "value": "recruiting" },
        { "field": "stage", "op": "eq", "value": "offer" }
      ],
      "actions": [
        { "type": "create_activity", "activity_type": "note",
          "body": "Offer out for {{title}}. Follow up with the candidate within 48 hours." }
      ] } }
  ]
}

A new deal then looks like this - note the fee-as-value trick for agencies:

curl https://api.relmcrm.com/v1/deals \
  -H "Authorization: Bearer relm_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Jane Doe - Senior Backend Engineer",
    "pipeline": "recruiting", "stage": "sourced",
    "primary_contact_id": "con_x8f3k2m9q2",
    "value_cents": 2400000, "currency": "USD",
    "custom_fields": { "role_title": "Senior Backend Engineer",
      "seniority": "senior", "salary_min": 120000, "salary_max": 150000 }
  }'

Apply it with your agent

If your agent speaks MCP, point it at https://api.relmcrm.com/mcp with a relm_test_ key (test mode is free and invisible to live data) and paste:

Apply the recruiting-pipeline kit from
https://relmcrm.com/resources/recruiting-pipeline-template

1. Read the workspace schema first.
2. Create the "recruiting" pipeline with its six stages, the seniority
   and candidate_source enum groups, the deal and contact fields, and
   the offer follow-up automation, exactly as specified in the kit.
3. Skip anything that already exists instead of erroring.
4. Create one test candidate (contact) and one test deal in "sourced"
   to prove the setup, then report every ID you created.

Candidate imports later run through POST /v1/batch - up to 100 contact or deal writes per call. The full walkthrough of the agent workflow is in how to give your AI agent a CRM; endpoint reference in the docs.

FAQ

Can I really use a CRM as an ATS?

Yes, up to a point. If you hire fewer than roughly 15-20 people a year, a CRM pipeline with six stages and a handful of custom fields covers sourcing, screening, interviews and offers with far less setup than Greenhouse or Lever. You give up structured scorecards, job-board multiposting and compliance reporting - which most early teams do not need yet.

Should candidates be contacts or deals?

Candidates are contacts - a person exists once, with their email, LinkedIn URL and source. The deal represents one candidate in process for one specific role, so the deal carries role title, seniority and salary range. This separation means a rejected candidate stays in your database and can be re-engaged for the next opening.

What if one candidate applies to two roles?

One contact, two deals. Each deal moves through the recruiting pipeline independently with its own role_title, seniority and salary fields. The contact-level record - source, resume link, past interview notes - is shared, so nobody screens the same person twice from scratch.

How do I track interview feedback without ATS scorecards?

Log one activity per interview against the deal, with the interviewer's verdict in the first line (strong hire / hire / no hire) and notes below. Backdating via occurred_at keeps the timeline honest when feedback arrives late. It is less structured than a scorecard but it is searchable, attributable and good enough below about 20 hires a year.

When should I graduate to a real ATS?

Three signals: you need compliance artifacts (EEOC/OFCCP reporting, GDPR candidate-consent flows at volume), you run structured interview loops with per-competency scorecards across many interviewers, or you post to job boards constantly and need multiposting. Any one of those justifies Greenhouse, Ashby or Teamtailor. Until then the CRM version is faster and cheaper.

Related resources

Build your ATS in one agent session

1,000 requests a month on the Free plan, no card. See pricing.

Start free →