TalentLyft to Jobsoid Migration: A Technical Guide
A technical guide to migrating from TalentLyft to Jobsoid — covering API extraction limits, pipeline stage mapping, CSV constraints, and GDPR compliance.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
TalentLyft to Jobsoid Migration: A Technical Guide
Migrating from TalentLyft to Jobsoid is a data-model translation problem complicated by asymmetric API capabilities and mismatched pipeline architectures. TalentLyft is built around inbound recruitment marketing with a well-documented REST API and flexible multi-pipeline system. Jobsoid is a pipeline-centric ATS with a more opinionated, category-locked stage model and minimal public API documentation. Every gap between these architectures — different pipeline stage logic, different custom field models, different attachment handling — is where candidate histories and application context silently break.
If you need a fast decision: TalentLyft's CSV candidate export flattens relational data and ships it as a ZIP file via email. It drops application-to-job relationships, pipeline stage histories, activity timelines, and file attachments. Jobsoid's CSV import auto-maps columns but cannot restore that relational context in a single operation. API-based extraction from TalentLyft's Customer API, combined with transformation and structured loading into Jobsoid, is the only method that preserves full candidate context at scale. But Jobsoid's public API documentation is minimal, which means you may need to negotiate API access or work within Jobsoid's import constraints.
This guide covers the real extraction and loading limits on both sides, entity-by-entity mapping, pipeline stage translation, every viable migration approach with trade-offs, and the edge cases that corrupt recruiting data during this specific ATS-to-ATS move.
For broader ATS migration patterns, see 5 "Gotchas" in ATS Migration. For compliance planning, read The Ultimate ATS Data Migration Checklist. If you are concerned about candidate data privacy during the move, see Ensuring GDPR & CCPA Compliance When Migrating Candidate Data.
The TalentLyft-to-Jobsoid Architecture Mismatch
Understanding where these two platforms diverge structurally is essential before you map a single field.
TalentLyft's Data Model
TalentLyft is built heavily around inbound recruitment marketing. Its architecture splits focus between a CRM (Talent Pools, Campaigns, Source Tracking) and an ATS (Jobs, Stages, Applications). Core entities include Candidates, Jobs, Departments, Pipelines, Applications (the join between a Candidate and a Job), Members (team users), Events, Forms, and Articles (career site content). The Customer API (https://api.talentlyft.com/v2) exposes endpoints for all of these. The API has been at v2 since at least 2021; v1 is deprecated and no longer documented.
Candidates carry rich profiles: education, experience, projects, languages (with proficiency levels like professional_working or native), social profiles across 20+ networks, source tracking, and custom fields. Pipelines are fully customizable — unlimited pipelines, assignable per job, with only three mandatory stages: Sourced, Applied, and Hired.
Jobsoid's Data Model
Jobsoid is optimized for pipeline velocity, job board syndication, and multi-channel communication. Its pipeline is more structured: default stages are New, Screen, Interview, Offer, Hire, On Hold, Reject, and Withdraw. Custom stages can be added, but Jobsoid organizes them under categories (Screen, Interview, Offer) and limits each category to 5 stages by default — expansion requires contacting support.
Jobsoid supports custom fields on jobs and candidate profiles, automated actions tied to pipeline stages, and questionnaire-based screening. Its base API endpoint is https://api.jobsoid.com. The public API surface area is narrow — documented write endpoints cover candidate creation and job application submission, but bulk operations, stage assignment, and attachment linking require direct negotiation with Jobsoid support. Its data import model is more constrained than TalentLyft's API-first approach.
Where the Models Clash
| Dimension | TalentLyft | Jobsoid |
|---|---|---|
| Pipeline flexibility | Unlimited pipelines, unlimited stages | Category-locked stages (Screen/Interview/Offer), 5 per category default |
| Mandatory stages | Sourced, Applied, Hired | New, Hire, Reject, Withdraw |
| API rate limit | 500 requests/min per token | Not publicly documented |
| API version | v2 (current), v1 deprecated | Single version, narrow surface area |
| CSV export | Candidate data as ZIP via email | N/A (Jobsoid is the target) |
| Attachment handling | Resume via API (PDF, DOC, DOCX, TXT) | Resume import (DOC, DOCX, RTF, PDF, TXT), max 10 files per batch |
| Custom fields | Candidate fields + Application fields | Job fields + candidate profile fields |
| Social profiles | 20+ networks (LinkedIn, GitHub, etc.) | Limited to standard profile fields |
| Talent Pools | Dedicated CRM pools for passive candidates | No direct equivalent — must convert to tags or custom fields |
Three structural differences cause the most pain during migration:
- Talent Pools vs. Tags. TalentLyft relies on "Talent Pools" to group passive candidates. Jobsoid has no 1:1 equivalent. You must map TalentLyft Pools into Jobsoid as Candidate Tags (e.g.,
Pool: Q3_Engineers) or custom fields. - Application-Level vs. Candidate-Level Notes. In TalentLyft, a recruiter can leave a note on the candidate profile or on a specific job application. Jobsoid tracks activity feeds at the candidate level. Pushing application-specific notes into a global feed without prepending the Job Title strips the context from the note.
- GDPR Consent Tracking. TalentLyft, being EU-based, has built-in consent tracking (consent dates, expiration dates, purposes). Jobsoid supports compliance, but these fields must be explicitly mapped to custom fields or consent flags in Jobsoid.
Why CSV Exports Fail for This Migration
Many teams assume they can use TalentLyft's bulk export feature to generate CSVs and upload them into Jobsoid. As we've noted in our JazzHR to Greenhouse migration guide, moving relational ATS data via flat CSVs inevitably destroys the application context your recruiting team depends on. This approach fails at scale for several reasons.
On the TalentLyft export side:
- Flat structure only. The CSV flattens candidates into rows. Application-to-job relationships, pipeline stage histories, and activity timelines are not included.
- No attachments. Resumes, cover letters, and uploaded files are not part of the CSV payload. The CSV might contain a URL to a resume, but those URLs expire or require authentication. When you shut down TalentLyft, every resume linked in a CSV becomes a dead link.
- No custom field granularity. Complex custom field types (multi-select, conditional fields) may serialize poorly.
- Flattened relationships. A candidate who applied to three jobs over two years gets duplicated or has historical applications overwritten, leaving you with only the most recent.
On the Jobsoid import side:
- No pipeline stage import. Candidates imported via CSV land at the beginning of the pipeline (typically "New"). Historical stage progression is lost.
- No activity history. Notes, emails, interview feedback, and stage-change timestamps cannot be imported via CSV.
- One job assignment per import batch. You can assign candidates to one job per import operation. Multi-job candidates require multiple import passes or manual reassignment.
- Resume import is separate. Jobsoid's resume import is a distinct operation from CSV import. You upload resume files separately, with a maximum of 10 files per batch via the UI. There is no way to programmatically link a CSV row to its corresponding resume file during import.
- Loss of activity timestamps. CSV imports stamp the "Created Date" as the date of import. Your historical data looks like 10,000 candidates applied on a single day.
- Column format requirements. Jobsoid's CSV auto-mapper expects UTF-8 encoding with comma delimiters. Headers must match Jobsoid's field labels exactly for auto-mapping to work; unrecognized columns require manual assignment during upload. Non-ASCII characters in column values (accented names, CJK characters) must be validated before upload or they will corrupt on import.
CSV export is viable only for small databases (<500 candidates) where you accept losing relational context and plan to re-upload attachments manually.
Extracting Data via the TalentLyft API
The TalentLyft Customer API is a REST API authenticated via API token. You generate the token under Profile → Integrations → TalentLyft Access Token. The API exposes endpoints for Candidates, Jobs, Departments, Pipelines, Members, Events, Forms, and Rejection Reasons. All endpoints are under https://api.talentlyft.com/v2.
Pagination and Rate Limits
TalentLyft paginates its responses. You must iterate through pages to pull complete datasets. Stick to batch sizes of 50.
The documented rate limit is 500 requests per minute per API token. For a database of 10,000 candidates — assuming one request per candidate detail fetch plus separate requests for applications and attachments — expect 60+ minutes of extraction time at full throughput. Your extraction script must monitor HTTP 429 Too Many Requests responses and implement exponential backoff.
import requests
import time
BASE_URL = "https://api.talentlyft.com/v2"
HEADERS = {"Authorization": "Bearer YOUR_API_TOKEN"}
def fetch_all_candidates():
candidates = []
page = 1
while True:
resp = requests.get(
f"{BASE_URL}/candidates",
headers=HEADERS,
params={"page": page, "pageSize": 50}
)
if resp.status_code == 429:
time.sleep(60) # Back off a full minute on rate limit
continue
resp.raise_for_status()
data = resp.json()
candidates.extend(data.get("items", []))
if page >= data.get("totalPages", 1):
break
page += 1
time.sleep(0.15) # Stay under 500 req/min
return candidatesExtracting Attachments
Resumes, cover letters, and portfolio files are the heaviest part of the migration. When you query a candidate via the API, the response includes metadata about attachments and a temporary, authenticated URL to download the file. A candidate record's attachment section looks like this in the API response:
{
"id": "cand_12345",
"firstName": "Ana",
"lastName": "García",
"email": "ana.garcia@example.com",
"attachments": [
{
"id": "att_98765",
"type": "resume",
"fileName": "Ana_García_CV.pdf",
"mimeType": "application/pdf",
"url": "https://files.talentlyft.com/secure/att_98765?token=TEMP_TOKEN",
"createdAt": "2023-11-14T09:32:00Z"
}
],
"customFields": {
"years_experience": "7",
"preferred_location": ["Remote", "Berlin"],
"referral_source": "Employee: Marcus Webb"
}
}Note that url values are temporary and authenticated. They will expire. Download files immediately after fetching each candidate record — do not batch the metadata extraction and attachment download as separate passes, or the URLs will be stale by the time you attempt downloads.
Your extraction middleware must:
- Query the candidate record.
- Parse the attachment URLs.
- Issue a GET request to download the binary file.
- Store the file temporarily in a secure staging environment (like an encrypted S3 bucket) keyed by
candidateId/attachmentId/fileNamebefore pushing to Jobsoid.
Do not try to pipe binary files directly from TalentLyft's API into Jobsoid in memory. If either API throttles the connection, the transfer drops. Always buffer attachments in a secure intermediate storage layer.
TalentLyft's API token is tied to your user account. If the account that generated the token is deactivated during migration, all API access stops immediately. Generate the token from a service account or admin account that will remain active through the entire migration window.
Extracting Custom Fields
Custom fields are extractable via the API, but the schema varies per account configuration. Export the custom field schema definitions first by querying GET /v2/custom-fields, then map values against those definitions. This prevents silent data loss when a field in TalentLyft has no matching type in Jobsoid. Pay particular attention to multi-select fields — the API returns these as arrays, which must be serialized to a delimiter-separated string if Jobsoid has no equivalent multi-select field type.
Loading Data into Jobsoid
Jobsoid's inbound data paths are more constrained than TalentLyft's outbound ones. You have two options, and both have limits.
CSV Import
Jobsoid supports CSV candidate imports with automatic column mapping:
- Navigate to Candidates → (+) New → Import → Import CSV Files.
- Optionally assign imported candidates to an existing job opening.
- Select a candidate source for tracking.
- Upload the CSV file (UTF-8, comma-delimited).
- Review Jobsoid's auto-mapped columns and correct any mismatches.
The limitations are significant: no pipeline stage import, no activity history, one job assignment per batch, and resume import is a separate operation capped at 10 files per batch.
Jobsoid API
Jobsoid does offer API access at https://api.jobsoid.com. The documented public endpoints include candidate creation (POST /candidates) and job application submission (POST /jobs/{jobId}/apply). Bulk operations, stage assignment via API, and programmatic attachment linking are not in the public documentation and require contacting Jobsoid support to confirm availability on your plan.
Jobsoid's API rate limits are not publicly documented. Before committing to an API-based loading strategy, get written confirmation from Jobsoid on request limits, throttling behavior, and any bulk-import endpoints that may not be in the public docs.
The Dependency Load Order
Regardless of whether you use CSV or API, data must be loaded into Jobsoid in dependency order. You cannot attach a candidate to a job that does not exist.
- Users/Recruiters — Create all internal team members first so you can assign ownership.
- Departments and Locations — Foundation data required for job creation.
- Jobs (Requisitions) — Create jobs, mapping TalentLyft's job statuses (Open, Closed, Draft) to Jobsoid's equivalents.
- Candidates — Push candidate profiles (Name, Email, Phone, Social Links).
- Attachments — Upload resumes and link them to newly created Candidate IDs.
- Applications — Link Candidate ID to Job ID.
- Notes & Activities — Push historical notes, interview feedback, and emails, associating them with the correct Candidate ID and User ID.
Resume Upload at Scale
Because Jobsoid caps resume uploads at 10 files per batch via the UI, a database with 5,000 resumes means 500 manual upload cycles. This is where API access becomes non-negotiable for any migration above a few hundred candidates — a bottleneck similar to the resume parsing constraints we see in Ceipal migrations. If API resume upload is unavailable, consider:
- Requesting a bulk import from Jobsoid's support team directly
- Scripting the UI workflow using browser automation (fragile, but sometimes the only option)
- Accepting that only active/recent candidate resumes will be migrated, and archiving the rest in a separate document store (S3, Google Drive) keyed to the candidate's TalentLyft ID
Entity-by-Entity Field Mapping
Every field without a direct Jobsoid equivalent needs a decision: drop it, flatten it into a notes field, or store it in a custom field.
Candidate Fields
| TalentLyft Field | Jobsoid Field | Transformation Notes |
|---|---|---|
Id |
external_id (Custom Field) |
Always store the legacy ID for troubleshooting and delta syncs. |
FirstName, LastName |
first_name, last_name |
Direct map. |
Email |
email |
Jobsoid enforces unique emails. Deduplicate in TalentLyft before loading. |
Phone |
phone |
Normalize to E.164 format during transit. |
Headline |
— | Map to custom field or notes. |
Address |
Location | May need restructuring (city vs. full address). |
Summary |
— | Map to candidate notes. |
Resume (file) |
Resume attachment | Separate upload required. |
Education [] |
Education | Verify structure compatibility. |
Experience [] |
Work Experience | Verify structure compatibility. |
Projects [] |
— | No native equivalent; use custom field. |
Languages [] |
— | No native equivalent; serialize to custom field (e.g., Spanish:native,French:professional_working). |
SocialProfiles [] |
Social links | Jobsoid supports fewer networks than TalentLyft's 20+. Map LinkedIn, GitHub, Twitter directly; drop unsupported networks or serialize to a text field. |
Tags |
tags |
Array of strings. |
TalentPools |
tags |
Convert pools to tags (e.g., Pool: Q3_Engineers). |
SourceType + SourceBy |
Candidate Source | Map TalentLyft source taxonomy to Jobsoid's source list. Create matching source values in Jobsoid first. |
CustomFields{} |
Custom Fields | Create matching fields in Jobsoid first. Multi-select arrays must be serialized to pipe-delimited strings if Jobsoid has no multi-select equivalent. |
Job Fields
| TalentLyft Field | Jobsoid Field | Transformation Notes |
|---|---|---|
| Job Title | Job Title | Direct map. |
| Department | Department | Create departments in Jobsoid first. |
| Location | Location | Direct map. |
| Job Description (HTML) | Job Description | Strip proprietary TalentLyft CSS classes and <iframe> embeds before import. Test HTML rendering in Jobsoid with a sample batch first. |
| Pipeline ID | Pipeline config | Manual recreation required. |
| Custom Fields | Custom Fields | Create matching job fields in Jobsoid first. |
Notes and Activity Feeds
TalentLyft exports notes with rich text formatting (HTML). Jobsoid supports rich text, but you must strip proprietary TalentLyft CSS classes or <iframe> embeds, as these can break the Jobsoid UI.
If the Jobsoid API does not allow you to override the created_at date on notes, prepend historical notes with the original author and timestamp in a standardized format:
[Migrated | TalentLyft | 2024-05-12 | John Smith] Great technical skills, moving to next round.
Using a consistent prefix format — pipe-delimited, with fixed field positions — makes these notes parseable if you ever need to re-process them or extract them from Jobsoid in the future.
Pipeline Stage Mapping
This is the highest-risk mapping in the entire migration.
TalentLyft's three mandatory stages (Sourced, Applied, Hired) map loosely to Jobsoid's New, pipeline middle stages, and Hire. But any custom TalentLyft stages between Applied and Hired must be forced into Jobsoid's category structure.
| TalentLyft Stage | Jobsoid Category | Jobsoid Stage |
|---|---|---|
| Sourced | — | New |
| Applied | — | New |
| Phone Screen | Screen | Screen (default) or custom |
| Technical Assessment | Screen or Interview | Custom stage (requires support if >5 exist) |
| On-site Interview | Interview | Interview (default) or custom |
| Reference Check | Interview | Custom stage |
| Offer Extended | Offer | Offer (default) |
| Hired | — | Hire |
| Disqualified | — | Reject |
Jobsoid allows up to 5 stages per category (Screen, Interview, Offer) by default. If your TalentLyft pipeline has more than 5 stages in any single category equivalent, you must contact Jobsoid support to increase this limit before migration. Otherwise, your stage mapping will silently truncate.
If a candidate is in a TalentLyft stage like "Phone Screen - Technical" and no exact match exists in Jobsoid, map them to a generic stage (e.g., "Phone Screen") and append a note detailing their legacy stage using the standardized prefix format described above.
Before migrating, audit all active TalentLyft pipelines and recreate them in Jobsoid. This step is non-negotiable — the Jobsoid API (or CSV import) will reject or misplace applications if the target stage does not exist.
Migration Approaches Compared
| Approach | Fidelity | Speed | Complexity | Best For |
|---|---|---|---|---|
| CSV export → CSV import | Low | Fast | Low | <500 candidates, no history needed |
| API extract → CSV transform → CSV import | Medium | Moderate | Medium | 500–2,000 candidates, basic field preservation |
| API extract → API load | High | Slow (rate limits) | High | 2,000+ candidates, full context preservation |
| API extract → Jobsoid support bulk import | Medium-High | Varies | Medium | Large databases, when Jobsoid provides import assistance |
For most teams, the practical path is a hybrid: extract via TalentLyft API, transform into Jobsoid's CSV format for candidate profiles, import via CSV, then handle resumes and stage placement as separate operations.
GDPR and Compliance Before Migration
Before you export a single record, run a compliance audit on your TalentLyft data. TalentLyft, being EU-based, has strict built-in GDPR consent tracking — consent dates, expiration dates, and purposes. You cannot leave this data behind or ignore it.
The pre-migration compliance checklist:
- Process all pending erasure requests in TalentLyft before export. GDPR Article 17 grants candidates the right to erasure. Migrating data for candidates who have withdrawn consent is a compliance violation, not a technical inconvenience.
- Verify consent status for every candidate record. Flag records where consent has expired or been withdrawn. Exclude them from the migration payload.
- Check retention periods. Typical GDPR-compliant retention for unsuccessful candidates is 6–24 months. The French CNIL sets a default of 2 years. Records older than your retention policy should be purged, not migrated.
- Map compliance data to Jobsoid custom fields. Create fields for
Legacy_Consent_Date,Legacy_Consent_Source, andLegacy_Consent_Expirationin Jobsoid. - Confirm Jobsoid supports automated retention. Your new system must handle future erasure requests and retention expiry — verify this before committing.
- Document the migration. Maintain an audit log of what was migrated, what was excluded, and why — keyed to each candidate's TalentLyft ID. This is your defense if a regulator or candidate asks questions post-migration.
If a candidate's consent has already expired in TalentLyft, purge their PII during the transformation phase. Do not migrate expired candidates into Jobsoid, or you will immediately violate GDPR data minimization principles (Article 5(1)(c)).
For more on PII handling during migrations, see Payroll Data Migration Security Compliance, which covers similar principles.
Edge Cases That Silently Break Migrations
These are the failure modes that appear most frequently in ATS-to-ATS migrations of this type:
Multi-Job Candidates
A candidate in TalentLyft can have applications across multiple jobs, each with a different pipeline stage. Jobsoid's CSV import assigns candidates to one job per batch. If you do not handle multi-job candidates explicitly, you will either lose secondary applications or create duplicate candidate records.
Fix: Build a candidate-to-jobs lookup table before import. The deduplication strategy: use the candidate's email field as the unique key. For each email, collect all associated applicationId + jobId + stageId tuples from TalentLyft. Import the candidate profile once (unassigned to any job). Then create each job association as a separate operation — via Jobsoid's UI or API — in the order they were originally created (applicationCreatedAt ascending). This preserves chronological application history without creating ghost records.
# Build candidate → applications lookup before import
candidate_jobs = {}
for application in all_applications:
email = application["candidateEmail"]
if email not in candidate_jobs:
candidate_jobs[email] = []
candidate_jobs[email].append({
"jobId": application["jobId"],
"stageId": application["currentStageId"],
"createdAt": application["createdAt"]
})
# Sort each candidate's applications chronologically
for email in candidate_jobs:
candidate_jobs[email].sort(key=lambda x: x["createdAt"])Custom Field Type Mismatches
TalentLyft supports custom field types on both candidate profiles and application forms. Jobsoid has custom fields on jobs and candidate profiles, but the field type options may differ. A multi-select dropdown in TalentLyft might need to become a text field in Jobsoid, losing structured data.
Fix: Export TalentLyft custom field schemas via GET /v2/custom-fields. For each field, apply this decision hierarchy: if Jobsoid has an identical type, map directly; if Jobsoid has a compatible type (e.g., single-select to radio), map with validation; if no match exists, serialize to a pipe-delimited text field and document the original schema in a migration log. Never silently drop custom field values.
Source Attribution Loss
TalentLyft tracks candidate sources with granular types: Recruiter, Sourced, Referral, Paid, plus specific board names (Indeed, ZipRecruiter). Jobsoid has its own source taxonomy. If you do not create matching source values in Jobsoid before import, source data either maps to "Other" or gets dropped entirely — destroying your sourcing analytics permanently.
Fix: Export the complete TalentLyft source taxonomy, create matching values in Jobsoid before any import begins, and validate source mapping in your dry run before full migration.
Rich-Text and HTML in Descriptions
TalentLyft job descriptions and candidate notes may contain HTML formatting with proprietary CSS classes (e.g., class="tl-highlight") and occasionally <iframe> embeds for video content. Jobsoid's import may strip or misrender these. Strip all class attributes and <iframe> tags during transformation. Test a batch of 10–20 descriptions in Jobsoid's UI before running the full migration.
Attachment Filename Encoding
If resume filenames contain non-ASCII characters (accented names, CJK characters — common in any international hiring pipeline), test that Jobsoid's upload process handles them correctly. The safest approach: normalize filenames to ASCII during the staging phase using a slug function (Ana_García_CV.pdf → Ana_Garcia_CV.pdf), store the original filename in your ID mapping table, and use the normalized name for upload. Filename corruption leads to orphaned files that cannot be linked back to candidates.
Duplicate Emails
Jobsoid enforces unique email addresses. TalentLyft may contain duplicate email records — the same candidate created twice, or different candidates sharing an email (family members, shared work addresses). You must deduplicate or merge these records during the transformation phase, before loading into Jobsoid. Deduplication strategy: group all TalentLyft records by email; for duplicates, merge profile fields by preferring the most recently updated record, and union all application histories, tags, and notes. Flag merged records in your audit log with both source TalentLyft IDs. Otherwise, Jobsoid will silently reject duplicates with no error surfaced to the import UI.
Delta Sync: Keeping Data Current During Migration
Large migrations take days to complete. During that window, recruiters continue working in TalentLyft — creating candidates, moving applications through stages, adding notes. Without a delta sync, that activity is lost at cutover.
Implementation strategy:
- Record the exact timestamp when your full extraction begins (
extraction_start_ts). - Store the TalentLyft
idandupdatedAtfor every extracted record in your ID mapping table. - After the full load completes, query TalentLyft for all records where
updatedAt > extraction_start_ts:
def fetch_delta_candidates(extraction_start_ts):
"""Fetch candidates created or modified after extraction began."""
delta = []
page = 1
while True:
resp = requests.get(
f"{BASE_URL}/candidates",
headers=HEADERS,
params={
"page": page,
"pageSize": 50,
"updatedAfter": extraction_start_ts # ISO 8601 format
}
)
resp.raise_for_status()
data = resp.json()
delta.extend(data.get("items", []))
if page >= data.get("totalPages", 1):
break
page += 1
time.sleep(0.15)
return delta
def apply_delta(delta_records, id_mapping_table):
"""Upsert delta records into Jobsoid using TalentLyft ID as idempotency key."""
for record in delta_records:
talentlyft_id = record["id"]
if talentlyft_id in id_mapping_table:
# Record exists in Jobsoid — update it
jobsoid_id = id_mapping_table[talentlyft_id]
update_jobsoid_candidate(jobsoid_id, record)
else:
# Net-new record created during migration window — insert it
jobsoid_id = create_jobsoid_candidate(record)
id_mapping_table[talentlyft_id] = jobsoid_idIdempotency: Use the TalentLyft id stored in Jobsoid's external_id custom field as your idempotency key. Before creating any record, query Jobsoid by external_id. If it exists, update; if not, insert. This prevents duplicate creation if the delta sync runs more than once.
Cutover sequence: Freeze TalentLyft activity (disable login or put a notice in place), run the final delta sync, validate record counts, then redirect your team to Jobsoid. The freeze window for a delta sync of under 1,000 records should be under 2 hours at TalentLyft's rate limits.
Step-by-Step Migration Playbook
Phase 1: Audit and Setup
- Audit your TalentLyft data. Count candidates, jobs, attachments. Identify custom fields, pipeline configurations, and active integrations. Export the custom field schema via
GET /v2/custom-fieldsand document every field type. - Run compliance checks. Process GDPR erasure requests, flag expired consent, purge beyond-retention records.
- Set up Jobsoid. Create departments, job openings, custom fields, pipeline stages (request category limit increases if needed), and source values in Jobsoid before importing any data. Confirm with Jobsoid support what API write endpoints are available on your plan.
Phase 2: Extract and Transform
- Extract from TalentLyft API. Pull candidates, jobs, applications, pipeline positions, and attachments. Store everything in structured JSON. Buffer attachments in encrypted intermediate storage keyed as
candidateId/attachmentId/fileName. Recordextraction_start_ts. - Build the ID mapping table. Every TalentLyft record ID must map to its future Jobsoid equivalent. Store
talentlyft_id,jobsoid_id,entity_type, andupdatedAtfor every record. This table is the single source of truth for the entire migration (a strict requirement even in same-platform moves like Loxo-to-Loxo) — and your only way to run a delta sync without creating duplicate records. - Transform data. Convert TalentLyft's schema to Jobsoid's expected format. Handle pipeline stage translation, custom field type conversion, source mapping, phone number normalization (E.164), HTML sanitization (strip
classattributes and<iframe>tags), and filename normalization for attachments.
Phase 3: Dry Run
- Test with a small batch. Run a test migration of 50–100 candidates in a Jobsoid trial or sandbox environment, complete with jobs, applications, notes, and resumes. Log into Jobsoid and manually verify: Did the resumes attach? Are the notes readable? Are the tags correct? Are pipeline stages accurate? Do multi-job candidates have all their applications? Did source attribution carry through?
Phase 4: Full Migration and Cutover
- Load the full historical dataset. Import candidates into Jobsoid (via CSV, API, or hybrid approach). Upload attachments separately. Set pipeline stages. This can take days for large datasets due to rate limits and attachment volumes — run it while your team is still using TalentLyft.
- Delta sync and cutover. Freeze activity in TalentLyft (ideally over a weekend). Run the delta sync using
extraction_start_tsas the filter boundary. Use TalentLyftidas the idempotency key to prevent duplicates. On Monday morning, your team logs into Jobsoid, and TalentLyft is retired. - Validate and reconcile. Compare record counts between source and target. Spot-check 5–10% of records for field accuracy. Verify attachment linkage and confirm pipeline stage positions. Confirm no candidates with expired GDPR consent appear in Jobsoid.
Run the full migration in a Jobsoid trial environment first. Validate everything. Only then execute against production. A trial run exposes mapping errors, encoding issues, and rate limit behavior before they affect your live recruiting pipeline.
When to Call in Help
This migration is technically straightforward for small datasets (<500 candidates, single pipeline, no custom fields). It gets complex fast when you have:
- Multiple TalentLyft pipelines with custom stages that exceed Jobsoid's 5-per-category default
- Thousands of candidates with multi-job application histories
- Compliance requirements across multiple jurisdictions (GDPR, CCPA)
- Large attachment volumes that cannot be uploaded 10 files at a time
- No confirmed API write access on the Jobsoid side
At ClonePartner, we have completed migrations for organizations of this type and built the extraction scripts, transformation pipelines, and loading automation for ATS-to-ATS moves. We handle the rate limits, the schema mapping, the compliance checks, and the API edge cases. If you are planning a move to Jobsoid and need guaranteed accuracy, we can help.
Frequently Asked Questions
- Can I use CSV exports to migrate from TalentLyft to Jobsoid?
- TalentLyft supports CSV candidate export (delivered as a ZIP via email), but it flattens relational data. Application-to-job relationships, pipeline stage histories, activity timelines, and file attachments are not included. Jobsoid's CSV import also cannot restore pipeline positions or link resumes to candidate rows. CSV is viable only for small databases under 500 candidates where you accept losing relational context.
- Does Jobsoid have an API for importing candidates?
- Jobsoid offers API access at api.jobsoid.com, but public documentation is minimal — the known SDK surface area is around 6 methods. Contact Jobsoid support to confirm available write endpoints, rate limits, and whether bulk import endpoints exist for your plan before committing to an API-based loading strategy.
- How do I map TalentLyft pipeline stages to Jobsoid?
- Jobsoid organizes custom stages under three categories — Screen, Interview, and Offer — with a default limit of 5 stages per category. Map TalentLyft's custom stages into the closest Jobsoid category. If you need more than 5 stages in any category, request a limit increase from Jobsoid support before migration, or your stage mapping will silently truncate.
- What is TalentLyft's API rate limit?
- TalentLyft's Customer API is limited to 500 requests per minute per API token. For a 10,000-candidate database with separate requests for candidate details, applications, and attachments, expect 60+ minutes of extraction time at full throughput.
- Do I need to check GDPR compliance before migrating ATS data?
- Yes. Process all pending GDPR erasure requests in TalentLyft before export. Exclude candidates who have withdrawn consent or whose consent has expired. Verify retention periods (typically 6–24 months for unsuccessful candidates) and purge expired records rather than migrating them to Jobsoid.