Which system holds the authoritative record?
For every entity that passes between systems, such as a customer, an order or a work order, write down which system owns it and which identifiers match it in the others. If both the app and the CRM can change a customer’s phone number, someone has to decide which one wins, and the integration has to know about that decision.
Describe the required fields, their formats and the allowed status changes. An integration brief should describe events and outcomes, not just a list of endpoints: “when an order is approved in the portal, a work order with these fields appears in the operations system, and the portal shows its number”. A sentence like that can be tested; a list of URLs cannot.
Decide in advance what happens when records conflict or the same field changes in both systems at once. Then check access rights, rate limits and differences between test and production environments in the provider’s current documentation, not in code copied from an old project.
What happens when a request fails or repeats?
Networks fail in awkward ways. A request can succeed on the remote side while your system never receives the response, so from your end it looks like a failure. If the code simply sends it again, the customer may end up with two orders or two payments.
Protect against this with stable operation identifiers, often called idempotency keys, which let the receiving system recognise a repeat. Add reconciliation as well: before retrying an action that may already have happened, check its actual state. Many providers can deliver the same webhook more than once, so the receiving side must handle repeats calmly.
Describe queues, timeouts and a place where failed messages wait for review (a dead-letter queue) where the volume justifies them. Keep the statuses users see honest: a handover that failed must never appear as completed. And specify what an operator needs to finish the work by hand: which record is affected, what was sent and what came back.
How do you know the integration really works?
Write end-to-end acceptance cases and run them in an environment close to production. Include new and existing records, missing or malformed data, expired access tokens, callbacks that arrive twice and a provider that is temporarily unavailable.
For each case, look at the final state in both systems. An HTTP success code only tells you the request was accepted; whether the right record appeared with the right fields is a separate question. Then decide what is logged, who receives alerts and how credentials are renewed before they expire.
Finally, treat the contract as a living document. Providers change their APIs, retire old versions and introduce new limits, so name the person who follows those changes. Otherwise a pilot that worked well can turn into a fragile dependency after the next API update. That is why integrations are planned at the start of app development, not added at the end.
Checklist: app integration
- Document which system owns each entity, the matching identifiers and the field formats.
- Decide what happens when records conflict between systems.
- Protect repeated operations with stable identifiers and reconciliation.
- Check the final records in both systems as well as the response codes.
- Name who handles monitoring, credential renewal and provider changes.
Example: passing on a work order without duplicates
A customer portal sends an approved work order to an operations system. Each handover carries a stable operation ID, so when a timeout triggers a retry, the operations system recognises the repeat and does not create a second order.
Until the destination confirms the record, the portal shows the order as “being transferred”, not “done”. If the result stays uncertain, an operator can see the order, what was sent and the last response, and reconcile the two systems by hand.


