84 duplicate customer numbers, and 61 of them were archived on one side
Almost no business system deletes a record. It sets a flag, and that flag is invisible to your automation unless you ask for it. The result is duplicates with none of the negotiated terms, contacts that come back to life overnight, and invoice lines priced at zero.
What the audit found
We compared 12,400 customer records between a wholesaler's CRM and their ERP earlier this year. 84 customer numbers existed twice. In 61 of those pairs, one side was archived.
Eleven of the 61 had taken an order in the previous twelve months against the wrong record. No negotiated discount, no payment terms, prepayment demanded from customers the company had served for years.
None of it showed up as an error. Every one of those orders was a successful workflow run.
Archiving is not deleting, and your API knows it
Business systems rarely delete anything. What looks like deletion in the interface writes a flag: deleted_at, archived, status set to inactive. The row stays where it was and drops out of the lists people look at.
That design is correct. Invoices point at customers, orders point at products, and a hard delete turns historical documents into orphans. Retention rules would forbid it in most cases anyway.
The archive itself is fine. It becomes a problem because an automation cannot see it unless somebody wrote the query that asks for it.
The same word, three behaviours
Three patterns show up constantly, often inside one workflow.
Some APIs hide archived records from search and list endpoints but return them happily on a direct fetch by ID. Search says the record does not exist. The fetch says it does.
Some return everything and put the state in one field among forty. If nobody looked for it while building the mapping, it is not in the mapping.
Some answer with a 404. The workflow takes the error branch, and in most no-code builds that branch ends at "create it, then".
Four ways this shows up
The most common outcome is a duplicate. The lookup does not see the archive and creates a fresh record. What the new record is missing is exactly what took years to accumulate: terms, contacts, delivery addresses, credit holds. It looks clean, which is why nobody questions it.
Then there is the resurrection. A nightly sync writes in both directions. The contact is archived in the CRM and still active in the shop. The sync sees a difference and pushes the shop version back. Somebody archives it on Monday and it reappears on Tuesday. One logistics client lived with that for four weeks before anyone opened the change history. Every one of those nights the log said one record updated.
The third case lands in the outbox. The mail tool pulls contacts through the API and gets the archived ones with them. The customer who asked to be removed sits in the CRM archive and in the mailing list at the same time. If the archive flag was set because they objected to marketing, the proof of the breach arrives in their inbox.
The fourth is about products rather than people. An order points at an archived product or an expired price list. The workflow fetches the description and price, gets nothing, and writes an empty description and 0.00 into the line. The invoice goes out. Accounting is the first place it can surface, and only if somebody checks the total against the order.
Testing will not catch it
Test data is new and active. Nobody archives a test record and then runs the workflow against it. Archiving happens later, in production, when a salesperson tidies up the account list, months after go-live.
Those months are the ones where everybody decides the automation works. By the time the first archived record goes through, the workflow is nobody's project anymore.
None of the four failures raises an error either. A duplicate is a successful create. A resurrection is a successful update. A newsletter to an archived contact is a successful send. Monitoring stays green throughout.
How we build it instead
Search the archive too. Every step that checks whether a record already exists asks for archived records explicitly rather than trusting the API default. An archived hit stops the create branch, and the workflow makes a deliberate choice at that point: reactivate, or hand it to a person as a task. Either beats a second record.
Carry the flag. The archived state belongs in the mapping and in every downstream system that receives the record. If the target has no field for it, add one. A record that arrives without that information forces every later step to guess.
Let one direction win. For any object synced between two systems, decide which system owns the archived state. The other side follows and never writes it back. Without that rule the ping-pong is a matter of time.
Check at send, not at start. Any step that sends something checks the state immediately before dispatch. On a run across 4,000 contacts, two hours can pass between reading the list and the last message. Anyone archived in that window still gets mail if the check sits at the top of the run.
And a 404 is not permission to create. The error branch has to distinguish "does not exist" from "exists, but not for this query". In practice that means a second lookup including archived records before the create step is allowed to run.
Where the switch actually sits
In Make and n8n the problem usually sits in the connector rather than in the logic. Prebuilt search modules mirror the default search of the API, and the default search hides archived records. Whether a switch exists at all is documented in the target system's API reference, not in the module. Some vendors expose an extra parameter on the list call, some a separate endpoint for archived objects, some only a filter on a status field whose name you have to know already.
If the module does not offer it, we replace the module with a plain HTTP call. That hands you authentication and error handling to maintain yourself, and it is still cheaper than a lookup that systematically misses half the database.
Plan for one side effect. A search that includes the archive finds more, including things nobody wanted found. The wholesaler's first run with the archive included returned 340 hits where there had been none. Some were genuine returning customers, some were leftovers from a 2019 migration. Sorting that out took two afternoons of somebody's time in sales, not a workflow.
Four questions for your own stack
Take an archived record from your leading system and push a transaction through that touches it. Whatever happens next answers the question faster than any analysis will. Do it in staging.
Count how often the same customer number or email address appears in the target system. Every pair is a candidate.
Read the change history for the last thirty days and look for records reactivated with no person behind the change. A service account in that column means you have a sync fighting itself.
Compare your mailing list against the archived contacts in the CRM. That intersection should be empty.
Where the wholesaler ended up
Two people from the sales team merged the 61 pairs by hand. When documents hang off a duplicate, the merge decides which customer owns which invoice, and that is not a decision to hand to a rule that treats 61 cases the same way.
The automation itself changed in two places. Customer lookup now includes archived records, and an archived hit creates a task instead of a new record. Half a day of work against a problem that grows every time somebody tidies up the CRM.