Every insurance provider sells "a quote". On paper they share a domain. In practice, each one has its own idea of what a quote request is, what an offer contains, and what "no" looks like.
In 2022–2023 I owned the integration layer for a specialty insurance product covering roughly thirty business verticals. To give a customer comparable offers, someone had to gather them from several providers by hand: open the portals, copy the fields, and assemble something a broker could stand behind. A typical round took about fifteen minutes. The people doing it weren't slow; a human was simply on the critical path.
The goal was to make quoting a product capability. A request goes in, comparable offers come out, and nobody acts as the router.
Same domain, different dialects
I integrated several providers over the life of the product. They agreed on the business and on almost nothing else:
- Protocols. REST, JSON, and SOAP showed up in different combinations — separate API surfaces, not one shared contract.
- Language. Some APIs and their documentation weren't in English, and their concepts didn't always map one-to-one onto ours.
- Documentation. Sometimes it was thin or missing, so I had to reverse-engineer behaviour from real responses.
The tempting move is to start coding the first integration and generalise later. That usually gives you a "common model" that is really provider #1's model with extra fields bolted on.
Understand before you abstract
The order of work mattered more than the code.
1. Learn the language of the domain. I talked to brokers and worked with our product manager as the domain expert. The hardest part wasn't technical. It was translation: working out whether a provider's term meant the same thing as ours, or something subtly different. That vocabulary became our ubiquitous language, and every later decision built on it.
2. Collect as much real data as possible. I gathered documentation, sample requests and actual responses for every provider.
3. Put the payloads side by side. Comparing them field by field showed which differences were essential to the business and which were just one provider's quirk. Only the essential differences were allowed into the core model.
The abstraction
Three layers came out of that work:
- A core model of the quote request and the offer, written in the product's language rather than any provider's.
- One adapter per provider. Each adapter translates the core model to its provider's protocol and vocabulary, and back again. SOAP envelopes, foreign field names and undocumented edge cases all stay inside the adapter. Each provider is effectively its own bounded context, and its adapter is the anti-corruption layer that keeps its quirks out of the core. Martin Fowler's Gateway pattern covers the mechanics.
- Per-vertical configuration and mapping, so supporting a new line of business didn't mean writing new code paths.
The tradeoffs
The harder decisions were about what to leave out.
- The core model is not the union of every provider's fields. A field earned its place only if the business needed it to compare offers. Everything else stayed in the adapter, even when two providers happened to share it.
- Adapters were allowed to be ugly. Each one absorbed its provider's complexity so the core could stay simple. Ugly code in one well-tested place beats clean code with leaky concepts everywhere.
- Unclear verticals went back to the domain experts. Some lines of business weren't sharply defined, even internally. Guessing in code would have baked that ambiguity into the model, so full coverage meant more conversations, not more conditionals.
What made it pay off
The payoff compounded. Each integration made the next one easier, because the model was already settled and each new provider was "just" another adapter. I owned the integration layer and delegated the front-end work to a separate team, so the boundary between them stayed clean.
Typical offer gathering went from about fifteen minutes of manual work to about five seconds in the product flow, across roughly thirty verticals. It ran in production without surprises.
Why this matters more now
The most valuable output of this work wasn't the adapters themselves. It was the structured knowledge behind them: a documented glossary, side-by-side payload mappings, and real examples captured as test fixtures and code.
That is exactly what makes AI useful in engineering today. Give a coding assistant a clean domain model, one good adapter as a worked example and real provider payloads, and the next integration comes together far faster. Without that groundwork, AI just produces confident guesses at speed. Writing the domain down, in a structured format or in code, is what turns AI from a guesser into a multiplier.
The pattern is not about insurance
The same shape shows up anywhere you integrate with parties that share a domain but not a dialect: payment providers, logistics carriers, marketplaces, or industry data standards in AEC. The method carries over:
- Learn the domain language from the people who live in it.
- Collect real payloads and compare them side by side.
- Model your own concepts, and let only the essential differences in.
- Put each outside party behind its own adapter.
- Let the second and third integrations prove the abstraction.
