|
EN / PT
← Back to projects

CV Automation | LinkedIn to Teamtailor with n8n

CV Automation

From LinkedIn to Teamtailor in Seconds: Automating Candidate Import with n8n

Sourcing candidates on LinkedIn Recruiter is great. Until you have to manually copy their details into your ATS. Download the CV, open Teamtailor, create a candidate, fill in the fields, upload the file. Repeat 20 times a week. So I built an automation that does all of it in the background.

Drop a CV into a Google Drive folder and it automatically creates the candidate in Teamtailor, uploads the resume to the right field, and links them to the correct job opening. No ATS required.


1. The Problem

Our recruitment team was sourcing candidates on LinkedIn Recruiter and manually importing them into Teamtailor. The process was:

  1. Find a candidate on LinkedIn
  2. Download their CV (LinkedIn allows up to 25 at a time, 200/month per seat)
  3. Open Teamtailor
  4. Create a new candidate manually
  5. Upload the CV
  6. Fill in name, email, job position
  7. Repeat

The LinkedIn Recruiter System Connect (RSC) integration with Teamtailor only works when candidates apply through a job posting. It does nothing for sourced candidates. The CV also never lands in the right field for automatic parsing.


2. The Tech Stack

Layer Technology
Workflow Automation n8n (self-hosted)
File Storage Google Drive
CV Upload Teamtailor Transient Upload API
ATS Teamtailor
Trigger Google Drive polling (every minute)

3. The Automation Pipeline

The workflow runs entirely in n8n and has 6 steps:

CV dropped in Google Drive folder
              │
              ▼
┌─────────────────────────┐
│   Watch CV Folder        │
│   Google Drive Trigger   │
│   (polls every minute)   │
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
│   Download CV            │
│   Fetches binary PDF     │
│   from Drive             │
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
│   Upload to Teamtailor   │
│   POST /v1/files         │
│   Returns transient URI  │
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
│   Create Candidate       │
│   POST /v1/candidates    │
│   resume = transient URI │
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
│   Find Job by Title      │
│   GET /v1/jobs           │
│   filter by filename     │
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
│   Create Job Application │
│   POST /v1/job-apps      │
│   links candidate + job  │
└─────────────────────────┘

4. Key Technical Decisions

Teamtailor Transient Upload

The Teamtailor public API doesn't support binary-data in the candidate creation endpoint. That's only available in the Direct Apply API for job board partners. The correct approach for importing external CVs is the transient upload endpoint:

POST https://api.teamtailor.com/v1/files
Content-Type: multipart/form-data

file: [binary PDF]

This returns a one-time transient: URI that you then pass as the resume value when creating the candidate. Teamtailor downloads it, parses the CV, and auto-fills name, phone, LinkedIn URL, and address from the document.

Job Matching via Filename Convention

Instead of hardcoding job IDs or building a mapping table, the workflow uses a simple filename convention:

EMEA Marketing Intern - Berta Carol Jutgla.pdf
SDR SP Intern - John Smith.pdf

The text before the - separator is extracted as the job title, then used in a live API call:

GET /v1/jobs?filter[title]=EMEA Marketing Intern

This means no configuration is needed when new job openings are created in Teamtailor. The workflow finds them dynamically by name.

Why Not Google Drive Desktop Sync?

The Google Drive desktop client introduces a sync delay. A file can appear in the local folder before it's fully uploaded to Google's servers. When n8n polls and detects the file, it may try to download an incomplete upload. Using browser upload directly on drive.google.com ensures the file is fully available server-side before the trigger fires.


5. What Gets Auto-Filled

When the CV lands in Teamtailor's resume field (not as an attachment), the built-in resume parser automatically extracts:

  • ✅ Full name
  • ✅ Phone number
  • ✅ LinkedIn URL
  • ✅ Address / location
  • ✅ CV summary (via Co-pilot)

The email address is not extracted automatically. Teamtailor's parser skips it for privacy reasons. A placeholder email is used at creation time and updated manually when the recruiter makes contact.


6. The Workflow in n8n

The complete workflow has 8 nodes:

Node Type Action
Watch CV Folder Google Drive Trigger Detects new files in the folder
Download CV Google Drive Downloads binary PDF
Upload to Teamtailor HTTP Request POST to /v1/files, gets transient URI
Create Candidate HTTP Request POST to /v1/candidates with URI as resume
Extract Candidate ID & Job Title Code Parses candidate ID + extracts job title from filename
Find Job by Title HTTP Request GET /v1/jobs filtered by title
Prepare Job Application Code Extracts job ID, pairs with candidate ID
Create Job Application HTTP Request POST to /v1/job-applications

All HTTP nodes use application/vnd.api+json as Content-Type (Teamtailor follows JSON:API spec).


7. Lessons Learned

The Teamtailor API is JSON:API. All requests need Content-Type: application/vnd.api+json, not application/json. This caused silent 500 errors for hours before being identified.

Binary data in n8n Code nodes. Accessing binary data from a previous node requires items[0].binary.data.data, which already contains a base64 string. The getBinaryDataBuffer helper doesn't work reliably in all contexts.

Google Drive Trigger processes multiple files. When several CVs are dropped at once, the trigger returns multiple items. All Code nodes must be set to "Run Once for Each Item" mode, otherwise only the first file is processed.

Transient URIs are single-use. They must be used within ~30 seconds of generation. The workflow is fast enough that this isn't an issue in practice.


Conclusion

What used to take 5 minutes per candidate now takes 5 seconds. The recruiter downloads CVs from LinkedIn, renames them with the job title prefix, drops them in the Drive folder, and Teamtailor does the rest.

The most interesting part of this build was discovering the Teamtailor transient upload API. A non-obvious endpoint that's not prominently documented, but the correct way to import CVs programmatically into the resume field rather than as generic file attachments.


Built by Nuno, Veesion Tech & IT