The scenario
Meridian Trust Bank is a retail bank. Card transactions live in the core banking system and land in Amazon S3 as nightly extracts. Loans live in a separate origination system. Mobile app events stream into Snowflake. Service and sales run on Salesforce.
The same customer exists in all four systems — as four unrelated records. A rep taking a call sees a Contact and a few Cases. They can't see that the caller holds two cards, is three years into a mortgage, and stopped opening the app six weeks ago. Marketing, meanwhile, keeps emailing card offers to people who already own that card.
This is the problem Data 360 (formerly Data Cloud) exists to solve: turn scattered records into one unified customer profile that the whole platform — Flow, Apex, Agentforce, analytics — can act on. In this post we build Meridian's profile end to end and, along the way, cover the concepts you'll use in every Data 360 project.
For beginners: think of Data 360 as a lakehouse bolted onto your org. Data stays big and raw over there; Salesforce gets a clean, stitched-together view of each customer over here.
The pipeline in one picture
Every Data 360 implementation is the same five stages. Meridian's build maps onto them directly:
- Ingest — bring in card, loan and app-usage data through data streams.
- Harmonize — map each source's fields onto a shared data model.
- Resolve identity — match records across sources into one unified profile per human.
- Compute insights — derive metrics like lifetime value with Calculated Insights.
- Activate — push the results into segments, CRM fields, flows, agents and dashboards.
Parts 2–5 of this series go deep on stages 4 and 5. This post covers the foundation: stages 1–3, plus how to query the results as a developer.
Stage 1 — Ingestion: data streams and DLOs
A data stream is a configured feed from one source. For Meridian:
- Card transactions: an Amazon S3 connector pointed at the nightly extract bucket, scheduled to refresh after the core banking batch finishes.
- Loans: the origination system exports CSV to the same bucket — a second S3 stream.
- App events: the Snowflake data lives where it is. With zero copy, Data 360 queries it in place — no duplication, no sync jobs.
- CRM data: the built-in Salesforce connector ingests Contact, Case and Account with a few clicks.
Each stream lands in a Data Lake Object (DLO) — a raw, source-shaped table. When you create a stream you assign it a category: Profile (who someone is — the loan holder file), Engagement (things that happened — card transactions, app events) or Other (reference data — branch list).
Stage 2 — Harmonization: DLOs become DMOs
Raw DLOs are useless for cross-source questions because every system names things differently: cust_no in core banking, borrower_id in the loan system, ContactId in CRM. Harmonization fixes that by mapping each DLO onto Data Model Objects (DMOs) — a shared, standardized schema based on the Customer 360 data model.
For Meridian, the mapping looks like this:
- Loan-holder and cardholder records map to the standard Individual DMO (
ssot__Individual__dlm) — one source profile per system. - Emails and phone numbers map to Contact Point Email and Contact Point Phone — identity resolution will need them.
- Card transactions map to a custom Card Transaction DMO; there's no standard object for them, and custom DMOs are fine.
- App events map to a custom App Session DMO with the event-time field as its engagement timestamp.
Mapping is point-and-click in the Data 360 UI: open the DLO, choose the target DMO, connect fields. The payoff is that every downstream feature — insights, segments, agents — works against one vocabulary instead of four.
Stage 3 — Identity resolution: four records, one human
After harmonization Meridian has three Individual source profiles for the same customer. Identity resolution stitches them together using a ruleset with two parts:
- Match rules decide when two source profiles are the same person. Meridian starts conservative: exact match on normalized email, OR exact phone plus fuzzy first name and exact last name.
- Reconciliation rules decide which value wins when sources disagree — e.g. "last updated" for mailing address, "source priority: core banking first" for legal name.
The output is a set of Unified Individual records, each linked back to its source profiles through link DMOs. Nothing is deleted or merged destructively — the unified profile is a computed layer on top, and it recomputes as new data arrives.
DMOs vs sObjects: know which world you're in
The biggest mental shift for a Salesforce developer is that DMOs are not sObjects. They look similar in the UI and end in a suffix, but they behave differently in almost every way that matters:
| Aspect | sObjects | DMOs |
|---|---|---|
| Storage | Transactional CRM database | Lakehouse storage alongside the org |
| Naming | Account, My_Object__c | ssot__Individual__dlm, Card_Transaction__dlm |
| Query language | SOQL | ANSI SQL via the Query API (joins, aggregates, window functions) |
| Writes | Full CRUD from Apex, Flow, API | Populated by ingestion and mapping; you don't insert into a DMO from Apex |
| Reacting to changes | Apex triggers, record-triggered flows | Data actions and Data 360–triggered flows (Part 4) |
| Row scale | Millions, with storage costs that bite | Billions — engagement data is the design case |
| Cost model | Storage and licenses | Consumption credits — queries and processing are metered |
That last row matters day to day: a careless SELECT * over two years of card transactions costs real money. Treat Data 360 queries like you treat callouts — deliberate, filtered and cached where possible.
Query it like a developer
Everything above is configuration. Here's where it pays off. The Query API speaks ANSI SQL against DMOs, so cross-source questions become one statement. Meridian's "active card exposure per customer":
SELECT
t.customer_id__c AS customer_id__c,
COUNT(t.card_id__c) AS active_cards__c,
SUM(t.current_balance__c) AS total_balance__c
FROM Card_Account__dlm t
WHERE t.card_status__c = 'Active'
GROUP BY t.customer_id__c
From Apex, the same query runs through ConnectApi.CdpQuery. Results come back as ordered rows plus a metadata map that tells you each column's position:
public with sharing class CardExposureService {
@AuraEnabled(cacheable=true)
public static Decimal totalActiveBalance(String customerId) {
ConnectApi.CdpQueryInput input = new ConnectApi.CdpQueryInput();
input.sql =
'SELECT SUM(current_balance__c) AS total_balance__c ' +
'FROM Card_Account__dlm ' +
'WHERE customer_id__c = \'' +
String.escapeSingleQuotes(customerId) +
'\' AND card_status__c = \'Active\'';
ConnectApi.CdpQueryOutputV2 result =
ConnectApi.CdpQuery.queryAnsiSqlV2(input);
if (result.data.isEmpty()) {
return 0;
}
Integer col = result.metadata.get('total_balance__c').placeInOrder;
Object raw = result.data[0].rowData[col];
return raw == null ? 0 : Decimal.valueOf(String.valueOf(raw));
}
}
Wire that into an LWC on the Contact page and the rep finally sees card exposure next to the Case list — data that never left the lakehouse until the moment it was asked for.
What about Calculated Insights?
Stage 4 of the pipeline is Calculated Insights: SQL-defined metrics that Data 360 computes on a schedule and stores as queryable objects — things like lifetime value, engagement score or churn risk. They deserve their own walkthrough, so that's Part 2 of this series, where a telco uses one to catch customers going quiet before they cancel.
What you learned
- Data 360 is a five-stage pipeline: ingest, harmonize, resolve identity, compute insights, activate.
- Data streams land raw data in DLOs; mapping DLOs onto DMOs gives every source one shared vocabulary.
- Identity resolution builds unified profiles non-destructively with match and reconciliation rules — start strict.
- DMOs are not sObjects: ANSI SQL instead of SOQL, no direct writes, consumption-based cost.
ConnectApi.CdpQuery.queryAnsiSqlV2puts all of it within reach of Apex and LWC.
Next in the series: Calculated Insights and segments. The full series lives on the Data 360 track page, and the grounding story continues in our Agentforce grounding walkthrough.
Sources: Salesforce Help — About Identity Resolution · Identity Resolution Rulesets · Apex Reference — CdpQuery Class · Data 360 Query API