Our work / Case study

Changing the engine without the passengers noticing

A new integration platform for a live partner API, cut over while customer data moved from a legacy CRM to Salesforce, and about 50 software vendors didn't have to rebuild a thing.

  • UK regulated financial services
  • Integrations & APIs
  • Migrations

Imagine swapping the engine of a plane mid-flight, while about 50 other companies are flying their own planes in formation with yours. That was the job: a new integration platform, a CRM migration running underneath it, and a promise to every partner that nothing would change except the address.

The problem

Our client, a UK regulated financial-services organisation, publishes APIs that dozens of third-party software vendors build against. Those vendors’ products in turn serve hundreds of the client’s business customers. The APIs sat on a legacy CRM and on Salesforce, across three business lines.

The client was consolidating everything behind a single managed integration platform, moving customer data to Salesforce one account at a time, and switching off the old API addresses by a hard deadline. About 50 integrator companies’ software had been written against the legacy system’s exact responses, error formats and quirks over many years. Asking them to rebuild wasn’t an option.

Our approach

Prove it before building it. Before any build started, we produced a working proof of concept on Azure. It showed the routing and translation model end to end and became the blueprint for the platform.

An API-led design with a translation bridge. Customer-facing APIs keep each legacy contract exactly as it was. A process layer authenticates each caller and routes each customer to whichever backend currently holds their data, and a system layer talks to each backend. For customers already on Salesforce, the bridge translates legacy-format requests into Salesforce and translates the replies back, keeping the same field names, types, status codes, error shapes and status wording. The calling software never knows it’s talking to Salesforce. Everything sits behind feature flags. The design also cut the number of deployed flows by about 40%, keeping the platform within its licence.

≈50 partner software vendors: new address, same code EXPERIENCE APIs Every legacy contract kept exactly: fields, types, status codes, error shapes and wording PROCESS LAYER Authenticates each caller and routes each customer to wherever their data lives, behind feature flags SYSTEM API: LEGACY CRM Customers not yet migrated TRANSLATION BRIDGE → SALESFORCE Legacy format in, legacy format out, Salesforce behind LEGACY CRM SALESFORCE customers move one account at a time
Partners keep their contracts; the platform decides, customer by customer, which backend answers.

Treat the running system as the specification. The legacy API’s documentation didn’t match how it actually behaved. So we stopped trusting documents and fired identical requests at the old and new endpoints, comparing the results. A strictness audit found 14 rules where the new platform rejected input the legacy system genuinely accepted. They traced back to three root causes (case sensitivity, type strictness and length/format limits), so we fixed them once by normalising input rather than patching each rule.

Prove parity, repeatably. We recorded 25 reference scenarios from the legacy API. A read-only probe compares status codes, response keys and data types, never values, so it’s safe to run against production. It gave objective proof of parity before each account moved.

25 RECORDED SCENARIOS same request LEGACY API NEW PLATFORM PARITY PROBE (READ-ONLY) ✓ Status codes ✓ Response keys ✓ Data types – Values: never Safe to run against production
Same request, two systems, one read-only comparison.

Translate meaning, not just fields. The legacy system has about 85 distinct statuses. We pulled real distributions from both systems, designed a two-level mapping with an explicit decision for each case, and proved it on real records before release (12 out of 12 correct). That stopped tens of thousands of closed records being mislabelled.

Let the traffic tell you what matters. Thirty days of production logs showed that one lookup made up over 90% of calls. By correlating bursts of calls in time, we could see which partners were affected by any change, even where the logs carried no customer identifier.

Release carefully. Every production change had a dated rollback snapshot taken beforehand. Feature flags allowed instant switch-off, and deploys needed explicit sign-off.

Built with: MuleSoft Anypoint Platform (CloudHub 2.0, API Manager, RAML, MUnit), Salesforce (Apex REST, Experience Cloud), Microsoft Azure and REST/JSON, following API-led connectivity.

The result

  • The new platform is live, carrying about 8,000 partner requests a day, and the old addresses were switched off on schedule.
  • About 50 partner software vendors moved across without rebuilding their integrations. They changed an address, not their code.
  • The legacy bridge is live, so customers can move to Salesforce one at a time while partner software sees no difference.
  • The few small contract differences that surfaced at cutover were found and fixed quickly, using side-by-side testing against the legacy system.

What made it hard

“Nothing changes” wasn’t quite true. The new platform’s error format, status codes and URL handling differed from the legacy system in small ways, and small differences are enough to break partner software. The documentation hid them. Testing against the running system found them.

The “200 trap”. The legacy API returns HTTP 200 to mean “queued”, not “done”. Tests that stopped at 200 would have given about 90% false positives, so every test follows each request through to its final outcome.

Responses that only looked right. Migrated data came back with legacy field names, but numbers arrived as text, IDs were missing and paging was absent. Tests using mocked data had hidden all of it. We also stopped a blanket “convert to number” fix from stripping the leading zeros off phone numbers.

What we’d do differently

We’d record a “golden” library of the legacy system’s real responses before building, measure parity before promising partners that nothing would change, and test against real backend responses rather than mocks from the first sprint.


Planning a migration behind a live API? Book a call and we’ll talk it through.

← All work