Integrating AI with an ERP that predates the idea of an API
The model is rarely the hard part. The hard part is a finance system that will let you read anything and write nothing, and voids its support contract if you go around it.
Find out what you are actually connecting to
Integrating AI with an ERP is mostly a question of what the ERP will let you write. Read access exists in some form on almost every system. A supported write path often does not, and the answer is frequently different for each record type you care about. Until that is settled in writing with the vendor, any estimate for the work is a guess.
Before anyone estimates this work, establish what the system will let you do. There is a ladder, and the distance between its top and bottom rungs is most of the project cost. A documented, supported API with a test environment is the top. Below it, an API restricted to certified partners or to a licence tier you do not hold. Below that, a database you can read but must not write to. Then a scheduled file exchange. At the bottom, a screen with nothing behind it.
Each rung has a different cost profile and a different failure mode, and the answer is frequently different for reading and for writing. Plenty of enterprise systems will happily let you read everything and offer no supported route to write anything, which is exactly the case where a project quietly turns into a person copying output into a form.
Ask three things of the vendor in writing. What is the supported way to write this record. What happens to our support agreement if we write another way. And what changes at the next major version, since an integration built against an undocumented surface breaks on an upgrade you do not control.
- A documented API with a test environment, which is the case everyone assumes and few have
- A partner or tier restricted API, where the blocker is commercial rather than technical
- Read-only database access, where writing directly would void vendor support
- Scheduled file exchange, which is unglamorous and often the right answer
- A screen and nothing else, where automation is fragile and should be a last resort
Why the direct connection is usually the wrong instinct
The obvious design is to have the AI workflow talk to the ERP. It is also the design that ages worst, because every quirk of that system ends up embedded in the workflow, and the next system you connect gets its own copy of the same problem. Six integrations later there is no single place where you can see what talks to what.
An integration layer in between gives you three things worth paying for. One place where field mapping and translation live, so a change to the ERP is a change in one file rather than in nine workflows. One place where every message is logged, which is the difference between diagnosing a problem in an hour and arguing about it for a week. And a boundary that lets the ERP be upgraded without every automation being retested.
The honest counterweight is that middleware is a system too. It needs hosting, monitoring, credentials, someone who understands it, and a plan for when it is the thing that fails. For two well behaved systems exchanging one kind of record, a layer is overhead with a maintenance bill attached.
Middleware earns its place at about the third integration, or the first one where the system underneath is difficult.
Batch or real time, decided by what is waiting
The question is not which is more modern. It is what decision is waiting on the data. If a person or a customer is on the other end expecting an answer now, that is real time. If the output feeds a report, a reconciliation or a queue somebody works through in the morning, batch is cheaper to build, easier to re-run when something goes wrong, and simpler to audit, because a batch has boundaries and a stream does not.
Most requests for real time turn out to be requests for something faster than the current overnight cycle. Hourly is not real time and it satisfies a surprising number of these, at a fraction of the complexity. Ask what happens if the data is twenty minutes old, then an hour, then a day. The answer usually names the actual requirement, and it is often narrower than the request.
A hybrid is common and sensible. Real time for the few events where someone is waiting, batch for volume and for anything that has to reconcile. Deciding per data flow avoids paying real time complexity across everything to satisfy one screen.
- Real time where a person or customer is waiting on the answer
- Batch where the output feeds a report, a reconciliation or a morning queue
- Ask what breaks if the data is an hour old, then a day, before committing to real time
- Decide per data flow rather than once for the whole project
Idempotency, retries and the duplicate invoice
Every integration meets this eventually. A call is made, the receiving system processes it, and the response is lost on the way back. The sender sees a timeout, retries as designed, and now two records exist. In a reporting system that is an annoyance. In a finance system it is a duplicate payment, and it will be found by someone outside your team.
The fix is to make repeating an operation harmless. Give every message a stable identifier derived from the record itself rather than from the moment it was sent, so a retry carries the same identifier as the original. Have the receiving side check that identifier before acting, and update rather than insert when it has seen it before. Where the target cannot do that, put the check in the integration layer.
Assume delivery is at least once rather than exactly once, because almost every queue and webhook in practice offers the former. Design so that processing the same message twice produces the same end state as processing it once. Then log every retry, because a rising retry count is usually the earliest visible sign that something downstream is degrading.
- A stable identifier per operation, derived from the record rather than the timestamp
- The receiver checks that identifier and updates instead of inserting a second copy
- Assume at least once delivery and make repeat processing produce the same end state
- Log retries, and alert when the rate rises rather than when it fails completely
When two systems each believe they hold the truth
This is the problem that outlasts the build. The CRM and the ERP both hold a customer address. Both can be edited. Both are correct according to somebody. Six months later nobody can say which is authoritative, and the reports disagree in a way that gets described as a data quality issue rather than the design decision it actually is.
Declare a system of record per field, not per system. The ERP may own the account number and the credit terms while the CRM owns the contact name and the communication preference. Write that down as a table, one row per field, with a direction of flow and an owner. It is a boring artefact and it is the single most useful document in an integration project, because it converts a future argument into a decision that was already made.
Then decide what happens on conflict, deliberately. Last write wins is a legitimate choice and a terrible default, because it silently discards a correction somebody made for a reason. The alternative is to detect the disagreement, hold it, and put it in front of a person. That means a scheduled reconciliation comparing both sides and reporting differences, with a named owner who works the list.
Where a field is genuinely edited in both places by different teams for different reasons, the honest answer is sometimes that the process needs changing rather than the integration. Two teams maintaining the same field is an organisational decision that predates the technology, and no amount of synchronisation logic resolves it.
One table, one row per field
Which system owns this field, which direction it flows, what happens on conflict, and who resolves it. Writing that table before the build converts the most common future argument into a decision already taken.
What the work costs, and the case for leaving a system alone
Integration is normally a scoped project with a defined end. You are buying a finite set of connections, documented and handed over, with least privilege credentials and every failure mode handled explicitly. What follows is smaller: a support arrangement for the months when a supplier changes a field or a certificate expires, sized once the system exists.
Three things move the number, and none of them is the count of workflows. How many systems have to be connected and where each sits on the ladder above, since one application with no supported write route can cost more than everything else combined. Whether the process is documented, or has to be mapped from how people actually work, which is a phase of its own.
And how many exceptions the process really has, because exception handling is most of the build and is always underestimated by whoever wrote the original brief. Anyone quoting before walking the process end to end and listing every system it touches is quoting a sales number, so ask to see the list.
Now the case nobody makes. Some systems should be left alone. If an application is scheduled for replacement within the year, integrating with it is buying something with a known expiry date. If the volume through a connection is low, the arithmetic may never justify the build, and counting first is cheaper than finding out afterwards.
There is also the support question. Where the only technical route in would void a vendor's support agreement, that constraint is usually worth more than the automation, because the day the ERP breaks is not the day to discover the contract does not apply. A file exchange running twice a day, ugly and supported, beats an elegant integration that voids your cover. And where a system has no documented write interface, treat it as read-only until write access is confirmed.
The week that decides everything, and who signs off a write
The first week of one of these is not building. It is establishing what your finance system will actually permit, which is rarely what the sales page claims and occasionally the opposite of what the vendor says on the phone. Read access with no write. Write access that voids a support contract. An export that runs nightly and cannot be triggered on demand. That week is the audit, and the roadmap it produces is yours whether or not you go on to build with anybody.
After that the first system is live inside a fortnight, and it is deliberately the smallest useful one: a single read, a single write, one batch, watched. Nobody should be six months into an ERP integration before finding out whether the write lands correctly.
Writes into a system of record get a person in front of them for as long as it takes to trust the mapping. In practice the machine prepares a batch, a person approves it, and that human approval step is dropped only once the exception rate has become boring. Anything the integration cannot map confidently waits for a person instead of guessing at a code, because a guessed cost centre is worse than a queue.
Wobble has published three custom ERP systems built for RM Gulistan Engineers in Karachi, covering accounts, human resources and inventory, which is the closest thing on the work page to this problem. Moiz Khan leads architecture on integration work. Doing it in-house is often correct when your ERP vendor employs the only people who understand the schema, and the useful engagement then is the mapping and the reconciliation layer rather than the whole build. What it costs turns on how many exceptions exist and how much of the reconciliation currently lives in one person's head. Credentials stay in your own accounts throughout, and Wobble remains accountable for what it connected.
Common questions
How do you integrate AI with an ERP that has no modern API?
Establish what the vendor supports before designing anything. Options run from a documented API, through a partner restricted one, read-only database access, scheduled file exchange, and finally screen level automation. Ask in writing what the supported write route is and what writing another way does to your support agreement.
Do we need middleware, or can the workflow talk to the ERP directly?
A direct connection is fine for two well behaved systems exchanging one kind of record. A layer in between earns its cost at around the third integration, or the first difficult one, because it centralises field mapping, logs every message, and lets the ERP be upgraded without retesting every automation.
Should the integration be batch or real time?
Decide by what is waiting on the data. Real time where a person or customer expects an answer now. Batch where the output feeds a report, a reconciliation or a morning queue, since batches are cheaper, easier to re-run and simpler to audit. Most real time requests are satisfied by hourly.
How do you stop an integration creating duplicate records?
Give every operation a stable identifier derived from the record rather than the send time, have the receiver check it and update instead of inserting, and assume delivery is at least once rather than exactly once. Then log retries and alert on a rising rate, since that is the earliest sign of trouble downstream.
What do you do when two systems disagree about the same data?
Declare a system of record per field rather than per system, written as a table with a direction of flow and an owner for each row. Then decide conflict behaviour deliberately, run a scheduled reconciliation that reports differences, and give the list a named owner. Last write wins is a choice, not a default.
When should we not integrate a system at all?
When it is due for replacement within the year, when the volume never justifies the build, or when the only technical route in would void the vendor's support agreement. A twice daily file exchange that is supported beats an elegant integration that removes your cover on the day the system breaks.
See where this applies to your business
The AI Readiness Call is a short, free conversation about where automation would actually pay back in your business. The call is free. The diagnosis is not.
Book AI Readiness Call ↗