Event-Driven PIM to Informatica MDM Product Master: inRiver Listener, MuleSoft Pull-and-Validate, B360 Connector Upsert Deliverable: A Mule 4 integration that receives inRiver PIM entity events, pulls the current entity from the inRiver REST API, validates and maps it to a canonical product, and writes it into Informatica MDM SaaS (Business 360, Product 360 Item) with the Informatica B360 connector, keyed on sourceSystem plus the inRiver entity ID. Every product change reaches the trusted master within seconds, bad records land in a dead-letter path with a reason, and nothing is written back to the PIM. Objective: Product data usually reaches commerce and analytics through a batch export from the PIM: a nightly file, a custom importer, and a storefront catalog load. When a value is malformed, the importer often swallows it and exits clean, so nobody learns of the gap until a product page is wrong. An MDM product master fixes the trust problem only if it is fed continuously and every rejected record is visible. This blueprint adds that feed as a branch beside the existing pipeline: it reads from the PIM's public API and listens to its events, so the PIM team and any current export partner keep their build untouched. What's Getting Built PIM event relay (inRiver Augmenta listener extension, container hosted by inRiver) — receives inRiver's entity events and forwards entity ID plus action to MuleSoft · POST /api/listeners/EntityCreated, POST /api/listeners/EntityUpdated, POST /api/listeners/EntityDeleted, GET /health/ready, GET /health/live Product events API (Process API, Mule app) — accepts the relay, deduplicates, queues, orchestrates pull, validate and upsert · POST /pim/events, GET /health inRiver System API (System API, HTTP connector) — reads the current entity from inRiver · GET /api/v1.0.0/entities/{entityId}/fieldvalues, GET /api/v1.0.0/entities/{entityId}/summary, GET /api/v1.0.0/entities/{entityId}/links Product master target (Informatica B360 connector 1.0.x, MDM SaaS) — Create Entity, Read Entity, Update Entity, Partial Update Entity, Delete Entity, Restore Entity, Search · POST, GET, PUT, PATCH, DELETE on /business-entity/public/api/v1/entity/{objectType} Dead-letter queue and reprocess (Anypoint MQ or your broker) — holds rejected entities with the rule that failed · POST /pim/reprocess/{entityId} Prerequisites inRiver: a REST API key for the target environment (a key is tied to a user with Portal access, so ask for a dedicated integration user) and the environment's API base URL ({inriver-base}). inRiver has no webhook-URL screen; event delivery needs an Augmenta listener extension deployed by someone with extension rights. Confirm whether the tenant runs Augmenta (container extensions) or the classic Remoting-based extension model before you plan the relay. Informatica IDMC: an org with MDM SaaS and Product 360, a user for the integration, and the login host for your pod. The connector logs in with username and password and keeps the session itself. If the org uses JWT authentication for sessions, keep it; switching org auth modes breaks other API clients. MDM configuration done before the first load: a source system defined for the PIM (for example inriver), its trust ranking against other sources, the Item match model, and data quality rules. Publish the match model before loading anything. Records stored before a model is published are not re-matched later. Anypoint: Mule runtime 4.6 or later (the B360 connector's minimum), the Informatica B360 connector from Exchange (com.mulesoft.connectors:mule4-informatica-b360-connector), HTTP connector, Object Store v2, and a queue. Scope agreement: which inRiver entity types (Product, Item, ChannelNode, Resource) map to which MDM entities. Agree this with the PIM owner in writing; it is the decision that takes longest. Choose your path Event-driven relay (recommended) — Choose this when you can deploy an Augmenta listener extension. Latency is seconds and you call inRiver only for entities that changed. Scheduled poll — Choose this when no extension can be deployed. A Mule Scheduler queries inRiver for changed entities since a watermark and feeds the same pull, validate and upsert steps. Confirm that your inRiver environment supports the "changed since" query you plan to use before committing to this path. Initial load — For both paths, backfill with an Informatica bulk ingress job (POST /job/public/api/v1/jobInstance/Ingress), not with millions of single-entity calls. The event flow handles change after the backfill. Architecture 1. Relay inRiver events, don't push full records inRiver calls your extension container at fixed routes: POST /api/listeners/EntityCreated, /EntityUpdated, /EntityDeleted, /LinkCreated, /LinkDeleted. Each request carries headers customerSafeName, environmentSafeName, environmentId and extensionId, and a body with id (UUID), numericId, timestamp, correlationId and, for updates, a fields array of changed fieldTypeIds. Keep the extension tiny: validate the body, POST { "numericId", "action", "timestamp", "correlationId", "changedFields" } to POST /pim/events, and return 204. Parse both application/json and application/cloudevents+json. The extension reads its settings (MuleSoft URL, client credentials) from extension settings, which arrive as base64 environment variables named SETTING_{name}. Send IDs, not records. The event is a hint that something changed; MuleSoft pulls the authoritative current state in step 3. That makes out-of-order or duplicated events harmless, because every pull returns the latest version. Return non-2xx when MuleSoft refused the event, so the failure shows in the extension's logs. 2. Accept, deduplicate and order in the Process API POST /pim/events validates the envelope, protects itself with client ID enforcement, writes to a queue and returns 202. Don't call inRiver or Informatica on the request thread. Deduplicate on correlationId in Object Store with a short TTL; bulk PIM edits fire bursts of events for one entity. Process one entity at a time per numericId (message group or a keyed lock), so a create and an update of the same entity never race into two MDM calls. Cap concurrency toward inRiver below its documented 10 concurrent requests per environment, leaving headroom for other users. 3. Pull the current entity from inRiver Call GET {inriver-base}/api/v1.0.0/entities/{numericId}/fieldvalues with header X-inRiver-APIKey. Add ?fieldTypeIds= only if you've decided to patch changed fields; for a master, pull the full set so the record is complete. Use /summary for entity type and /links for parent or category relationships. inRiver's request timeout is 230 seconds. Set the Mule HTTP request timeout below it and retry 429 and 5xx with backoff, not 4xx. On 404 for an update event, the entity may have been deleted after the event fired. Confirm with GET /api/v1.0.0/entities/{numericId}/summary before routing it as a delete; if that call fails, or returns anything other than a clean 404, send the event to dead letter instead. A transient error or a key without access must never soft-delete a master's source record. Exchange has no inRiver connector; use the HTTP connector and publish the System API spec for reuse. 4. Map and validate before anything reaches MDM Map inRiver field values to a canonical product in DataWeave, then to the Item shape. Field names in MDM read responses are unprefixed (identifier, brand, status, description[].productTitle), while search responses prefix them (p360item.brand). Map to the read form. If the entity metadata endpoint returns 404, read field names off a real record with Read Entity. Key the master on the PIM entity, never on a part or catalog number. A single physical part number is often shared by many sellable variants, so a part-number key collapses distinct variants into one record. Split packed values. PIMs and storefront exports often pack two languages into one string with a delimiter, or stuff configuration attributes into generic option fields. Split them into language-tagged values and named attributes in the mapping, not downstream. Treat conditional attributes as conditional. An attribute that applies only to one product generation may show low coverage by design. Encode "required when" rules, not "always required" rules, or you'll dead-letter valid records. Never send a literal null for an empty field. MDM stores it as the string "null". Omit the field or send "". Fail closed: any record that fails a rule goes to the dead-letter queue with entity ID, rule name, field and value. It is never written partially and never silently dropped. Records that are incomplete but valid (missing dimensions, offline on every site) go through with a data steward flag, not to dead letter. 5. Upsert into Product 360 with the B360 connector Configure the connector with the v3 connection (login POST /saas/public/core/v3/login, session header IDS-SESSION-ID). It rewrites the pod URL to the MDM host and refreshes the session on 401 itself. Create: Create Entity with Object Type p360.item, Source System {your-pim-source-system}, Source Primary Key = the inRiver entity ID. It POSTs to /business-entity/public/api/v1/entity/p360.item?sourceSystem=…&sourcePKey=… without a business ID, so the match model decides which master the record joins. The response is { "approvalRequired", "id", "businessId" }. Crosswalk: store inRiver entity ID → businessId in Object Store from each create response. On an update event, use Partial Update Entity (JSON Patch: [{ "op", "path", "value" }]) or Update Entity (full replacement; every mandatory field must be present) against that business ID. Turn on Resolve Crosswalk when the PIM sends picklist values that MDM must standardize for that source system. Cache miss: connector 1.0.x has no read-by-source-key operation. Before creating, check MDM with GET /business-entity/public/api/v1/entity/p360.item/{sourceSystem}/{sourcePKey} through an HTTP request, or a Search on the identifier. A 404 whose detail says the resource "does not exist" means create; a hit returns the existing master, whose business ID goes into the crosswalk. Don't assume Create behaves as an upsert for a key that already exists; prove it in your tenant first (see Testing). Delete: Delete Entity with the source system and source key soft-deletes only the PIM's source record, so the master survives if other sources contribute. Restore Entity reverses it. Map connector errors: RATE_LIMITED and SERVER_BUSY retry with backoff (Informatica's limits reset continuously); BAD_REQUEST goes to dead letter with the response body; UNAUTHORIZED after the connector's own refresh means credentials, so alert, don't retry. 6. Security and compliance Credentials (inRiver key, IDMC user, relay client credentials) live in secure properties or a vault, never in the extension image or the repo. Least privilege: the inRiver key reads only. The IDMC user gets create, update and delete on in-scope MDM entities, nothing in Administrator. Logging: log entity ID, event action, correlation ID, MDM business ID, rule outcome and status codes. Do not log API keys, session IDs, or full field payloads at INFO. Audit: the source system plus source key on every MDM record gives lineage from the master back to the PIM entity. Keep dead-letter messages until a steward closes them. Sample payload — event in, MDM create out { "event": { "numericId": 4711, "action": "EntityUpdated", "timestamp": "2026-11-05T15:04:05Z", "correlationId": "{correlation-id}", "changedFields": ["ProductName", "ProductBrand"] }, "mdmCreateRequest": { "identifier": "4711", "brand": "{brand}", "description": [ { "productTitle": "{product title}", "descriptionLanguage": { "Code": "English" } } ] }, "mdmCreateResponse": { "approvalRequired": false, "id": "{record-id}", "businessId": "{business-id}" } } The create goes to p360.item with sourceSystem={your-pim-source-system} and sourcePKey=4711. Deterministic checks POST /pim/events with a valid envelope returns 202 and the entity appears in MDM, readable by source key, within your agreed latency. Replaying the same event (same correlationId) produces no second MDM call. Replaying a different event for the same entity produces an update, never a second source record. An entity that fails a validation rule never reaches MDM; it appears in the dead-letter queue with entity ID, rule and field. A delete event soft-deletes the PIM source record only; a master with other contributing sources stays active. A 404 from inRiver that the summary check doesn't confirm goes to dead letter, never to Delete Entity. No literal "null" string appears in any MDM field written by this flow. Concurrency to inRiver never exceeds the configured cap; a burst of 500 events completes without inRiver 429s. MUnit: one test per mapping rule against captured inRiver responses, one per error type (RATE_LIMITED, BAD_REQUEST, 404 from inRiver), and the dedupe and ordering cases. Testing and validation Happy path: change one field on one product in inRiver and follow it through the extension log, the queue, the inRiver pull and the MDM read by source key. The edge case that breaks naive builds is the second write for an existing key. Before go-live, create one test record, then send a second create with the same source system and source key, and record what your tenant does (update, duplicate source record, or error). Build the crosswalk on what you observed. The endpoints, event schemas and connector operations here come from inRiver's published extension spec, the connector itself and reads against a live MDM tenant; the full write path has not been run end to end, so this test is the gate. Second edge case: records loaded before the match model was published are never re-matched. Run the first load only into an empty entity with the model published. Prove mapping correctness, not just delivery: compare a sample of MDM records field by field with the inRiver values, including split language values and conditional attributes. Phased rollout Phase 1 — Connect Prove the inRiver key against GET /api/v1.0.0/entities/{id}/fieldvalues, prove the B360 connector login with a Read Entity, and deploy a listener extension that only logs events. Phase 2 — Map and validate Define the source system and publish the match model, backfill with an ingress job, then turn on the event flow for one entity type. Run the second-create test and the field-by-field comparison. Phase 3 — Production Add the remaining entity types, alert on dead-letter depth and upsert latency, hand triage to data stewards, and keep the batch export running until the master is trusted. Success metrics Time from a PIM change to the MDM master updating (p50 and p95). Records rejected per day, by rule, and the age of the oldest open dead-letter item. Share of PIM entities in scope that have an MDM master (target: all). Product data defects reported downstream that trace to the PIM-to-master leg (target: zero silent drops). Troubleshooting Events never arrive in MuleSoft — Likely cause: the extension isn't registered for the event type, or a SETTING_{name} is missing or not base64. Fix: check its health endpoints and logs; post a test event locally first. inRiver returns 401 — Likely cause: wrong header name or a key for another environment. Fix: send X-inRiver-APIKey, and use the API host for the environment the key was issued in. inRiver returns 429 or requests time out during bulk edits — Likely cause: more than 10 concurrent requests per environment. Fix: lower the Mule concurrency cap and queue the rest. MDM field shows the text "null" — Likely cause: a literal null in the payload. Fix: omit empty fields in the DataWeave mapping. Two masters for one PIM entity, or masters merging variants that should be distinct — Likely cause: keyed on part number, or a loose match rule on title. Fix: key on the PIM entity ID and tighten the Item match rules; unmerge in MDM. New records never match existing masters — Likely cause: the records were loaded before the match model was published. Fix: publish first, then reload into an empty entity. Create succeeds but search doesn't find the record — Likely cause: search index lag. Fix: verify by business ID or source key.