Integration is a contract, not a connection.
Two systems exchanging data need agreement on more than a protocol: which side owns the record, what a field means on each side, what happens when a value has no equivalent, how often the exchange runs, and what "successful" means. Written down, that is an interface contract. Left unwritten, it is a set of assumptions that only surface when they disagree.
The failure path is the part that gets skipped.
The happy path is straightforward and usually built first. What is left for later, and then never done, is the behaviour when the far end is down, when a message is malformed, when the same message arrives twice, and when a batch half succeeds. Integrations that lack this do not fail loudly; they fail quietly and reconcile wrong.
We design the contract, then build to it.
A map of the systems and what genuinely needs to flow between them, an interface contract per flow with ownership, field mappings and volumes, a decision on pattern per flow rather than one pattern everywhere, then build with retries, idempotency, dead letter handling and alerting designed in. Monitoring is part of the deliverable, not an afterthought.
What you are left with.
Documented interfaces somebody else can maintain, a mapping catalogue that matches what is running, error handling that surfaces problems to a person who can act, and a view of interface health that does not depend on somebody noticing a number looks wrong.

