When two business systems need to share records, the hardest part is often not the API request. It is deciding how both sides know that a record in one system is the same record in another.
A customer may be identified by a name in one database, an email address in a CRM, and a numeric ID in an order system. Those values can change, collide, or be entered inconsistently. A practical integration needs a more deliberate approach: stable identifiers, clear ownership, and rules for what happens when a match is missing.
Why names and email addresses are weak integration keys
Human-readable fields are useful for display and search, but they are risky as permanent links between systems. Two people can share a name. A company can have multiple contacts at the same address. An email address can change, be reused, contain a typo, or represent a shared inbox rather than one person.
Even a value that appears unique in a spreadsheet may not be unique across the full life of a business. If an integration uses that value as its only key, a correction in one system can create a duplicate, update the wrong record, or silently stop a sync.
Use names and email addresses as matching clues, not as the final authority, unless the business has explicitly accepted the risks and has a controlled process for resolving collisions.
Choose the system of record first
Before designing fields or endpoints, decide which system owns the identity for each important object. For example, the CRM might own the customer identifier, the order system might own the order identifier, and a support application might own the ticket identifier.
Ownership does not mean every other system must store a copy of every field. It means there is a clear place to ask whether the record exists, whether it was merged, and which identifier should be used when another system refers to it.
Write this decision down for each object:
- What is the object: customer, order, invoice, ticket, or something else?
- Which system creates its authoritative identifier?
- Which fields may other systems update?
- What happens when the object is merged, archived, or deleted?
This small inventory prevents an integration from treating every system as equally authoritative and then having to guess when values disagree.
Prefer stable IDs for relationships
A stable identifier should remain associated with the same record even when editable attributes change. It can be a database-generated value, a provider-issued resource name, or an application-generated identifier designed for the business’s needs.
Store the identifier as data, not as a value hidden inside display text. If an order belongs to a customer, the relationship should point to the customer’s identifier. A label such as “Acme, Inc.” can still be shown to a person, but it should not be the only way the integration finds the customer.
Keep the identifier’s scope clear. An ID may be unique inside one application but meaningless to another. A useful integration contract says whether a value is globally unique, unique only within a tenant, or paired with a source-system field to become unambiguous.
Use a cross-reference table when systems have different IDs
Connected systems often cannot share one universal identifier. In that case, create a small cross-reference table that records the relationship between identifiers. A row might contain the source system, source ID, destination system, destination ID, object type, first-seen time, and last-confirmed time.
The table should have a uniqueness rule that matches the business relationship. For example, one source customer ID should map to at most one destination customer ID for a given account, unless the domain explicitly supports a one-to-many relationship.
Do not use the table as an excuse to skip ownership decisions. It is a translation layer, not a replacement for an authoritative record. Include enough metadata to explain how a mapping was created and to investigate a disputed match without relying on memory.
Design for missing, delayed, and changed matches
A new order may arrive before the corresponding customer record has finished synchronizing. An external system may return a temporary error. A person may merge duplicate records in the source system. These are normal integration conditions, not exceptional proof that the design has failed.
Define an explicit state for each unresolved relationship. Options might include pending match, rejected match, needs human review, or permanently unavailable. Record the reason and the next action. A queue or review list is usually safer than silently creating a second customer from a weak match.
For merges, preserve the old identifier as an alias or redirect when the source system supports it. Update the cross-reference carefully and make the change auditable. For deletions, follow the source system’s policy instead of assuming that removing a row everywhere is always correct; some businesses need a retained reference for invoices, support history, or reporting.
Validate identifiers at the API boundary
When data enters an integration, validate the identifier’s shape, scope, object type, and required companion fields. Reject a customer ID in an order-ID field even if both happen to be strings. Check that a referenced identifier belongs to the expected account or tenant before applying an update.
Return an actionable error that identifies the failed relationship without exposing sensitive data. Capture a correlation or request ID so an operator can trace the event through logs. If the integration can safely retry, make sure the retry does not create a new mapping or duplicate record.
Test the mapping before expanding the integration
Start with a small set of representative cases: a new record, an update to a display field, a missing match, a duplicate candidate, a merge, a delayed response, and a retry. Verify both the data result and the operational result. Can someone tell why a match was accepted? Can they find the unresolved cases? Can the team restore a mapping after an accidental change?
Test with realistic variation, but do not copy sensitive production data into a test system without an approved process. Mask or synthesize values while preserving the shapes and edge cases that matter.
A practical starting checklist
- List the objects that cross system boundaries.
- Assign an owner and authoritative identifier to each object.
- Document identifier scope and allowed relationships.
- Create a cross-reference table where IDs cannot be shared directly.
- Define states for missing, duplicate, merged, and deleted records.
- Validate IDs at the integration boundary and log safe trace references.
- Test normal and failure cases before adding more systems or fields.
Stable identifiers will not solve every integration problem, but they make the important decisions visible. That gives a small business a clearer foundation for reliable APIs, custom applications, and workflow automation.
Next step: Schedule a short consultation to identify the next useful improvement.