SYSTEM NOTE
Why enterprise integrations are harder than the API documentation suggests
The documentation describes the happy path against a system you do not control, cannot test against, and will be debugging weeks after the failure.
Every enterprise integration looks straightforward in the documentation. There is an endpoint, a payload format, an authentication scheme. A day's work, maybe two.
Then you start, and the difficulty turns out to be somewhere else entirely.
You cannot iterate against production
Consumer API development has a rhythm: send a request, read the error, adjust, repeat. It is fast because the feedback loop is fast and the counterparty is built to be developed against.
Enterprise systems are usually not. There may be no sandbox. The system may be a live procurement network, an access-control database with safety implications, or an ERP that the business runs on. You do not experiment against any of those.
Which means correctness has to be established before transmission rather than discovered after it — local validation, schema checking, a preview of exactly what will be sent. Every check you can perform locally is worth several performed remotely.
When we built the SAP Ariba connector, that was the whole design: generate the cXML, validate it locally against the expected structure, show a human the exact payload, and only then send.
Strict protocols do not help you
REST APIs are mostly forgiving. Extra fields are ignored, errors are descriptive, there is usually a hint about what was wrong.
Enterprise B2B protocols are not built that way. cXML is versioned and schema-driven: a document conforms or it is refused, and the refusal tells you much less than you want. There is no partial credit and no helpful error body.
The adjustment is to stop treating the payload as a serialisation detail and start treating the document as the unit of work. Once you do, validation, preview and history become the obvious three features rather than nice-to-haves.
The real work is reconciliation
Here is the thing the documentation never covers: two systems model the same reality differently, and the difference is where all the time goes.
An access-control database models credentials. An HR directory models people. A person may have two credentials. A badge reported lost may still be in use. Contractors exist in one system and not the other. Somebody left in March and their record was updated in one place.
The transport is trivial. Deciding what your system does when the two sources disagree — and they always disagree — is the actual engineering, and it needs explicit handling for each case rather than a join that assumes cleanliness.
Failures are investigated late
Nobody notices missing supplier data immediately. Nobody notices that attendance stopped reconciling. Someone notices weeks later, and asks what happened.
At that point you either have a record of what was sent and what came back, or you have nothing. Push history is worthless on the happy path and the only thing that matters when the question arrives. Build it before you need it, because you cannot build it retroactively.
What I do differently now
- Validate locally before transmitting, always.
- Make the payload inspectable by a human before it goes.
- Log every exchange durably, including the response.
- Model the disagreement cases explicitly rather than assuming clean joins.
- Read from systems of record; avoid writing to them where possible.
- Treat protocol versions as load-bearing rather than as a detail.
None of that is clever. All of it is the difference between an integration that is diagnosable and one that is a mystery.