Your vendor just hiked prices 4×. Their UI shows 12,420 records. Their CSV export gives you 11,903. Their API isn't documented. Their support ticket queue takes a week. You can't justify staying, but you can't justify leaving without your data either. Here's the 6-step framework we use to get every record out — cleanly, with proof.
Get a free migration feasibility auditThe vendor lock-in business model depends on one quiet assumption: that getting your data out costs more than staying. Every niche industry SaaS knows it. The customers who feel most trapped pay the most willingly — and the vendor knows you have years of customer records, jobs, invoices, notes, attachments, and workflow state stored on their servers. They also know that "export to CSV" is the bare minimum the contract required, and that the export was built to look complete without actually being complete. So when the renewal letter announces a 4× price hike, switching becomes a project that scares everyone in the room. (If your business handles EU customer data, the right to receive your data in a structured, machine-readable format is actually written into law under GDPR Article 20 on data portability.)
It doesn't have to be. The data is recoverable — almost always — through a combination of API reverse-engineering against the vendor's RFC 7231 HTTP endpoints, careful reconciliation, and a parallel-run migration. Below is the exact 6-step framework, with a real Python snippet of the kind of reconciliation pass we run before recommending any cutover. Once the data lands in your new system, the same dedup discipline from our CRM cleanup framework stops the migration from importing four years of legacy junk along with the actual records.
List every entity worth migrating: customers, jobs, invoices, files, statuses, notes, attachments.
The export's silent omissions are usually here.
Compare UI counts to CSV/API counts.
If they don't match, the export is hiding rows on purpose.
Decode hidden IDs, enum codes, and status flows.
The CSV's status_code = 7 has to become 'delivered, awaiting invoice' or your new system won't know what it means.
Use APIs, hidden reports, screen scraping, and backups to pull what the CSV export silently dropped.
Fit the recovered data into the new system cleanly.
Don't replicate the old vendor's bad shape — fix it on the way out.
Reconcile counts and samples between source and target before cutover.
The migration is only done when the totals tie.
A simplified version of the API reverse-engineering and reconciliation pass we run before any cutover.
Python · API reverse-engineering + 3-way reconciliation# 1. Reverse-engineer the undocumented "list jobs" API
def fetch_all_jobs(session, base_url, page_size=100):
page = 1
while True:
r = session.get(
f"{base_url}/jobs",
params={"page": page, "size": page_size, "include": "all"},
)
rows = r.json().get("data", [])
if not rows:
return
yield from rows
page += 1
# 2. Three-way reconcile: dashboard count vs API count vs CSV export
ui_count = scrape_dashboard_total(session) # 12,420
api_count = sum(1 for _ in fetch_all_jobs(session, API)) # 12,418
csv_count = len(pd.read_csv("vendor_export.csv")) # 11,903
assert abs(ui_count - api_count) < 5, "API drift vs UI"
assert csv_count >= ui_count - 50, "CSV missing rows — do not cut over"
# 3. Re-fetch missing rows directly from the detail-page API
missing_ids = (set(api_ids) - set(csv_ids))
recovered = [fetch_job_detail(jid) for jid in missing_ids]
print(f"Recovered {len(recovered)} jobs the CSV export silently dropped.")
This becomes urgent — not optional — if any of these is true today:
The framework above isn't theoretical — it's a checklist that runs before any commitment to a new vendor. Each gate produces an artifact: an entity inventory, a reconciliation report, an enum map, a recovered-records log, a target schema validated against a JSON Schema specification, and a final tie-out. The actual extraction usually runs through the Python requests library for the API reverse-engineering pass, with bulk loads handled by AWS Database Migration Service when the volumes get large. By the time you sign anything new, you already know what's coming with you.
Most of our migrations start the same way: a single phone call where the founder describes the renewal letter and the broken export. Within 48 hours we send back a feasibility audit — what's recoverable, what's risky, and a realistic week-by-week plan. No access to your vendor required, no commitment, no pressure. The same parallel-run, never-cut-too-fast approach we use here is the spine of our framework for migrating from DigitalOcean to AWS or Azure.
Tell us which vendor you want to leave and which entities you'd need to bring out. Within 48 hours we'll send back a clear report: what's recoverable, what's risky, what reverse-engineering the API will involve — and a realistic week-by-week plan if you decide to move.
Show me what's possible (free)