How to Connect Your Business Systems Without Replacing Everything
How to connect business systems: a field ownership table, real Zapier, Make and Power Automate cost math, duplicate-proof retries and an exception queue.
Luka Abramovic20 min read

To connect business systems without replacing them, automate one handoff at a time: agree which system owns each field, choose the cheapest tool that can handle that handoff's failures, and send every failure to a list that a named person works through. Design first for the failure almost nobody plans for. The destination creates the record, its reply is lost, the integration retries, and the delivery team gets two projects. Then check the pricing mechanics. On Make, a trigger that checks for new deals every minute uses about 43,200 credits a month before it moves a single deal.
We follow one illustrative handoff throughout: a deal marked won in the CRM becomes a project in the delivery tool. It is a composite, not a client result. The last section turns each piece into an integration brief you can hand to any builder.
Pick one handoff and watch it done by hand
"Connect our systems" can't be built or tested. One handoff can: a transition that happens every week, has a clear finish and depends on someone copying data. If you are still deciding whether the tools themselves should stay, settle that first with our integrate, replace or build guide.
Sit with the person who does the handoff today while they process three or four real records. Write down five things:
- What tells them to start: an email, a stage change, a Friday habit.
- Every field they copy, and where they copy it from.
- Every check they make before continuing, such as "is the scope signed?"
- Every time they stop to ask someone, and who.
- What the receiving team needs in order to start work without asking questions.
Items 3 and 4 are your business rules. Each check becomes a condition, and each "I'd ask Maria" becomes an exception type with an owner. Our example comes out as six steps, used for the pricing arithmetic later:
- Trigger: a deal moves to Closed Won in the CRM.
- Check: customer, signed scope, start date and delivery owner are all filled in. If not, stop and raise an exception for the salesperson.
- Prepare: build the project name and map the fields.
- Create: create the project in the delivery tool, with the CRM deal ID stored on it.
- Link: write the new project ID back onto the deal.
- Notify: post a message in the delivery team's channel.
If one of the two systems is an older in-house tool, find out what it already does behind the scenes before you connect to it. Our legacy system examples show where those hidden jobs and rules usually sit.
Fill in a field ownership table
Connected systems disagree faster than disconnected ones, because every disagreement is copied automatically. The ownership table prevents that. The method:
- List every field on the deal and the project that the handoff reads or writes. Include fields someone might edit on either side after the handoff.
- For each field, find the person who fixes it when it is wrong. Ask them: "When this is wrong, which system do you correct first?" That system is the owner. If they answer "both", you have found a conflict before it cost you anything, and the business owner of the handoff decides.
- Record when the value is copied (once at handoff, or on every change) and what happens if someone edits the copy.
- Mark the fields that must not move at all.
| Field | Owner | Who corrects it | Copied | If someone edits the copy |
|---|---|---|---|---|
| Customer legal name | CRM account | Sales operations | At handoff, then on every change | Overwritten at the next change. Correct it in the CRM. |
| Signed scope | CRM deal (signed version) | Account manager | Once, at handoff | Later changes go through a change request, not the sync. |
| Promised start date | CRM deal | Salesperson | Once, at handoff | Never copied again. |
| Planned start date | Project tool | Delivery owner | Project to CRM, on every change | Read-only in the CRM. |
| Delivery owner | Project tool | Delivery lead | Once, at handoff | Reassign in the project tool only. |
| Project status | Project tool | Delivery owner | Project to CRM, on every change | Read-only in the CRM. |
| Deal value and margin | CRM deal | Finance | Never | Not sent. |
| CRM deal ID | CRM | Nobody | Written onto the project when it is created | Locked. The duplicate checks later in this guide depend on it. |
Notice that the start date is split into two fields. It is the field most likely to have two owners, because sales promises it and delivery changes it. Our default is to give each team its own field rather than sync one field in both directions. Two-way sync of a single field needs conflict and loop-prevention rules, which is a bigger job than most first handoffs justify.
The "who corrects it" column also tells you where exceptions go. If a handoff fails because the start date is missing, the table says the salesperson fixes it, so the exception goes to the salesperson and not to IT.
Native connector, integration platform or custom: what each really costs
Use the simplest option that can move the fields in your ownership table in the right direction, avoid duplicates when something is retried, and show failures to the person in the "who corrects it" column.
Five questions for a native connector
A vendor-built connector is usually the cheapest option and often the least transparent when it fails. Ask the vendor to show you these in a trial account, not describe them:
- Can it map every field in our ownership table, including custom fields?
- Which direction does each field move, and what happens when both sides change the same record?
- Where does a failed record appear, and can a non-developer retry it?
- If the same deal is saved twice, does it update the existing project or create a second one?
- Which plan includes the connector, on both products?
If the answer to question 3 is "in the admin logs", budget for someone to read those logs every day, or choose another option.
How integration platforms charge, as of September 2026
- Zapier counts tasks. A task is an action step that completes successfully, so a step that errors doesn't use one. Zapier's task usage page says trigger steps, Filter steps and Paths steps don't count, and Formatter steps stopped counting in Zapier's 2024 plan changes. If you exceed your plan, pay-per-task billing charges extra tasks at 1.25 times your plan's per-task price on annual billing and 2.5 times on monthly billing, up to three times the plan's task limit. After that, tasks are held until the next billing cycle, which means your handoffs stop.
- Make counts credits. Make defines an operation as "a single module run to process data or check for new data", and for most modules one operation uses one credit. The words "check for new data" matter: a scheduled trigger uses a credit every time it looks, whether or not anything changed. Make's scheduling guide puts a five-minute schedule at 288 credits a day for the trigger alone. An instant trigger, which receives a webhook, runs only when data arrives.
- Power Automate is licensed, not metered per step. Microsoft 365 licenses include Power Automate with standard connectors only. A flow that uses a premium connector (the Salesforce connector is one) needs Power Automate Premium at $15 per user per month, or a Process license at $150 per month, both paid yearly, according to Microsoft's pricing page. The licensing FAQ has the rules that catch people out. An automated or scheduled flow runs under its owner's license, so only the owner needs Premium, while a button-started flow needs every user who runs it licensed. If a premium flow's owner leaves or loses their license, the flow is downgraded and turned off after 14 days unless someone acts. Several people sharing one service account's Premium license is what Microsoft calls multiplexing, which the FAQ says is not compliant.
Worked example: 400 deals a month
Illustrative inputs: 400 deals reach Closed Won each month, and the handoff has the six steps listed earlier. Three of them (create, link, notify) are actions in other apps. Months are counted as 30 days.
| Setup | What is counted | Monthly usage |
|---|---|---|
| Zapier | 3 action steps × 400 deals. The trigger, the check (Filter) and the preparation (Formatter) are free, so deals stopped at the check cost nothing. | 1,200 tasks |
| Make, trigger checks every 15 minutes | 2,880 trigger checks (4 an hour × 24 × 30), plus 3 action modules × 400 | 4,080 credits |
| Make, trigger checks every minute | 43,200 trigger checks, plus 1,200 | 44,400 credits |
| Make, instant trigger | About one trigger run per event, if the CRM sends events only for deals entering Closed Won, plus 1,200 | About 1,600 credits |
| Power Automate, Salesforce as the CRM | Licenses, not runs: Premium for the flow's owner, or a Process license on the flow itself | $15 or $150 a month, paid yearly |
Three inputs change the answer more than the choice of platform does:
- Make's polling interval. At one-minute checks, the trigger uses 36 times as many credits as the work itself.
- The return direction. If project status flows back to the CRM and each project changes status five times, that adds 2,000 tasks or credits a month, more than the original handoff.
- Who owns a Power Automate flow. $15 a month on one person's license is cheap until that person leaves. A Process license keeps the flow running regardless of who owns it, but the flow has to be inside a solution before one can be assigned.
For your own numbers: take last month's count of records that entered the trigger stage, multiply by the counted steps, add trigger checks if you use Make, and read the tier that covers the total off the vendor's pricing page.
When custom earns its cost
Custom has no per-task fee. You pay instead for the build, hosting, monitoring and changes when a vendor changes its API. A rule we use: custom starts to earn its cost when at least one of these is true.
- The exception queue described below needs to be a real screen that operations staff work from every day.
- The duplicate protection in the timeouts section needs logic that the platform can only express as a tangle of branches nobody but its builder can read.
- The platform bill grows with volume rather than with new workflows.
- One of the systems has no connector on the platforms you use.
Polling or webhooks: how the integration hears about a change
Polling asks the CRM every few minutes for anything new. A webhook is a message the CRM sends the moment something changes. Each fails differently.
- Polling is late by up to one interval and, on Make, costs a credit per check. It also can't see deletions, because a query for records changed since the last check can't return a record that no longer exists.
- Webhooks are fast, but each vendor sets its own delivery rules. Stripe's webhook documentation says the same event can arrive more than once and events can arrive out of order. Microsoft Dataverse, the data platform under Dynamics 365 Sales, waits 60 seconds for your endpoint to respond. A timeout or any response outside the 2xx range fails the call, and Dataverse makes one more attempt only for 502, 503 and 504 errors. If your receiver is down for an hour, those events won't come back on their own.
Our default is webhooks for speed plus a daily sweep as the safety net. The receiver should save each event and reply within a few seconds, then do the work, because slow work inside the request becomes a timeout on the sender's side. The sweep compares source and destination and catches whatever the webhooks missed.
A first version needs no developer. Export yesterday's won deals to a sheet named Deals, deal ID in column A. Export projects to a sheet named Projects, stored CRM deal ID in column B. Put this in cell B2 of Deals and fill down (Excel or Google Sheets):
=IF(COUNTIF(Projects!B:B, A2)=0, "MISSING", IF(COUNTIF(Projects!B:B, A2)>1, "DUPLICATE", ""))
It flags every won deal with no project or more than one. The operations lead can run it weekly in the first month. Every flag should already be in the exception queue. One that isn't is a failure the integration didn't notice.
Timeouts and retries: where duplicates come from
A timeout doesn't mean the request failed. It means the integration stopped waiting. This illustrative sequence shows how a correctly configured flow still creates a duplicate:
- 10:02:00. The integration asks the delivery tool to create a project for deal 4417.
- 10:02:04. The delivery tool creates project P-889, but its reply is slow or lost on the way back.
- 10:04:00. The integration gives up waiting (Power Automate's limit for an outbound synchronous request is 120 seconds) and records a failure. It never learns that P-889 exists.
- 10:04:10. The retry policy sends the same request again, and the delivery tool creates P-890.
- Next morning. Half the delivery team plans work in P-889 and half in P-890.
Platforms retry by default. Power Automate's limits page shows up to 12 retries for Premium and Process flows, the gap growing to about an hour before the last, and up to 2 on the Low profile that covers Microsoft 365 licenses. The Azure Logic Apps documentation it links to says a request is resent when it times out or returns a 408, 429 or 5xx error. Microsoft's retry pattern guidance describes the case above exactly: the service processes the request, fails to send a response, and the retry sends it again. Retrying is right. Retrying a create without protection makes the duplicate. There are two protections.
Fix 1: an idempotency key
An idempotency key is a unique reference generated once per intended action and sent unchanged with every retry. The destination remembers keys it has seen, and when one arrives again it returns the original result instead of doing the work twice. The IETF is standardizing this as an Idempotency-Key header, and the implementers the draft lists, such as Stripe, Adyen and PayPal, are mostly payment companies. The draft also lets an API expire keys after a period it publishes, so compare that period with your longest retry. Search the destination's API documentation for "idempotency". If the word isn't there, assume there is no such protection and use the second fix.
Fix 2: look up before you create
Store the source record's ID on the destination record, and check for it before every create. In our example, the project gets a custom field called "CRM deal ID". This is the logic to ask your builder for, whichever tool they use:
Before creating a project for deal D:
1. Search projects where "CRM deal ID" = D.
2. One found: link it to the deal and stop. Do not create.
3. More than one found: stop and raise a "duplicate projects" exception.
4. None found: create the project with "CRM deal ID" = D in the same call.
5. If the create times out: go back to step 1 before any retry.
On Make, the search is one more module, so add 400 credits a month to the worked example. Two details decide whether this works. First, write the deal ID in the create call itself, not in a follow-up update. If it goes in a second call and the timeout falls between the two, the search in step 1 finds nothing and you create a duplicate anyway. Second, two attempts for the same deal running at the same moment can both search, both find nothing and both create. Ask your builder how simultaneous attempts for one record are prevented, and rely on the sweep's DUPLICATE flag to catch any that get through.
Which errors to retry
| Response | What it means | What the integration should do |
|---|---|---|
| No response (timeout) | Outcome unknown | Run the search from fix 2, then retry only if nothing was created. |
| 429 Too Many Requests | The API is limiting your request rate | Wait as long as the response says, then retry. |
| 500, 502, 503, 504 | A temporary problem on their side | Retry with growing waits, then move the item to the exception queue. |
| 400 or 422 | The data was rejected | Don't retry. Send an exception to the field's owner from the ownership table. |
| 401 or 403 | Credentials or permissions | Don't retry. Alert the technical owner. |
| 404 on an update | The record was deleted or merged | Don't retry. Send an exception to the handoff's business owner. |
Retrying a 400 or 422 sends the same bad data and gets the same answer. It uses up the retry budget and delays the one person who could fix the record in a couple of minutes.
If one side is your own application: the transactional outbox
When one side is your own application, a different gap opens. The app saves the deal, then sends the "create project" message. If the network drops between the two, the deal is saved, the message is gone, and nothing records that it was ever needed. The named fix is the transactional outbox pattern. In plain English: write the intention to your own database first, then send.
- In the same save as the deal update, the app writes a row to an outbox table: "create project for deal 4417, status pending".
- A separate background job reads pending rows, sends each message and marks the row sent once the destination confirms.
- If sending fails, the row stays pending and is retried later. Nothing depends on the send happening at the same moment as the save.
The background job can still send a row twice, for example if it crashes after sending but before marking the row, so the receiving side still needs fix 1 or fix 2. The question to ask a supplier is: "If the connection drops between saving the record and sending the message, where is the message?" A good answer names an outbox or something equivalent. "That rarely happens" doesn't answer the question.
Design the exception queue
A failed handoff should land in a list a business person works through, not a developer's log. It can live in the CRM, a shared table, a SharePoint list or a custom screen. What matters is what each item contains. This is the record we specify:
| Field | Example | Why it's there |
|---|---|---|
| Source record link | Link to deal 4417 in the CRM | One click to the thing that needs fixing. |
| Handoff and step | Deal to project, step 4 (create project) | Tells the technical owner where to look. |
| What was attempted | Create project "Acme Corp: Phase 2" for deal 4417 | The owner can judge the consequence without reading code. |
| Error in plain language | The start date is empty, and the delivery tool requires one. | Written for the person who fixes it. |
| Technical error | 422: start_date is required | Kept for the technical owner and shown second. |
| Outcome | Failed, outcome unknown, or waiting on a person | "Outcome unknown" after a timeout tells everyone to check before retrying. |
| First seen | 2026-09-24 10:04 | How old the problem is. |
| Last attempt | 2026-09-24 10:41 | Whether retries are still running. |
| Retry count | 4 of 12 | How close it is to giving up automatically. |
| Owner | The salesperson on the deal, taken from the ownership table | A name, not a team. |
| Suggested action | Add a start date to the deal, then choose Retry. | The owner shouldn't need to ask anyone what to do. |
| Attempt key | The idempotency key or deal ID used for every attempt | Makes retries safe. |
| Resolution | Who resolved it, when, how, and the destination record ID | Needed for the weekly review and for any later audit. |
Each item needs three actions, and each one has a rule that makes it safe:
- Retry reuses the same key and runs the search from fix 2 first. A retry button that generates a fresh key is how a recovery queue creates duplicates.
- Skip requires a reason, such as "deal canceled". Skipped items leave the alert count but appear in the weekly review, so a habit of skipping stays visible.
- Mark resolved manually requires the ID of the project the person created by hand and writes that link back to the source record. Without it, the next automatic retry or the daily sweep doesn't know the project exists, and creates or reports a second one.
Route each item by its cause, using the ownership table. Data problems go to the person who owns the field. Credential, permission and outage problems go to the technical owner. Outcome-unknown items go to the technical owner until the search confirms what happened. Alert on the age of the oldest open item rather than the number of items. Our default is a daily summary to the handoff's business owner, plus an immediate alert when any item is older than the time the receiving team can wait, which you set in the integration brief below.
For a delivered system with scheduled pipelines and failure handling at scale (400+ connected properties, around 220k rows a day), see our anonymized operations platform case study. It does not describe the illustrative workflow in this guide.
Test the failure paths before launch
A demo with one perfect deal proves the easy path. Run these tests in a sandbox or test account, and don't go live until each one passes.
| Test | How to run it | Pass condition |
|---|---|---|
| Same deal twice | Move a test deal out of Closed Won and back in. | One project. The second event is recorded as already handled. |
| Missing field | Close a deal with no start date. | No project. An exception reaches the salesperson with the plain-language message. |
| Access revoked | Revoke the integration's access in the test account, close a deal, then restore access. | No retries. An exception reaches the technical owner at once. After Retry, exactly one project. |
| Timeout after success | Ask the builder to set the integration's timeout shorter than the delivery tool's response time. | The retry finds the project through the search. One project. |
| Manual fix | Create a project by hand for a failed deal, mark it resolved with that project's ID, then trigger the deal again. | No second project. |
| Sweep | Run the sheet formula over a week of test deals. | No MISSING or DUPLICATE flag that isn't already in the queue. |
| Owner leaves | Check which account owns the flow and which license it runs under. | Nothing depends on one employee's account or license. |
Then run the integration alongside the manual process. Our default is two weeks in which the integration does the work and the person who used to do it checks each result. Go fully live after a week in which every problem they spotted was already in the queue.
The integration brief, filled in
Everything above fits on one page. Copy the template, fill it in with the people who do the work, and give it to whoever builds the integration. Here it is completed for the illustrative example.
INTEGRATION BRIEF
1. Handoff: Won deal in CRM becomes a delivery project
2. Business owner: Head of Delivery (decides disputed cases)
Technical owner: Operations systems admin (fixes connections)
3. Trigger: Deal stage changes to Closed Won
4. Done means: Project has customer, signed scope, promised
start and delivery owner; project ID is on
the deal; delivery channel notified
5. Systems: CRM: webhooks available, API on current plan
Delivery tool: API, no idempotency key,
custom field "CRM deal ID" created
6. Volume: About 400 deals a month; peak of 40 on the
last business day of the quarter
7. Maximum wait: Receiving team can wait 4 business hours
8. Ownership: Field ownership table attached
9. Rules: Stop if scope, start date or delivery owner
is missing; exception to the salesperson
10. Duplicates: Search by CRM deal ID before every create;
deal ID written in the create call
11. Retries: Timeout: search, then retry. 429 and 5xx:
growing waits, then queue. 400, 401, 403,
404, 422: no retry, straight to the queue
12. Queue: Exception fields as specified; Retry, Skip,
Mark resolved manually; alert when the oldest
item is older than 4 business hours
13. Sweep: Daily comparison of won deals to projects
14. Must not move: Deal value, margin, private sales notes
15. Access: Integration account reads deals, writes two
deal fields, creates and reads projects
16. Test cases: 3 to 5 recent real failures attached:
duplicate project, missing scope, deal
canceled after handoff, scope changed
after delivery started
17. Success: Zero MISSING and zero DUPLICATE flags in the
weekly sweep for four weeks in a row;
re-keying time recorded before and after
18. Fallback: Pause the flow; the operations coordinator
creates projects by hand and records each
project ID on the deal
Items 6 and 7 set the pricing and the alerting. Items 10 to 13 are the ones to compare between builders: ask each one to explain in writing how their design handles them.
If you'd like a second opinion before anyone builds, bring the completed brief, your ownership table, last month's handoff count and three recent handoffs that went wrong. We would start with the destination API's retry and duplicate behavior and your exception list, because those two decide whether a platform flow is enough. That review is where our business systems integration service begins.