The ERP says shipped, the CRM says pending, and the shop floor is still building it
Operational integration between the systems people type into all day, not analytical pipelines. We settle in writing which system is allowed to be right about each field, choose honestly between point to point and a middle layer, make redelivery of the same message harmless, and put failures in a queue a named person works rather than a log nobody opens. Upstream changes then break a test instead of a customer.
- Companies delivered for
- 20+
- Median to first production-grade artefact
- 6 weeks
- Software a real user can open
- By week 3
- Team on a build
- Pod of three, no bench
- Published case study for this pillar
- None yet
Signs the systems have stopped agreeing about the same record
Nobody books a call about integration. They book a call about one order that three systems describe differently, and a customer who has noticed.
The ERP, the CRM and the shop floor each hold a different version of the same order
Sales quotes one status, production works from another, finance invoices from a third. Everybody is reading their own screen correctly. The screens disagree, and the argument gets settled by whoever is most senior in the room.
A duplicate went out and nobody can say which system sent it
The same invoice, the same dispatch note, the same notification, twice. The retry that produced it looked like a success in every log you have, because from the sending side it was one message, sent once.
The integration works until the upstream team ships on a Friday
A field is renamed, a code list gains a value, a payload gains a level of nesting. Nothing was announced, because from where that team was standing nothing looked breaking.
The file arrived but was empty, and everything downstream treated that as zero
Zero sales, zero stock, zero open jobs. The job reported success, no alert fired, and the first person to notice was outside the company.
A person re-keys the same record into two systems every morning
Somebody's first hour is spent being a message bus. When they are on leave the two systems drift, and the drift is found weeks later by somebody else, in a reconciliation.
Failures go to a log, and the log has no owner
There is a queue somewhere with failed messages in it. Nobody's job description includes reading it, so it gets read after an escalation rather than before one.
Each symptom is a missing mechanism, not a missing connector
Connectors are the part that is easy to buy. What is usually missing is one of these mechanisms, and the symptom tells you which one.
- Three systems, three versions of one orderA named system of record per field
- A duplicate nobody can traceIdempotency keys and capped retries
- Upstream shipped and the flow brokeContract tests at the boundary
- An empty file treated as zeroArrival checks before anything is applied
- A person re-keying every morningA flow, replacing the person
- Failures sitting in a log nobody readsAn error queue with a named owner
What one message has to survive on the way across
Integration reads as plumbing until you follow a single record end to end. Each of these five points is somewhere it can be lost, duplicated or quietly mangled.
- 01
Emitted
Something happened in the source system. The first question is whether that system can tell you it happened at all, or whether you are going to have to go and look on a schedule.
- 02
Carried
A queue, a topic, an API call, or a file on a server. This is the part integration products are sold on, and it is the part with the fewest decisions in it.
- 03
Understood
The payload is checked against a contract before anything acts on it. A field that changed shape is rejected here, where it is cheap, rather than three systems later where it is not.
- 04
Applied
The receiving system changes. This is where a second delivery of the same message either does nothing or creates a duplicate invoice, and which of those happens was decided months earlier.
- 05
Acknowledged, or parked
Success is recorded so the work is not repeated. Failure goes somewhere a person will actually look, with the payload attached, and can be replayed once the cause is fixed.
Point to point, or a middle layer, and when each is honestly right
Both answers are defensible. The wrong one is expensive in a way that takes a long time to become visible.
Two systems, one direction, a stable contract
If you have two systems, one flow, and no plan to add a third, a direct connection is the honest answer. Fewer moving parts, easier to debug at seven in the morning, and a middle layer here would be a tax with no service attached.
When the connections start multiplying
Each new system adds connections rather than one connection. The tell is not the count. It is the day somebody asks which flows would break if a field were renamed, and nobody can answer without opening code in four repositories.
When you need one place to see what moved
A broker, a hub or a small integration service gives you routing, retries, replay, and one screen where every message can be seen. That visibility is usually the real reason to build it. The routing is the easy part.
It is a system, and systems need owners
It needs deployment, monitoring, someone on call and a version story of its own. We will say plainly when an estate is not large enough to pay that back, because an unowned hub is worse than the point-to-point flows it replaced.
Events, batch, or the nightly file drop nobody wants to touch
The question is never which of these is modern. It is how stale the receiving system is allowed to be, and who is harmed while it is.
- Events
When staleness costs something measured in minutes
Stock sold twice, a credit limit checked after the order was taken, a dispatch that leaves before the cancellation lands. Events are worth their complexity when the gap between two systems is where the money leaks. They also bring ordering and duplicate handling with them, and that is real work rather than a checkbox.
- Batch
When the receiving system only acts once a day anyway
If the finance run happens overnight, a stream feeding it changes nothing except your operational burden. A well-instrumented batch job, with a completion check and an alert when it does not finish, is frequently the correct answer and a great deal cheaper to run and to staff.
- The file drop
The nightly file that has run for years
It is easy to be rude about it. It has also run for years, the operations team knows its shape, and the person who wrote it may have left the industry. We do not remove it because it is old. We put an arrival check, a row count check and a named owner around it, and we replace it when there is a reason beyond taste.
The rules that stop the second delivery becoming a duplicate invoice
Retries are not optional, because networks fail halfway through an operation. Everything on this list exists so that a retry is boring.
Every message carries a key the receiver recognises
The receiving system records what it has already applied and matches on that key. Applying the same message twice then changes nothing, which is the property that makes automatic retries safe in the first place.
Retries back off, and they stop
An immediate retry loop against a system that is already struggling is an outage you caused. Delays widen, attempts are capped, and whatever is left after the cap goes to the error queue rather than round again.
Ordering is stated, not assumed
Two updates to the same order can arrive in the wrong order. Either the receiver refuses anything older than what it already holds, or we write down plainly that this flow does not need ordering, and why.
Late arrivals have a decided destination
The record that turns up after the period closed goes somewhere agreed in advance, with somebody told. Silently dropping it and silently applying it are both wrong, and the second is worse, because it moves a number that was already signed off.
Empty and partial count as failures until proved otherwise
A file with no rows, a response with an empty list, a payload cut short. Each needs a check before anything downstream reads it, because zero is a value the rest of your estate will happily believe and act on.
One bad message cannot stop the queue
A single malformed record should not hold up everything behind it. It gets parked, the queue keeps moving, and the parking is visible on a screen rather than inferred from a gap in the numbers.
What happens when a message fails, in order
The difference between an integration people trust and one they work around is almost entirely what happens after something fails.
- 01
It fails loudly, in one place
The failure is recorded with the payload, the destination, the attempt count and the reason. Not a stack trace in a log file. A row somebody can read without being an engineer.
- 02
It is retried, within written limits
Transient failures resolve themselves. The retry policy is written down per flow, so nobody has to guess whether a message is still in flight or gone.
- 03
It lands in an error queue with a named owner
Not a team. A person, with a deputy for when they are away. An error queue with no name against it is a log with extra steps and a nicer interface.
- 04
Somebody is told, on a channel they actually watch
The alert says which flow, which record, and what a human is expected to do about it. Alerts that report only that something went wrong get muted, and then the queue is unwatched again.
- 05
It is fixed, then replayed
Replay is built at the same time as the flow, not added after the first incident. Reprocessing is safe precisely because of the idempotency rules above.
- 06
The cause goes back into the contract
If a payload shape broke the flow, the contract test is updated so the same shape breaks a build next time instead of breaking a customer.
The system of record decision is yours, and it cannot be skipped
This is the one part of an integration project that is not a technical decision, and it is the part that stalls most of them.
What the question actually is
For every field that lives in more than one system, one system has to be allowed to be right. Not usually right. Right, so that when two values disagree there is no discussion about which one wins.
Until that is decided, an integration can only move the disagreement around faster than before.
Why we cannot decide it for you
Whether the warehouse system or the ERP owns stock on hand is a decision about how your business runs and who is accountable when the figure is wrong. We can set out the consequences of each answer, show what breaks either way, and write down what we would choose and why. Signing it is yours.
What we do once it is decided
The other copies stop being second opinions. They go read-only, or they are switched off, or they are kept and clearly marked as a copy with a staleness people can see on the screen.
What we will not do is leave two systems both able to write the same field and hope the flows keep them level. That is the arrangement that produced the problem you called about.
Contract testing, so an upstream change breaks a test instead of a customer
The most common way a working integration stops working is that somebody upstream made a change they had every reason to believe was safe.
Nobody upstream knows you are there
The team that owns the source system has a roadmap and no list of who consumes their payloads. From where they stand, adding a field or tightening a validation is not a breaking change. From where you stand it can be.
The contract is written down and executed
The shape each side depends on becomes a test that runs in both builds. Required fields, types, code lists, and what is allowed to be absent. It is not a document, because documents do not fail a pipeline.
The break moves to where it is cheap
The change fails a build on a Tuesday afternoon, with a named owner and the reason attached, instead of arriving on a Friday evening and being discovered by whoever answers the phone on Monday.
Where the upstream is not yours to change
Third-party APIs and vendor systems will not run your tests. There we check payloads against the contract in flight, quarantine what no longer matches, and alert instead of quietly coercing it into shape. That is a weaker guarantee, and we say so rather than imply otherwise.
Why a pod of three moves quickly on this
Integration work has always been mostly reading: undocumented payloads, exception branches nobody wrote down, and the reason one field carries two meanings. That reading is the part that has changed.
- Already built
Patterns that have run in production
Idempotent receivers, retry and back-off policies, error queues with replay, arrival checks and contract test harnesses. Fitted to your systems rather than written again from an empty repository.
- AI first pass
Reading payloads nobody documented
Claude reads sample messages, legacy interface code and the exception handling, then drafts the candidate contract and flags what it could not explain. The flags are where we start asking questions.
- AI first pass
Drafting the tests alongside the flow
Contract tests and reconciliation checks are generated from the agreed contract, so the thing that proves the integration is built with it rather than after it, when nobody has budget left.
- Human call
Ownership, ordering and what is allowed to be quiet
Which system owns which field, whether a flow needs ordering, what a late arrival does, and which failures may pass without waking anyone. Those decisions make an integration trustworthy, and they stay with the engineer.
- What you keep
Yours to run without us
Contracts, tests, runbooks and the error queue, in your repositories. We are an Anthropic Build Partner and joined the Claude Partner Network at launch, so we build on Claude directly with no reseller sitting in between.
What we have actually delivered
There is no named integration case study on this site yet, so these are firm-wide delivery figures. We will say on the call which of them came from work that looked like yours.
What the first six weeks look like on an integration
Three phases, always. The interesting decision is which flow gets picked first.
- Week 1
The audit, fixed fee
Two calls, and one real record followed end to end across every system that touches it. You get a one-pager naming the flows, who owns which field, the mechanisms that are missing and the order to fix them in. Yours whether or not we go further.
- Week 2
One flow is chosen, and it is not the easy one
We take the flow that carries real transactions and causes real arguments, because that is where the payback shows and where the team will notice the difference. The demo-friendly flow teaches you nothing about whether the design holds.
- Week 3
Something runs
The flow moves real records, with its contract test, its error queue and its replay path attached. This is the week a wrong assumption about ordering or ownership surfaces, when correcting it costs a conversation rather than a rebuild.
- Weeks 4 to 6
It runs alongside, then takes over
The new flow runs beside the current path and the outputs are compared before anyone depends on the result. Switching is then a configuration change rather than a weekend and a war room.
- Week 7 onwards
Operate
Quarterly reviews and on-call governance. Somebody answers when the error queue fills at seven in the morning, and the fix goes back into the contract rather than into a workaround.
Questions operations and platform teams ask us
The ones that come up on almost every first call about this work.
Should we just buy an integration platform?
Often yes, and we will say so. A packaged platform earns its keep when you have many similar flows and a team to run it. It stops being the answer when your hard problems are ownership, ordering and late arrivals, because a platform decides none of those for you. You will still be writing the same rules, only inside somebody else's product.
Is this not the same as your data engineering work?
No. Data engineering there means analytical pipelines feeding reporting and models, where being an hour behind is usually acceptable. This is operational integration between systems people type into, where being an hour behind means a customer was told something untrue. Different failure modes, different tests, and a very different tolerance for being wrong.
We have a nightly file that has run for years. Do you want to replace it?
Not by default. It works, the operations team knows its shape, and the risk of replacing it is real. What we usually do first is put an arrival check, a row count check and a named owner around it, so an empty file stops being read as zero. Replacement comes later, if there is a reason beyond taste.
How do you actually stop duplicates?
Every message carries a key, and the receiving system records that key once it has applied the message. A second delivery of the same key then changes nothing. Retries back off and are capped, and what does not succeed goes to an error queue with an owner rather than round the loop again.
Who decides which system is the master?
You do. Which system is allowed to be right about stock on hand, or a customer balance, is a decision about accountability rather than about software. We set out the consequences of each answer and write down what we would choose. Until it is signed, an integration can only move the disagreement around faster.
Our upstream team ships without telling us. Can anything be done about that?
Where the upstream is one of your own teams, the contract becomes a test that runs in both builds, so their change fails a build instead of failing your Friday. Where it is a third party who will not run your tests, we check payloads in flight, quarantine what no longer matches and alert. That is a weaker guarantee and it is honest to call it one.
Can we run this without hiring anyone new?
That is the design constraint from the first week. The flows use a stack your team can hire for, the error queue is a screen rather than a log, and the runbook says who is called and what they do. If we build something only we can operate, we have failed at the part that matters.
You have no case study for integration. Why should we believe you?
Because we told you, rather than putting an analytics result on this page and hoping you did not check. Our published cases belong to other disciplines and would tell you nothing about your order flow. What we offer instead is Week 1: two calls, one real record traced across every system that touches it, and a one-pager you keep either way.
Is AI writing our integrations?
No. AI does first passes, reading undocumented payloads and drafting contracts and tests, and every one is reviewed by the engineer who owns that flow. The decisions that make an integration trustworthy, which system owns a field, whether ordering matters, what is allowed to fail quietly, are made by the people whose names are on the work.
What happens when it breaks after you have gone?
The error queue has a named owner and a replay path, the contract tests run in your pipeline, and Week 7 onwards is quarterly reviews and on-call governance if you want them. That is a service you can stop, not a dependency you are stuck with.
The rest of the practice
These are genuinely different jobs with different ways of failing. Most engagements start in one of them.
- Data engineeringJobs that finish, migrations that reconcile, and storage that stops paying for cold data.
- Data integration and governanceOne set of records the finance team and the operations team both accept.
- Data platforms and modernisationOff the platform you outgrew, without a twelve-month freeze on new reporting.
- Apache SupersetSuperset built and run by people who commit to the project, including embedding and Kubernetes.
- Command centresThe one screen an operations floor runs the day from, not another dashboard.
- AI evaluationA graded eval set, because an AI system cannot simply pass or fail a test suite.
- AI governanceGovernance you can defend in a board meeting and audit on demand.
- AI agentsOne reasoning agent on Claude, on your live data, with evidence and a kill switch.
- Data agentsAgents that watch the data, flag what moved, and explain what is driving it.
- AI use case, guaranteedOne production agent in eight weeks, or you do not pay for the build.
- Applications and automationThe system your team works in all day, built or replaced in slices.
- Application modernisationThe system nobody wants to touch, replaced a slice at a time rather than rewritten.
- Process digitisationThe process that still runs on paper, WhatsApp and one shared spreadsheet.
Start with the Week 1 audit
Two calls, a fixed fee, and one real record followed end to end across every system that touches it. You get a one-pager naming the flows, who owns which field, and the order to fix things in. It is yours whether or not we build anything. NDA-friendly, fixed scope. hello@woodfrog.tech, Pune.