---
cuppy_hub: salesforce
cuppy_path: reference/data360/insights-and-data-graphs.md
cuppy_section: docs
cuppy_doc: 2RC7-RKK0
cuppy_doc_uuid: 93574845-953b-45e8-b1d4-a2d22c32703f
cuppy_permalink: https://cuppy.io/salesforce/d/2RC7-RKK0
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/salesforce/docs/reference/data360/insights-and-data-graphs
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 5f83a65fe3e9b158575a4fa103b8a0a9b34617b837220dd0448e21544e189608
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Calculated insights and data graphs

## Calculated insights: revenue metrics on golden records

A calculated insight (CI) is an ANSI SQL aggregate saved as a `__cio` object. Its **dimensions** are what you group by: always the golden record's ID, plus any slices. Its **measures** are the aggregates.

Lifetime revenue per golden individual, following the join Salesforce's Trailhead query uses (sales order → link DMO → unified individual):

```sql
SELECT
  u.ssot__Id__c                                     AS unified_individual_id__c,
  SUM(o.ssot__GrandTotalAmount__c)                  AS lifetime_revenue__c,
  COUNT(o.ssot__Id__c)                              AS order_count__c,
  MAX(o.ssot__PurchaseOrderDate__c)                 AS last_order_date__c,
  SUM(o.ssot__GrandTotalAmount__c) / COUNT(o.ssot__Id__c) AS average_order_value__c
FROM ssot__SalesOrder__dlm o
JOIN IndividualIdentityLink__dlm l
  ON o.ssot__SoldToCustomerId__c = l.SourceRecordId__c
 AND o.KQ_SoldToCustomerId__c = l.KQ_SourceRecordId__c
LEFT OUTER JOIN UnifiedIndividual__dlm u ON l.UnifiedRecordId__c = u.ssot__Id__c
GROUP BY u.ssot__Id__c
```

- **Key qualifiers.** Salesforce's query also matches the `KQ_` key-qualifier columns, which keep IDs from different sources apart. The exact link-DMO column names above are the hub's reading. Confirm them with `GET /ssot/data-model-objects/{name}`.
- **Account revenue.** Group `ssot__BillToAccountId__c` through the account link DMO to the unified account instead.
- **Output columns** end in `__c`. Name them as you want them to appear in prompts and in the search-index narrative.

**API** (under `/services/data/v66.0/ssot`):

| Call | Endpoint |
|---|---|
| List or create | `GET` / `POST /calculated-insights`. The body takes `apiName` (must end `__cio`), `displayName`, `definitionType`, `expression`, and optionally `dataSpaceName`, `description` and `draft` |
| Run now | `POST /calculated-insights/{apiName}/actions/run` (path per the community plugin). A data kit sets a `publishInterval` |
| Read rows | Query the `__cio` with `query-sql`, like any object |

- `definitionType` is `CalculatedMetric` (batch), `StreamingMetric` or `ExternalMetric`. Revenue rollups are `CalculatedMetric`.
- **Create the insight before the search index and data graph that read it**, and run it after each identity resolution run, so metrics follow the latest golden records.

## Data graphs: a golden record with its orders, as one document

A data graph precomputes a root DMO (for example `UnifiedIndividual__dlm`) with related objects (link records, sales orders and products, insights) into a JSON record per root ID. That's the shape a prompt wants: *this* customer with *their* orders, in one lookup.

| Call | Endpoint (community plugin, reconciled to Salesforce's v67 spec) |
|---|---|
| Definitions | `GET /data-graphs/metadata` |
| Refresh | `POST /data-graphs/{name}/actions/refresh` |
| Read one record | `GET /data-graphs/data/{name}`, scoped to one record ID. The community plugin builds the ID into the path; confirm the exact form in the spec |

- **Use a data graph for "tell me about this account"**: grounding by a known ID, in real time.
- **Use a search index for "find accounts like this" or "who is ready to buy"**: semantic or hybrid search across many golden records (`reference/data360/search-indexes-and-retrievers.md`).
- The revenue pipeline uses both (`patterns/golden-record-rag-pipeline-for-revenue.md`).
- **In an agent**, a flow that queries Data 360 is the action Salesforce's workshop uses ("Get Merchant Order Insights"). Prompt Builder templates can ground on Data 360 too (family 6).

## Failures

| Symptom | Cause → fix |
|---|---|
| CI create rejected | `apiName` lacks `__cio`, the SQL isn't an aggregate grouped by a key, or a column lacks `__c` |
| CI is empty | Identity resolution hasn't run, or the join misses the key qualifier and matches nothing. Count rows at each join with `query-sql` |
| Revenue double-counted | Joining order lines (Sales Order Product) and orders in the same aggregate. Aggregate lines in a sub-query first |
| Data graph returns stale orders | It hasn't refreshed since the last ingest. Refresh after the CI run |
| Data graph read 404 | The wrong root ID: use the **unified** ID, not the CRM Account or Contact ID |


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 376 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/salesforce/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
