System integration

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.

Three or more of these and the problem is not a missing connector. It is that nothing between the systems has an owner, a contract, or a way to fail loudly.

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.

  1. Three systems, three versions of one orderA named system of record per field
  2. A duplicate nobody can traceIdempotency keys and capped retries
  3. Upstream shipped and the flow brokeContract tests at the boundary
  4. An empty file treated as zeroArrival checks before anything is applied
  5. A person re-keying every morningA flow, replacing the person
  6. Failures sitting in a log nobody readsAn error queue with a named owner
Left is what the business reports. Right is the mechanism that was never built. The row you recognise tells you which mechanism to ask about first.

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

Points 03, 04 and 05 are where a message gets quietly mangled rather than visibly lost. Point 02 is the part that is easy to buy, and buying it settles none of the other four.

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.

Point to pointOften right

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.

Point to pointStops being right

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.

Middle layerEarns its place

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.

Middle layerThe cost

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.

  1. 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.

  2. 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.

  3. 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.

This gets decided per flow, not per estate. An estate that ends up running all three at once is a correct outcome rather than a compromise.

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.

This list gets written for your specific flows during the Week 1 audit. Two calls, a fixed fee, and you keep the one-pager whether or not the rest of the work goes ahead.

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

The problem01

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 mechanism02

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 effect03

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.

The limit04

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

20+Companies delivered forFounded in 2023, based in Pune, delivering across India, APAC and the US.
6 weeksMedian to first production artefactNot a diagram of the target architecture. A flow moving real records with its tests attached.
Week 3Software a real user can open byEarly enough that your team can disagree with us while disagreeing is still cheap.
ThreePeople in the pod, no benchThe people on the calls are the people writing the flows and carrying the pager.

What the first six weeks look like on an integration

Three phases, always. The interesting decision is which flow gets picked first.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

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.