How to Connect CRM, Website, Warehouse and Accounting So the Data Stays Right
How do you connect a CRM, a website, a warehouse and accounting so that the numbers stay right? Most connections work on launch day and drift afterwards, with no error anyone sees. Here is how they fail, which mechanisms stop it, explained in plain words with the real limits of Stripe, Shopify and HubSpot, when Zapier, Make or n8n are enough, and what to ask a contractor.
IN SHORT
Why integrations break
An integration stays reliable when each kind of data has one owning system, every message is stored before it is processed, handling the same message twice does no harm, a scheduled job compares the systems and repairs differences, and a person gets an alert when something stops. A point-to-point script has none of this by default, so it works on launch day and then loses orders, creates duplicates and drifts, often for weeks before anyone notices.
From the owner's chair it looks ordinary. The site shows three units and the shelf is empty. An accountant retypes invoices because "the sync misses some". A manager calls a client about an unpaid order that was paid on Tuesday. Nobody has seen an error message, because the failure happened between two systems and neither is responsible for that gap.
A direct script is the cheapest way to start, and for two systems it can be enough. The trouble is the arithmetic: three systems can need three connections and five can need ten, each with its own login and its own idea of what a customer is.
How much of what follows you need depends on what one wrong record costs. A newsletter sign-up that arrives twice costs nothing; a paid order that never reaches the warehouse costs a customer.
An integration that works on launch day has only passed the easiest test.
HOW THEY FAIL
Four failures nobody sees
Lost messages. Most modern systems announce changes with a webhook: a short message sent to your server when something happens. If your server is down, the sender tries again for a while and then gives up. Shopify retries up to eight times within four hours, and if failures persist it removes the subscription, so new events stop arriving altogether until someone recreates it (Shopify, November 2026). A server that is down from Saturday night to Sunday morning can lose those orders and the connection itself, and on Monday everything looks calm.
Duplicates. The same message can arrive twice. The sender retries because your answer came a second too late, though your code had already done the work. Stripe says plainly that an endpoint might receive the same event more than once. Without protection, one order becomes two invoices.
Rate limits. Every API limits how fast you can call it. On a HubSpot Professional account, a privately distributed app gets 190 requests per 10 seconds and the account gets 625,000 a day; above that, HubSpot answers with status 429, meaning "too many requests" (HubSpot, November 2026). Pushing 40,000 updated records one call at a time takes about 35 minutes at the full allowance. A script that ignores 429 reports success for the first part and drops the rest.
Changed fields. A manager makes a CRM field required, renames a status from "Paid" to "Payment received", or a vendor releases a new API version. The script keeps running and writes empty values, or stops matching anything. Shopify releases an API version every three months and supports each stable version for at least 12 months. When a version retires, Shopify answers with the oldest stable version still available, so old code receives newer behaviour with no error at all, only a different X-Shopify-API-Version header (Shopify, November 2026).
Senders set the deadlines, and your integration has to live within them:
| Sender | Retries in live mode | Time to answer | Order and duplicates |
|---|---|---|---|
| Stripe | For up to three days, with growing pauses | "Quickly", before any complex logic | Order is not guaranteed; the same event can arrive more than once |
| Shopify | Up to 8 times in 4 hours, then the subscription can be removed | 5 seconds | Order is not guaranteed; delivery is not always guaranteed; duplicates are spotted by X-Shopify-Webhook-Id |
| HubSpot | Up to 10 times over 24 hours | 5 seconds per batch | Not stated on the error-handling page we read |
These are vendor figures as of November 2026, and they change. The idea lasts longer: every sender gives up at some point and expects you to recover what it could not deliver.
ONE OWNER
One owner for each figure
Before anyone writes code, write down which system owns each kind of data. If two systems can change the same figure independently, they will drift apart, and syncing only copies the disagreement faster. The wider logic of systems of record is in Digital Architecture: How to Build a System That Can Grow With Your Business. In practice the decisions fit on one page:
| Data | Usually owned by | Others receive it | Where it tends to go wrong |
|---|---|---|---|
| Customer and deal | CRM | Store, accounting | Two records for one client after a guest checkout |
| Price and discount | ERP or accounting | Store, CRM | A manager's negotiated price that finance never saw |
| Stock | Warehouse system | Store, CRM | A promise made from a figure that is an hour old |
| Order status | Store until handover, then warehouse | CRM | Sales change a status that the warehouse also changes |
| Payment | Payment provider, recorded by accounting | CRM, store | The account manager calls before the payment is visible |
A wholesale channel or a partner program changes who owns what, as we describe in When E-Commerce Becomes a Business System. A company that keeps purchasing and production inside its CRM has a different question, covered in CRM vs ERP: What Is the Difference and Which One Do You Need?
Two-way sync deserves suspicion, because it often means nobody decided. When data does travel in both directions, the owner is set field by field: the order total goes one way and the delivery status the other.
What this looks like on our projects. For an e-commerce client running Salesforce for sales and a separate warehouse system for fulfilment, we built a custom layer that synced orders in both directions with no manual re-entry; neither system was broken, so neither was replaced. Our Honda Ukraine platform connects to Honda's internal CRM and inventory systems, so product data and dealer operations stay in sync. Launched in 2019, it is still in use more than six years later, and our team maintains it. For a FIAT dealership, inventory syncs with the CRM, and the job there was to keep working when the CRM pushes an update; both projects are discussed in The Customer Sees a Car Catalog. The Business Runs a Lifecycle System.
The strongest fix is fewer connections. For LavShash, with a restaurant, a market of about 2,000 to 3,000 products and its own delivery, we designed one system with three journeys in place of three products to keep in sync; the system is built and its launch is on hold. The reasoning is in Restaurant, Online Store and Delivery: One System or Three Products?
QUEUES AND RETRIES
Store first, process later
When a message arrives, your server does only three things: checks the signature, saves the message and answers "received". The real work (creating the invoice, updating the stock) happens afterwards, in a background worker reading from a queue.
The vendors ask for exactly this. Stripe tells you to return a 2xx status before any complex logic, and its own example is marking an invoice as paid in your accounting system: answer first, do that later. It also recommends an asynchronous queue, so that a spike at the start of a month does not overwhelm your servers. Shopify gives you five seconds, and an accounting system can easily take longer than that.
A queue also gives you retries you control. When the accounting system is down for an hour, messages wait, then drain at a pace it can take. Three rules keep it safe:
- Wait longer after each failure, with some randomness. AWS engineers call this backoff with jitter, and warn that stacked retries multiply load: in their example, independent retries at each layer raise the load on the database 243 times.
- Respect the limit you were told. A 429 answer may carry a Retry-After header saying how long to wait (RFC 6585). Shopify recommends backing off for one second. HubSpot asks that error responses stay under 5% of your daily requests.
- Stop after a set number of attempts and park the message. A message that fails ten times usually has a problem no retry will fix, such as a client with no tax number. It goes to a separate list, often called a dead-letter queue, which a person can read, fix and resend.
The same applies to what your own system sends out. If you save an order and then call the CRM, a crash between the two loses the call. The transactional outbox pattern writes the outgoing message into the database in the same transaction as the order, and a separate process delivers it. We apply the idea on our own site in its simplest form: every lead is written to a log before the email is sent, so a mail failure cannot lose it. How Much Testing Does a Website or App Need Before Launch? tells how a form could have kept thanking visitors while every email disappeared.
Answer first, do the work later, and keep the message until it is done.
IDEMPOTENCY
Safe to receive twice
Idempotency is an awkward word for a simple property: doing something twice has the same result as doing it once. Pressing an elevator button five times still brings one elevator. Retries make repeats unavoidable, and AWS's documentation for its own queue service says a message may be delivered again and applications should be designed for it.
Here is the failure it prevents. Your system asks accounting to create an invoice. The invoice is created, but the answer is lost when the connection drops. Your system sees a timeout and retries, and now there are two invoices.
An idempotency key is the fix: a unique label sent with the request, so the receiver can say "I have already done this one". Stripe's API works this way. It accepts a key of up to 255 characters on POST requests, saves the result of the first request and returns that same result on a retry. If the parameters differ from the original, it answers with an error. Keys can be removed once they are at least 24 hours old, so they protect against retries and do not replace your own records (Stripe, November 2026).
Where the receiving system offers nothing this convenient, the protection moves to your side:
- Build the key from the business fact: source system, order number and operation, such as shop-1042-create-invoice. A random value generated on each attempt protects nothing, and Stripe advises against putting personal data such as email addresses in keys.
- Keep processed keys in a database table with a unique constraint, so two workers running at once cannot both win, and store the ID the other system returns.
Order needs the same care. Stripe warns that invoice.paid can arrive before the event announcing the invoice, and that its created timestamp, in whole seconds, cannot sort events; it advises tracking event IDs and fetching missing objects through the API. Shopify suggests the X-Shopify-Triggered-At header or the updated_at field. Our rule of thumb follows from both: treat a webhook as a signal that something changed, then read the current state from the owning system, so an old message cannot overwrite a newer status.
RECONCILIATION
Compare the systems every night
Reconciliation catches what queues and keys cannot: a job on a schedule compares systems and reports or repairs differences. Shopify is direct about it: webhook delivery is not always guaranteed, so apps should not rely on webhooks alone and should run reconciliation jobs that fetch data periodically, using updated_at filters to get what changed since the last run (Shopify, November 2026).
For each kind of data the job asks the owning system what changed, compares that with the systems that received it and sorts the result: fixed automatically, or waiting for a person. Typical checks, with the frequency we would start from:
- orders for the day in the store against the CRM and the warehouse, by count and total, every night;
- paid amounts at the payment provider against invoices in accounting, every night;
- stock per SKU in the warehouse system against the store, every hour or more often where you sell out fast;
- active prices in the ERP against the store, after every bulk change.
Logs and alerts close the loop. Each message needs a trace: where it came from, where it went, its key, attempts, result and the text of any error. Alerts go to the person who can act, with a short note on what to do first. An alert that fires every day and needs no action gets fixed or removed, because it teaches the team to ignore the next one.
The alert most integrations lack is about silence. Watch the business signal: no orders reached the CRM in the last hour of a working day, the queue has been growing for twenty minutes, the last successful reconciliation was two days ago.
A failing script makes noise. A disconnected one makes none, so watch for silence.
CONTRACTS AND TESTS
Versions, sandboxes and drills
Every connection needs a written contract: which fields travel, their types, which are required, which values are allowed, who owns them and what happens with an unknown value. One page per flow is enough, kept with the code. It is what you open when a manager asks to rename a status.
Name the API version in every call, as Shopify advises, and treat its quarterly release as a calendar task. Stripe sets the structure of an event by the API version in your account settings at the moment the event occurs, so an account upgrade can change what your handler receives. A test in your pipeline that checks the shape of each response tells you this on the day it happens.
Test against sandboxes, and know their limits. Stripe's sandboxes simulate payments without moving real money, yet they retry webhooks three times over a few hours, against up to three days in live mode. So a sandbox shows that your code understands the messages. How the business survives an outage takes drills on a test copy:
- switch the receiver off for six hours, then check that nothing was lost;
- send every message twice and in the wrong order.
On store projects we test bulk updates, the delay between the ERP and the storefront, recovery after a failed integration and sync during a peak before launch. Better to learn on a test copy what the first real Saturday outage would do.
WHICH TOOL
Zapier, Make, n8n or custom
Prices and limits are from vendor pages as of November 2026:
| Option | Fits when | What to watch | Cost |
|---|---|---|---|
| Zapier | A few flows at low volume, where a repeat or a miss costs little | Each successful action step is a task; replaying a whole run repeats steps that already succeeded; polling every 2 minutes on Pro, 1 on Team | Pro from $19.99 a month billed annually for 750 tasks; 50,000 tasks $289 a month |
| Make | Branching flows with moderate volume and someone who can maintain them | At the 10,000-credit tier: 10 MB for failed runs and a webhook queue of 667; a run stops after 45 minutes | Core from $9 a month for 10,000 credits |
| n8n | Long flows, since one run counts as one execution whatever its length; a technical owner | Self-hosting means your team runs updates, backups and monitoring | Starter 20 euros, Pro 50 euros a month billed annually, for 2,500 and 10,000 runs; a self-hosted version is on GitHub |
| Ready connector or middleware | A standard pair of systems with standard objects | Your own rules end up outside it; the connector's mapping becomes one more thing to maintain | NetSuite through connectors: often $5,000 to $20,000 one-off (market range, our estimate) |
| Custom layer | Money or stock at stake, your own rules, several systems, high volume | It needs a team that maintains it and a contract for handover | Laravel work at $75 an hour or projects from $15,000; support from $1,000 a month |
Two details deserve a look before you trust a no-code tool with orders. On Make, a failed run is saved so the data is not lost, but when that storage is full, Make discards the failed data and keeps the scenario running, and discarded data cannot be recovered. On Zapier, with pay-per-task switched on, usage continues at a higher overage rate but stops altogether at three times your subscription until the next cycle. Both are terms to know before the busiest day of the year.
Run the sums for your own flow. Take 10,000 orders a month with five action steps each: that is 50,000 tasks on Zapier, $289 a month billed annually or $433.50 billed monthly, and 10,000 executions on n8n's Pro plan. That is modest money next to a developer, so the deciding question is who designs the idempotency, the reconciliation and the alert about silence.
Our usual advice is a split: no-code for notifications and marketing lists, where a miss is cheap; code for orders, payments, stock and invoices. And sometimes no custom code is needed at all. For a professional services client sure it needed a custom CRM, we mapped a three-stage sales process and recommended a configured HubSpot: two weeks of setup in place of months of development. Replacing a system or connecting it is the subject of Custom CRM or ERP: When Standard Software Stops Fitting.
When custom is right, it is built around how your business runs, and the code, deployment commands, rollback procedure and an AGENTS.md file describing the rules are handed over to you under the contract. The layer can grow into a custom CRM from $30,000, an ERP from $50,000 or a web application from $25,000. We do not sell integration as a separate technical job, because the useful decisions, such as who owns a price, are business decisions.
WHAT TO ASK
Questions for your contractor
A good answer is specific and comes with something to show you.
- Which system owns each field? Ask to see the table.
- What happens if our server is down for six hours? Listen for the queue and how missed events return.
- What happens if the same message arrives twice, or out of order? Ask which key prevents a duplicate invoice.
- What is the rate limit of each API, and what does the sync do at 429? Ask how long a full catalogue update takes.
- How often do you reconcile, and where do we see the differences? Ask for a sample report.
- Who gets the alert, and how would we learn that a connection went silent?
- Which API versions are pinned, and who watches for retirements?
- Which failures do you test? Ask for the drill list, including an outage.
- What do we get at the end? Code, documentation and each flow's contract belong on the list.
What it costs at Peretz Agency. A connection between existing systems is usually Laravel work at $75 an hour or a fixed project from $15,000; the price moves with the number of systems, the quality of their APIs and the volume of data to clean. A discovery phase from $4,000, lasting two to four weeks, maps integrations and risks into a backlog with a budget. If the developer of an inherited integration has left, a takeover audit from $2,500 writes down what is connected to what. Support starts from $1,000 a month. The usual first step is a $500 strategic session, credited toward the project within 30 days.
FAQ
Frequently asked questions
Why do integrations between systems keep breaking?
Direct scripts assume every message arrives once, in order, and that the other system never changes. In practice senders give up after a retry window, messages arrive twice, APIs enforce rate limits, and fields change. Without queues, keys, reconciliation and alerts, those failures stay invisible until a person finds them.
How do I connect a CRM, a website, a warehouse and accounting?
First write down which system owns each kind of data. Then connect them through a layer that stores every message before processing it, can safely process it twice, compares the systems on a schedule and alerts a person when something stops.
Is Zapier or Make enough for business integrations?
For low-volume flows where a miss or a repeat costs little, often yes. For orders, payments and stock, check how the tool handles duplicates and failed runs, and who reconciles the results.
Should integrations use webhooks or scheduled polling?
Usually both. Webhooks bring changes within seconds and reduce API calls, and HubSpot suggests them over polling. Scheduled reconciliation catches what webhooks miss, which is why Shopify tells developers not to rely on webhooks alone.
How much does a system integration cost?
At Peretz Agency a connection between existing systems is usually Laravel work at $75 an hour or a project from $15,000, and support starts from $1,000 a month. No-code tools start from $9 or $19.99 a month as of November 2026, but someone still has to design and watch the flows.
Sources
- Stripe: Receive Stripe events in your webhook endpoint
- Stripe: Idempotent requests
- Shopify: Webhook best practices
- HubSpot: API usage guidelines and limits
- Microservices.io: Transactional outbox pattern
Orders, stock or invoices drifting between your systems? Let's look at where the data stops agreeing.
One notification a week with the new PERETZ articles. Nothing else.