Case Study: Integrating Two SaaS Platforms Without Creating Tight Coupling
Two SaaS products both exposed APIs.
At first glance, the integration seemed straightforward: retrieve data from one platform and send it to the other.
The complication was the equipment data behind those APIs.
The source platform was specialized around the physical equipment and its measurements, while the receiving platform had its own domain model, identifiers and way of representing the data.
So the real architecture was not:
SaaS A → SaaS B
It was:
specialized equipment → SaaS A → integration → SaaS B
That distinction matters.
The API was not the contract
Both SaaS providers had APIs, but their APIs represented different models of the world.
An asset could have one identifier in the source system and another in the receiving system. A measurement could have different naming, units or metadata. Historical data and current data could also have different semantics.
Simply forwarding JSON between the two systems would have created a fragile dependency on both vendor models.
A change in one SaaS platform could then directly affect the other.
The architecture therefore needed an explicit integration boundary.
SaaS A
│
│ vendor data model
▼
┌────────────────────┐
│ Integration │
│ │
│ mapping │
│ validation │
│ identity │
│ error handling │
└─────────┬──────────┘
│
│ target data model
▼
SaaS B
The integration layer becomes the place where the two external models are deliberately translated rather than accidentally coupled.
Identity was one of the harder problems
The physical asset is the real-world object, but both SaaS systems maintain their own representation of that object.
That creates a basic architectural question:
What is the authoritative identity?
Without an explicit answer, the integration ends up depending on assumptions such as matching names or carrying vendor-specific IDs throughout the application.
A stronger design treats identity mapping as an explicit part of the integration.
For example:
Physical asset
│
├── Source-system ID
│
└── Target-system ID
The integration can then maintain the relationship without pretending that the two external systems have the same domain model.
Avoid turning the consumer into a vendor client
Another temptation is to put all the vendor-specific logic into the consuming application.
That may be quick initially:
Application
│
├── SaaS A API logic
├── SaaS A authentication
├── SaaS A data mapping
└── SaaS A error handling
But now the application has become a client of the vendor’s implementation details.
A cleaner architecture isolates that dependency:
Application
│
▼
Internal integration contract
│
▼
Vendor-specific adapter
│
▼
SaaS A
The same principle applies to the second SaaS platform.
The integration absorbs vendor-specific differences so the rest of the solution does not have to.
External systems also define your failure model
A SaaS integration cannot assume that both platforms are always available.
There can be:
- API throttling;
- temporary outages;
- authentication failures;
- incomplete responses;
- changed schemas;
- delayed measurements;
- duplicated messages.
That means resilience needs to be considered at architecture level.
Retries, idempotency, observability and reconciliation are not merely implementation details when the integration is responsible for moving business-critical equipment data between independently operated platforms.
For example, retrying a failed write without an idempotency strategy can create duplicate records.
Likewise, successfully processing today’s data does not prove that yesterday’s data was complete.
The architecture therefore needs a way to detect and recover from gaps.
The trade-off: direct integration vs. abstraction
The architectural decision was essentially between two approaches.
Direct
SaaS A ───────────────► SaaS B
Simple and fast, but tightly coupled.
Explicit integration boundary
SaaS A
│
▼
Integration layer
│
▼
SaaS B
More components, but much clearer control over mapping, identity, resilience and ownership.
The second approach introduces additional architecture and operational responsibility. That cost only makes sense when the integration is important enough, expected to evolve, or likely to support more consumers.
That is the important decision—not whether an abstraction is fashionable.
The HLD decision
At HLD level, the key decisions are about the boundaries:
Which system owns the source data?
Which system owns the target representation?
Where is identity mapped?
Where does transformation happen?
Who owns the integration?
How are failures and data gaps detected?
How much vendor-specific logic is allowed to leak into the consuming application?
The Technical Design can then work out the API endpoints, authentication configuration, mapping implementation and deployment details.
Key insight: Two APIs make communication possible. They do not make the systems decoupled. The architecture has to create the boundary between the two vendor models deliberately.