This card covers cross-ERP Master Data Management — the architecture, survivorship logic, and synchronization patterns needed to maintain a single golden record across multiple ERP and CRM systems. It is platform-agnostic but references the four dominant MDM platforms for concrete implementation details. This card does NOT cover single-system data governance, product information management (PIM), or one-time data migration.
| System | Role | API Surface | Direction |
|---|---|---|---|
| MDM Hub (Informatica / Reltio / Profisee) | Golden record authority, match/merge engine | REST, GraphQL, Streaming | Hub <-> All systems |
| SAP S/4HANA | ERP — financial master, material master | OData v4, RFC/BAPI, IDocs | Bidirectional |
| Salesforce | CRM — customer/account master | REST v62.0, Bulk API, Platform Events | Bidirectional |
| Oracle ERP Cloud | ERP — financials, procurement | REST, FBDI | Bidirectional |
| NetSuite | ERP — mid-market financials, inventory | SuiteTalk REST/SOAP | Bidirectional |
| Microsoft Dynamics 365 | ERP/CRM — sales, finance, supply chain | OData v4, Dataverse API | Bidirectional |
MDM platforms expose APIs for match, merge, golden record CRUD, survivorship configuration, and event subscription.
| MDM Platform | Match API | Golden Record API | Event/CDC | Bulk Import | Latency (p95) | Auth |
|---|---|---|---|---|---|---|
| Informatica IDMC | REST /match | REST /entity CRUD | Kafka, webhooks | CSV batch, 300+ connectors | ~500ms | OAuth 2.0 |
| Reltio | REST /entities/match | REST /entities, GraphQL | Streaming API, webhooks | REST bulk, S3 ingest | <300ms | OAuth 2.0, API key |
| SAP MDG | RFC/BAPI match | OData entity CRUD, staging workflow | IDocs, AIF, CPI events | FBDI, batch input | ~1-2s (approval workflow) | SAP OAuth, X.509 |
| Profisee | REST /match | REST /records CRUD | Webhooks, Azure Event Grid | REST bulk, Azure Data Factory | ~400ms | OAuth 2.0, Azure AD |
| ERP System | Read API | Write API | CDC/Events | Bulk | Rate Limit |
|---|---|---|---|---|---|
| SAP S/4HANA | OData v4 | OData v4, BAPI | Business Events, AIF | IDocs batch | Fair-use, throttled |
| Salesforce | REST SOQL, Bulk API 2.0 | REST, Composite | Platform Events, CDC | Bulk API 2.0 (150MB/file) | 100K calls/24h (Enterprise) |
| Oracle ERP Cloud | REST | REST, FBDI | Business Events | FBDI (250MB/file) | Throttled per tenant |
| NetSuite | SuiteTalk REST/SOAP | SuiteTalk REST/SOAP | User Event Scripts, SuiteScript | CSV import, SuiteTalk lists | 10 concurrent requests |
| Dynamics 365 | Dataverse OData v4 | Dataverse OData v4 | Webhooks, Azure Service Bus | Data Import wizard | 6K requests/5min per user |
| Platform | API Calls | Concurrent Requests | Bulk Import Size | Match Throughput |
|---|---|---|---|---|
| Informatica IDMC | Tier-based (contract) | 50 concurrent (default) | 500K records/batch | ~10K matches/min |
| Reltio | Tier-based (contract) | 100 concurrent (Enterprise) | 1M records/bulk load | ~50K matches/min (FERN) |
| SAP MDG | No hard API limit (shared with S/4) | Work process pool (configurable) | Unlimited (batch input) | ~5K matches/min (HANA) |
| Profisee | Tier-based (contract) | 25 concurrent (default) | 100K records/batch (REST) | ~8K matches/min |
| Limit Type | Informatica | Reltio | SAP MDG | Profisee |
|---|---|---|---|---|
| Max records per query | 1,000 | 10,000 | 500 (OData default) | 5,000 |
| Max payload size | 10 MB | 50 MB | 100 MB (IDoc) | 25 MB |
| Match candidates returned | 50 (default) | 100 (configurable) | 20 (default) | 50 (default) |
| Golden record merge limit | 10 records/merge | 50 records/merge | 5 records/merge (workflow) | 20 records/merge |
| Platform | Flow | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| Informatica IDMC | OAuth 2.0 client credentials | 30 min | Yes | Service-to-service recommended |
| Reltio | OAuth 2.0, API key | 1h (OAuth), permanent (API key) | Yes (OAuth) | API key for dev; OAuth for production |
| SAP MDG | OAuth 2.0, X.509, SAML | Session-based (configurable) | Yes | X.509 for server-to-server |
| Profisee | OAuth 2.0 / Azure AD | 1h | Yes | Azure AD integration native |
START — User needs cross-ERP Master Data Management
├── What's the primary use case?
│ ├── Analytics / reporting only (no writeback needed)
│ │ └── CONSOLIDATION style
│ │ ├── Batch ETL from all ERPs nightly
│ │ ├── Match/merge → golden records
│ │ └── Feed BI/analytics; source ERPs unchanged
│ ├── Cross-reference lookup (which records match across systems?)
│ │ └── REGISTRY style
│ │ ├── MDM hub as index/cross-reference only
│ │ ├── Minimal disruption, fast deployment
│ │ └── WARNING: Rarely viable in production — data quality stays poor
│ ├── Operational sync (golden records used in real-time operations)
│ │ ├── Can you designate one hub as sole master data author?
│ │ │ ├── YES → CENTRALIZED style (18-24+ months, most disruptive)
│ │ │ └── NO → COEXISTENCE style (most common enterprise pattern)
│ │ │ ├── MUST define per-attribute ownership rules
│ │ │ └── MUST implement conflict resolution before go-live
│ │ └── How many data domains?
│ │ ├── Single domain → 3-6 months
│ │ ├── 2-3 domains → 9-12 months
│ │ └── Enterprise-wide → 12-18+ months
│ └── Hybrid (different styles per domain)
│ ├── Customer data → coexistence (operational)
│ ├── Product data → consolidation (analytics)
│ └── Vendor data → centralized (procurement-owned)
├── Which MDM platform?
│ ├── SAP-heavy landscape → SAP MDG (native integration)
│ ├── Multi-vendor, cloud-first → Reltio (<300ms, LLM matching)
│ ├── Enterprise, 100+ sources → Informatica IDMC (300+ connectors)
│ └── Microsoft/Azure stack → Profisee (Azure-native)
└── What middleware for ERP sync?
├── SAP CPI → SAP-to-SAP + SAP-to-cloud
├── MuleSoft → Multi-vendor, API-led connectivity
├── Boomi → Cloud-to-cloud, rapid deployment
└── Azure Integration Services → Microsoft ecosystem
| Rule Type | How It Works | Best For | Example |
|---|---|---|---|
| Source priority | Rank source systems per attribute; highest-rank wins | Regulated environments with clear data ownership | CRM owns email; ERP owns billing address |
| Most recent | Newest timestamp wins for the attribute | Frequently changing data (phone, email) | CRM phone updated yesterday; ERP has last year's → CRM wins |
| Frequency | Most common value across sources wins | Stable attributes with many sources | 3 of 4 systems say "New York"; 1 says "NY" → "New York" wins |
| Completeness | Most complete (non-null) value wins | Sparse data environments | CRM has name + email; ERP has name only → CRM email survives |
| Aggregation | Combine values from multiple sources | Multi-valued attributes | Merge all known phone numbers, deduplicate |
| Conditional | Apply different rules based on data context | Complex business rules | If country = US, trust ERP for tax ID; if EU, trust CRM |
| Stacked (composite) | Chain rules: try priority first, fall back to recency | Production environments needing fallback | Trust CRM for email → if null, use most recent from any source |
| Capability | Registry | Consolidation | Coexistence | Centralized |
|---|---|---|---|---|
| Golden record persistence | No (federated) | Yes (read-only) | Yes (read-write) | Yes (authoritative) |
| Source system changes | None | None | Writeback to sources | Sources become read-only |
| Sync direction | Read-only from sources | Sources → hub | Bidirectional | Hub → sources |
| Implementation time | 4-8 weeks | 3-6 months | 9-18 months | 18-24+ months |
| Governance strength | Low | Medium | Medium-High | Highest |
| Disruption level | Minimal | Low | Medium | High |
| Data quality improvement | Minimal | Moderate | High | Highest |
| Real-time operational use | Limited | No (batch) | Yes | Yes |
| Conflict resolution needed | No | No | Yes (critical) | No (single author) |
| Production prevalence | Rare | Common (starting point) | Most common | Aspirational |
Map all systems that create or consume master data. For each data domain, identify the current system of record and data quality issues. [src6]
# Inventory: list all systems with master data
# system,domain,records,dup_rate,completeness,api,update_freq,sor
# SAP S/4HANA,vendor,150000,8%,92%,"OData v4, BAPI",real-time,yes
# Salesforce,customer,500000,15%,78%,"REST v62.0, Bulk API",real-time,yes
# NetSuite,customer,200000,12%,85%,"SuiteTalk REST",hourly,no
Verify: Complete system inventory with duplicate rates and data quality scores for each domain.
Define matching criteria (deterministic + probabilistic) and attribute-level survivorship rules before touching any technology. [src2, src3]
# Match key design for Customer domain
match_rules:
- name: "exact_match"
type: deterministic
keys: ["tax_id"]
action: auto_merge
- name: "fuzzy_match"
type: probabilistic
keys:
- field: "company_name"
algorithm: "jaro_winkler"
threshold: 0.85
min_score: 0.90
action: auto_merge
# Survivorship rules
survivorship:
customer_name:
rule: source_priority
priority: [CRM, ERP]
fallback: most_recent
billing_address:
rule: source_priority
priority: [ERP, CRM]
email:
rule: most_recent
require_valid_format: true
tax_id:
rule: source_priority
priority: [ERP]
Verify: Every attribute in your golden record has an explicit survivorship rule with fallback.
Deploy the MDM platform, configure match/merge rules, and perform initial bulk load from all source systems. [src1]
# Reltio initial data load via REST API
import requests
RELTIO_BASE = "https://{tenant}.reltio.com/reltio/api/{tenant_id}"
HEADERS = {"Authorization": "Bearer {token}", "Content-Type": "application/json"}
def load_entities_bulk(entities, entity_type="configuration/entityTypes/Customer"):
BATCH_SIZE = 1000
for i in range(0, len(entities), BATCH_SIZE):
batch = entities[i:i + BATCH_SIZE]
payload = [{"type": entity_type, "attributes": {...}, "crosswalks": [...]} for e in batch]
resp = requests.post(f"{RELTIO_BASE}/entities", headers=HEADERS, json=payload)
if resp.status_code == 429:
sleep(2) # Rate limit backoff
Verify: GET /entities?filter=crosswalks.type==*&max=1 returns entities with cross-references.
Set up event-driven sync between ERP systems and the MDM hub using CDC or Platform Events. [src1, src4]
# Salesforce CDC -> MDM Hub sync
def process_cdc_event(event):
changed_fields = event["payload"]["ChangeEventHeader"]["changedFields"]
delta_payload = {field: event["payload"][field] for field in changed_fields if field in FIELD_MAP}
mdm_client.update_entity(crosswalk=("Salesforce", event["recordId"]), attributes=delta_payload)
Verify: Update a record in Salesforce, wait <5s, verify golden record in MDM hub reflects the change.
Configure automated and manual conflict resolution for bidirectional sync scenarios. [src1, src2]
# Conflict detection: competing updates within 60s window
def resolve_conflict(golden_record, update_a, update_b, survivorship_rules):
for attr in conflicting_attrs:
rule = survivorship_rules.get(attr)
if rule["rule"] == "source_priority":
# Higher-priority source wins
elif rule["rule"] == "most_recent":
# Newer timestamp wins
else:
create_stewardship_task(golden_record["id"], attr) # Manual review
Verify: Simulate a conflict — update same customer in two ERPs within 60s. Confirm survivorship resolves or creates stewardship task.
# Input: Source system extracts (JSON) from SAP, Salesforce, NetSuite
# Output: Golden records created in MDM hub with cross-references
import requests
from time import sleep
def load_entities_bulk(entities, base_url, headers, batch_size=1000):
results = {"created": 0, "matched": 0, "errors": 0}
for i in range(0, len(entities), batch_size):
batch = entities[i:i + batch_size]
resp = requests.post(f"{base_url}/entities", headers=headers, json=batch)
if resp.status_code == 200:
r = resp.json()
results["created"] += r.get("created", 0)
results["matched"] += r.get("matched", 0)
elif resp.status_code == 429:
sleep(2)
continue
else:
results["errors"] += len(batch)
return results
# Input: OAuth token, entity attributes to match
# Output: List of potential duplicate entities with match scores
curl -X POST "$RELTIO_BASE/entities/match" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "configuration/entityTypes/Customer",
"attributes": {
"Name": [{"value": "Acme Corporation"}],
"PostalCode": [{"value": "10001"}]
}
}' | jq '.potentialMatches[] | {uri, score, attributes.Name}'
# Expected: Array of match candidates with scores 0.0-1.0
| MDM Golden Field | SAP S/4HANA | Salesforce | Oracle ERP Cloud | NetSuite | Gotcha |
|---|---|---|---|---|---|
| Customer Name | BP_NAME (BUPA) | Account.Name | HZ_PARTIES.PARTY_NAME | customer.companyName | SAP max 40 chars; SF max 255 |
| Address Line 1 | ADRC.STREET | Account.BillingStreet | HZ_LOCATIONS.ADDRESS1 | customer.defaultAddress.addr1 | SAP structured; SF freeform |
| Postal Code | ADRC.POST_CODE1 | Account.BillingPostalCode | HZ_LOCATIONS.POSTAL_CODE | customer.defaultAddress.zip | Format varies by country |
| Country | ADRC.COUNTRY (ISO 2) | Account.BillingCountry (full name) | HZ_LOCATIONS.COUNTRY (ISO 2) | customer.defaultAddress.country (ISO 2) | SF stores "United States"; others use "US" |
| Tax ID | DFKKBPTAXNUM.TAXNUM | Account.Tax_ID__c | ZX_REGISTRATIONS.REGISTRATION_NUMBER | customer.defaultTaxReg | Format validation per jurisdiction |
| ADR6.SMTP_ADDR | Contact.Email | HZ_CONTACT_POINTS.EMAIL_ADDRESS | customer.email | SAP may have multiple via ADR6 | |
| Phone | ADR2.TEL_NUMBER | Account.Phone | HZ_CONTACT_POINTS.PHONE_NUMBER | customer.phone | Enforce international format (+code) |
| Credit Limit | KNKK.KLIMK | Account.Credit_Limit__c | HZ_CUST_ACCT_SITES.CREDIT_LIMIT | customer.creditLimit | Currency conversion required |
| Payment Terms | KNB1.ZTERM | Account.Payment_Terms__c | RA_TERMS.NAME | customer.terms.name | Code vs. description mismatch |
| Error Pattern | Cause | Impact | Resolution |
|---|---|---|---|
| Over-merge (false positive) | Match keys too loose | Distinct customers merged; orders misattributed | Tighten thresholds; add negative match rules |
| Under-merge (false negative) | Match keys too strict | Same customer exists as multiple golden records | Add fuzzy matching; normalize data before matching |
| Sync loop (ping-pong) | No change-origin tracking | Infinite loop: ERP A → hub → ERP A → hub... | Tag changes with source system; skip writeback to origin |
| Stale golden record | Batch sync delay (24h) | Agent sees yesterday's data in operational context | Move to coexistence/centralized; add CDC for critical fields |
| Race condition | Two ERPs update same attribute within sync window | Last-write-wins picks wrong value | Per-attribute ownership; vector clocks or priority-based resolution |
| Governance bypass | Direct API calls skipping approval workflow | Unvalidated data enters golden record | API gateway with validation middleware |
Quarterly match key effectiveness reviews; monitor false positive/negative rates. [src3]Alert on attributes without explicit rules; block new field sync until rules defined. [src2]Pin connector versions; test in sandbox after every ERP upgrade. [src1]Load in 100K batches; disable real-time matching during load; batch match/merge after. [src1]Auto-merge above 0.95, auto-reject below 0.60; manual review only 0.60-0.95. [src2]# BAD — record-level survivorship discards valuable data
survivorship:
customer_record:
rule: source_priority
winner: CRM # CRM record wins entirely
# Result: ERP billing address, credit limit, payment terms all lost
# GOOD — each attribute has its own survivorship rule
survivorship:
customer_name:
rule: source_priority
priority: [CRM, ERP]
fallback: completeness
billing_address:
rule: source_priority
priority: [ERP, CRM] # ERP owns financial data
credit_limit:
rule: source_priority
priority: [ERP] # ONLY finance system sets this
# BAD — N ERPs = N*(N-1)/2 integrations; no golden record
SAP <---> Salesforce (custom sync)
SAP <---> NetSuite (custom sync)
Salesforce <---> NetSuite (custom sync)
# 3 ERPs = 3 integrations; 5 ERPs = 10 integrations
# GOOD — N ERPs = N integrations; MDM hub is golden record authority
SAP <-> MDM Hub <-> Salesforce
|
NetSuite
# 3 ERPs = 3 integrations; 5 ERPs = 5 integrations
# BAD — sends ALL 150+ fields even if only email changed
def sync_to_mdm(salesforce_account):
mdm_client.upsert_entity(salesforce_account.to_dict())
# GOOD — only sync changed attributes
def sync_to_mdm(cdc_event):
changed_fields = cdc_event["changedFields"]
delta = {f: cdc_event["payload"][f] for f in changed_fields if f in FIELD_MAP}
mdm_client.update_entity(crosswalk=("Salesforce", cdc_event["recordId"]), attributes=delta)
# Check golden record cross-references (Reltio example)
curl -H "Authorization: Bearer $TOKEN" \
"$RELTIO_BASE/entities/{entity_uri}?options=crosswalks" | jq '.crosswalks'
# Verify survivorship — which source won for each attribute
curl -H "Authorization: Bearer $TOKEN" \
"$RELTIO_BASE/entities/{entity_uri}?options=sourceValues" | jq '.attributes'
# Check match candidates
curl -X POST "$RELTIO_BASE/entities/match" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"configuration/entityTypes/Customer","attributes":{"Name":[{"value":"Acme Corp"}]}}' \
| jq '.potentialMatches'
# Monitor stewardship queue
curl -H "Authorization: Bearer $TOKEN" \
"$RELTIO_BASE/tasks?status=OPEN&type=POTENTIAL_MATCH&max=10" | jq '.total'
# Verify sync status — last sync per source
curl -H "Authorization: Bearer $TOKEN" \
"$RELTIO_BASE/entities?filter=crosswalks.type==configuration/sources/Salesforce&max=1&orderBy=-updatedTime" \
| jq '.[0].updatedTime'
| Platform | Version | Release Date | Status | Key Changes |
|---|---|---|---|---|
| Informatica IDMC | 2025.3 | 2025-10 | Current | CLAIRE AI matching improvements; new Kafka connector |
| Informatica IDMC | 2024.3 | 2024-10 | Supported | GraphQL API GA; enhanced survivorship UI |
| Reltio | 2025.1 | 2025-03 | Current | FERN LLM matching GA; <300ms p95 latency |
| Reltio | 2024.2 | 2024-06 | Supported | Zero-shot learning matching; bulk API improvements |
| SAP MDG | S/4HANA 2023 FPS02 | 2024-04 | Current | Cloud-native deployment; improved OData APIs |
| Profisee | 2024.1 | 2024-03 | Current | Azure-native rewrite; REST API v2 |
| Use When | Don't Use When | Use Instead |
|---|---|---|
| 2+ ERP systems with overlapping master data domains | Single ERP with no external sources | Native ERP data governance (SAP MDG standalone) |
| Customer/vendor duplicates across systems cause operational issues | Data quality issues within a single system only | Data quality tools (Informatica DQ, Ataccama) |
| Regulatory compliance requires single customer view (KYC, GDPR) | Compliance met with system-level controls | Per-system compliance tooling |
| M&A integration requires merging acquired company master data | One-time migration without ongoing sync | ETL migration with reconciliation |
| 100K+ records with >5% estimated duplicate rate | <10K records with minimal duplication | Spreadsheet-based deduplication |
| Capability | Informatica IDMC | Reltio | SAP MDG | Profisee | Notes |
|---|---|---|---|---|---|
| Architecture | Cloud-native SaaS | Cloud-native SaaS | On-premise + cloud | Cloud (Azure-native) | |
| Matching Engine | CLAIRE AI (ML + rules) | FERN (LLM-powered) | HANA-based fuzzy match | Rules + ML | Reltio fastest |
| Match Latency (p95) | ~500ms | <300ms | ~1-2s (incl. workflow) | ~400ms | |
| Pre-built Connectors | 300+ | 50+ (API-first) | Native SAP, limited non-SAP | 30+ (Azure) | Informatica widest |
| Survivorship Rules | Attribute-level, stacked | Attribute-level, confidence | Field-level with workflow | Attribute-level | |
| Multi-domain | Yes | Yes (connected graph) | Yes (BP, Material, Finance) | Yes | |
| Governance Workflow | Built-in stewardship | Built-in stewardship | Full change request + approval | Built-in stewardship | SAP strongest governance |
| Deployment Time | 3-6 months | <90 days | 6-12 months | 3-6 months | Reltio fastest |
| Pricing Model | Tier (records + API calls) | Tier (entities + users) | License + SAP infra | Tier (records) | |
| Best For | Enterprise, 100+ sources | Cloud-first, real-time | SAP-heavy landscape | Microsoft/Azure stack |