ClaudforceHLS · Provider + Payer

An ordered route from an empty Salesforce org to a working Data Cloud, Marketing Cloud Next and Agentforce demo. Written from the org it was built in, verified against that org on 3 September 2026.

Connect this to your Claude

This page is an MCP server. Point your agent at it.

Everything below is also available as tools your agent can call. Connect this server for the route, the traps and the data shapes, and connect your own Salesforce org so your agent can act on it. Neither half is enough on its own: this server knows what to build and cannot touch an org; the Salesforce MCP can touch an org and does not know this build.

1. Connect this guide

claude mcp add --transport http claudforce-hls https://claudforce-hls.thelonelyagent.com/api/public/mcp

No auth. Twelve tools: start_here first, then get_guide, get_corrections, list_sections, get_section, search_traps, verify_step, list_skills, get_skill, get_dataset_schema, get_manifest, list_downloads.

2. Connect your own Salesforce org

Point your agent at your own org with the Salesforce MCP server. That is the half that does the building. This guide never touches your org and never sees your data.

How to connect your Salesforce org, step by step

You need an External Client App. Connected Apps are not supported for MCP client connections. Verified against a live org — about five minutes of setup, plus up to thirty minutes of waiting that catches most people out.

  1. In Setup, go to External Client App Manager and choose New External Client App.
  2. Give it a name. The API Name must contain no hyphens — the label can. A hyphen in the API name is a silent failure later.
  3. Set the Callback URL to https://claude.ai/api/mcp/auth_callback
  4. Add the OAuth scopes mcp_api and refresh_token. Both are required.
  5. Under security, enable JWT-based access tokens for named users, and leave PKCE on. Uncheck everything else that is changeable.
  6. Set Distribution State to Local.
  7. Save, then wait. See the trap below.
  8. In Claude, add the Salesforce MCP server using the server URL from Salesforce's documentation for your setup. Standard hosted servers ship with tools already and are the fastest route; a custom server only pays off when you need to expose specific Flows, Apex or Data Cloud queries.
Salesforce MCP connection summary
SettingValue
WhereSetup → External Client App Manager → New External Client App
API NameNo hyphens. The label can keep them
Callback URLhttps://claude.ai/api/mcp/auth_callback
OAuth scopesmcp_api and refresh_token
SecurityJWT-based access tokens for named users, PKCE enabled
Distribution StateLocal
PropagationUp to 30 minutes

Salesforce's setup guide at developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/setup-overview.html is the source for the server URL and the current client list. Salesforce lists Claude as a supported client.

Reading instead? The whole document is below, or as one Markdown file at /rebuild-path.md, plain text at /rebuild-path.txt, indexed at /llms.txt.

Get everything

The downloads

Everything on this page is downloadable. The asset pack is the whole build: 37 Apex classes, 18 Lightning web components, pages, tabs, permission sets and the schema. The mock data is the thirteen scrubbed datasets on their own. The skills are five Claude skills written while building this, for driving Salesforce over its APIs: headless discovery, campaign build, web affinity, Tableau Next dashboards, and SE triage.

Claude skills

Salesforce SE skills

Five skills for driving Salesforce over its APIs, written while building this and used to build it.

5 skills · 36 KB

Download the skills

Data only

Makana mock data

The thirteen datasets on their own, if you have an org and just need something in it. Scrubbed and synthetic.

13 datasets · 467 KB

Download the mock data

The build

The asset pack

Everything behind the screenshots and videos on this page. Apex, components, page placement, data and configuration.

553 files · 1.04 MB

Full file list: /manifests/asset-pack.txt

Download the asset pack

Machine-readable paths and the MCP server are covered at the top of this page.

The result

What the build produces

Four short screen recordings from the finished org, so you can see where the week ends before it starts.

The unified profileA custom Unified Profile connected live to campaigns, segments and web affinity data, with Maps showing how close each patient is to the nearest clinic and a full engagement timeline.
The campaign pageAutomated campaign creation with mock engagement data, attribution insights, A/B path experiments, multi-content campaigns and a matching landing page.
A/B testingA standalone app inside Marketing Cloud Next that shows every live content A/B test running across the platform.
Audience overlapAdjust audience priority and see where customers overlap across segments. Identify the people tied to three, four or more segments and prioritise them directly.

Scope

What you are rebuilding

A single Salesforce org carrying a full healthcare marketing demo, and it is not one undifferentiated route. The difficulty sits in the data foundation: the mock data, the data streams and the DLO to DMO mappings, identity resolution, the data graphs, the engagement data connections, consent, and the segments built on top of all of it. Everything downstream of that foundation — the Tableau Next dashboards, the custom components and the Agentforce agents — is comparatively mechanical once the foundation is correct and resolving. The foundation is where the time actually goes. The figures below are the shipped state of that org.

640

unified profiles

5,828

consent rows

6

campaigns

192

dashboard widgets, all returning Ok

4

agents

26

message variants

Every figure on this page carries a verification date. Status in a catalogue decays faster than content.

Day 0

Before you build anything

Two constraints set here shape every decision for the rest of the week.

Build

Day 0 prerequisites
RequirementWhy
Data Cloud provisioned, with a data spaceEverything downstream of Day 1
Marketing Cloud Next enabledCampaigns, Flows, Content tabs
UnifiedMarketingStarterUserPermSet assigned to yourselfBlank Campaigns/Flows/Content tabs are a permissions problem, not a setup problem. Marketing Cloud Admin configures MC Next; it does not let you use it
Tableau Next workspaceDay 4
Agentforce enabledDay 6

What the source org actually holds

Verified against the source org on 3 September 2026. It is an Enterprise Edition trial, non-sandbox, expiring 11 November 2026. Every permission-set licence below expires with it. A trial gets provisioning and limits a customer org will not — treat the counts as evidence the feature was on, not as a shopping list.

Source org licence and permission inventory
Licence or permissionTotalUsedWhat breaks without it
Salesforce (user licence)55069Everything
Data Cloud GenieDataPlatformStarterPsl200,0002Day 1 onward. No streams, no DMOs, no identity resolution
Customer Data Platform CdpPsl2,5001Segment creation and the MarketSegment sObject
Customer Data Cloud for Marketing200,0001Segment activation into campaigns
Marketing Cloud MarketingCloudPsl36,0051Campaigns, Flows, Content — the whole of Day 3
Marketing Triggers5,0001Event-driven journeys
Marketing Intelligence Users10,0001Campaign performance reporting
Agentforce (Default) EinsteinGPTCopilotPsl3,10510Day 6. No agents in the picker
Einstein Prompt Templates3,11015Prompt Builder
Einstein Agent (user licence)8021Agent runtime
Tableau Next Creator101Day 4. Authoring dashboards
Tableau Next Consumer101Viewing them
CRM Analytics Plus1313The analytics platform underneath
Data Pipelines Base User31Batch data prep
Guest User License259The anonymous web-visit capture only

The two constraints that shape every later decision

  • Trap

    Custom objects cannot be created over any REST surface. Tooling CustomObject reports createable: true and rejects FullName. There is no createCustomObject action. /headless/metadata is not served. deployRequest needs multipart. Confirmed independently four times across this project. Metadata API via the sf CLI only.

  • Trap

    Custom fields are fine over Tooling. This is the standard workaround, and it shapes the architecture: where you would reach for a new object, put fields on an existing one. Five fields on User replaced a leaderboard object. B2B_Mood_Board__c, a stock SDO object, carries an entire 27-row message registry. A Tooling-created CustomField has no FLS, so SOQL and REST report No such column while Apex reads and writes it perfectly. A seed can therefore succeed against a field you cannot query.

Traps that apply all week

  • Trap

    +, ++, & and # in an executeAnonymous query string. + decodes to a space; & truncates the body at that character and surfaces as Missing closing quote character ' at an unrelated column. Use String.join and a List as a counter. Build the characters you need with String.fromCharArray(new List<Integer>{38}). This was the single most frequently recurring trap in the project.

  • Trap

    Throwing an exception to read a value out of executeAnonymous rolls back every DML in that transaction. It once reverted 2,983 updates and silently no-opped a 1,165-row seed. Read-only probes only. To prove a write: run it plain, confirm success: true, verify with a separate query.

  • Trap

    where, group and on are reserved words in Apex. on is the nastiest: for (String on : map.keySet()) fails with Unexpected token 'on' and then cascades a dozen unrelated errors below it — Extra ')', Method does not exist: void get() from the type Map<String,Integer> — none of which are real.

  • Trap

    Apex identifiers are case-insensitive. A parameter src silently shadowed the constant SRC and mis-grouped every seeded row.

  • Trap

    Every out-of-the-box marketing tile defaults to Last 30 Days. Anchor every generator to Date.today(), never a literal date. Hit three separate times; stale data is indistinguishable from a broken pipeline.

The part that takes the time

The data foundation

Dashboards, components and apps are straightforward once this exists. The foundation is where the difficulty lives, and it is the part that has to be right before anything downstream means anything. Everything here was verified against the source org.

The order

  1. Field inventory and design, complete, named, typed
  2. Create fields and field-level security
  3. Populate and verify in CRM by SOQL
  4. Create the data stream
  5. Map DLO to DMO, and verify the mapping by reading the DLO field list
  6. FULL refresh
  7. Dry-run the match rule, and state the predicted unified count
  8. Run identity resolution, reconcile against the prediction, explain any gap
  9. Segments, Calculated Insights, data graph
  10. Dashboards last

Steps 1 to 3 before step 4 is the rule that saves the most rework.

The data stream create contract

POST /services/data/v64.0/ssot/data-streams

{
  "name": "Patient_Appointments_CRM",
  "label": "Patient Appointments - CRM",
  "datastreamType": "SFDC",
  "connectorInfo": {
    "connectorType": "SalesforceDotCom",
    "connectorDetails": { "name": "SalesforceDotCom_Home", "sourceObject": "Patient_Appointment__c" }
  },
  "refreshConfig": { "refreshMode": "UPSERT", "frequency": { "frequencyType": "BATCH" } },
  "sourceFields": [ { "name": "Id", "dataType": "Text" } ],
  "dataLakeObjectInfo": {
    "name": "Patient_Appointments_CRM__dll",
    "label": "Patient Appointments - CRM",
    "category": "Engagement",
    "recordModifiedFieldName": "SystemModstamp",
    "eventDateTimeFieldName": "Appointment_DateTime_c",
    "dataspaceInfo": [ { "name": "default" } ]
  }
}
Data stream create traps
TrapDetail
No array wrapperPOST the object directly
dataLakeObjectInfo takes no field listDerived from sourceFields
dataspaceInfo, lowercase s, inside dataLakeObjectInfoEntries take name only
sourceFields uses dataType on createThe read returns datatype
Source field types must match CRM exactlyEmail declared as Text returns Expected EMAIL, was given Text
No isPrimaryKey, shouldFetchImmediately or type in connectorDetailsRejected on create, present on read
Engagement category needs eventDateTimeFieldNameGive it the mangled DLO name, not the CRM name
DELETE needs ?shouldDeleteDataLakeObject=trueOtherwise MALFORMED_QUERY

The run trigger is POST /ssot/data-streams/{name}/actions/run with {"refreshType":"FULL"}, and POST /ssot/calculated-insights/{apiName}/actions/run with an empty body. Both return {"errors":[],"success":true}. /actions/refresh, /refresh and /data-refreshes all 404 and are not endpoints.

DMO mapping

  • Trap

    Identity resolution operates on one DMO. "Add my object to identity resolution" always means mapping its DLO into ssot__Individual__dlm plus ssot__ContactPointEmail__dlm, not creating a parallel custom Profile DMO.

  • Trap

    auto-map-dlos omits ParentId to ssot__PartyId__c on contact points. 887 email and 836 phone rows landed with a null party, orphaned, and the match rule needs that link. Always assert COUNT(ssot__PartyId__c) = COUNT(*) after auto-map, before running identity resolution. Fix with the Aura deploy action and re-run a FULL refresh.

  • Trap

    auto-map-dlos 500s while the DLO is still PROCESSING. Wait about 60 seconds and retry. The 500 is a timing artefact, not a failure. It also only works for opinionated objects, Individual, ContactPointEmail, ContactPointPhone, Contact, Lead, Account, Order, and returns mappedDloNames: [] for anything else.

  • Trap

    There is no served DLO to DMO mapping API. The only route is the Aura DataModelingController/ACTION$deploy action, which needs a live session.

  • Trap

    Field names mangle across three hops. CRM Party_Title__c becomes DLO Party_Title_c becomes SQL and deploy source Party_Title_c__c. Run SELECT * … LIMIT 1 once and read the metadata block. Never guess.

  • Trap

    Always FULL refresh after a bulk source update or a new mapping. Incremental appends modified rows as new versions and silently duplicates. The tell is COUNT(*) > COUNT(DISTINCT Id__c).

Identity resolution

  • Trap

    Read the rule, do not trust its label. The reference ruleset is called "Fuzzy Name and Normalized Email" and contains no fuzzy matching. It is an AND of three exact criteria: first name exact, last name exact, email exactnormalized. Email alone will not resolve. A synthetic identity needs an Individual row with first and last name AND a linked ContactPointEmail row.

PATCH /ssot/identity-resolutions/{id} writes filters over REST:

Identity resolution PATCH contract
ConstraintDetail
Requiredlabel, matchRules, reconciliationRules. Omitting any returns a named INVALID_INPUT
RejectedobjectApiName, dataSpaceName, output-only, JSON_PARSER_ERROR
Not allowedTwo definitions on the same field with the same operator inside one group, which returns "The filter contains a duplicate entry"
Use insteadNOT_IN with a comma-joined value, for example "Contact,Individual"
ReconciliationSend entityName, fields, ruleType and sources only. Drop the linkDmoName and unifiedDmoName the GET returns
After PATCHrulesetStatus goes PUBLISHING to PUBLISHED in about two minutes. Wait for PUBLISHED before running

The data graph

The data graph is the grounding object. One retrieval answers who this member is, what their plan and risk look like, what their clinical picture is, and whether you may contact them. Nothing in the agent layer works properly without it.

Unified Individual HLS1 (Primary)     5 fields
└── Unified Link Individual HLS1      5
    └── Individual                    3   (+ Title, so role is visible on the grounding object)
        ├── Payer Profile            16
        ├── Patient Profile          14
        └── Communication Consent     6   (Id, PartyId, ChannelTypeId, ConsentStatus,
                                           ContactPointValueText, ConsentCapturedSourceName)
  • Trap

    Verify counts on the ID DMO, not the fragments. *_FRAGMENT__dlm DMOs are empty, zero rows, on every graph checked. The *_ID__dlm object carries one row per node and record and answers everything:

    SELECT object_name__c AS node,
           COUNT(*) AS rows_,
           COUNT(DISTINCT root__c) AS members
    FROM   <Graph>_<epoch>_ID__dlm
    GROUP BY 1
    ORDER BY 2 DESC

  • Trap

    The ID DMO's name carries a creation epoch you cannot derive. Find it with GET /ssot/metadata?entityType=DataModelObject&entityCategory=Related and match on the display name.

  • Trap

    Orgs have a data graph cap. A failed build still occupies a slot, so delete it before retrying rather than creating a second.

  • Trap

    POST creates on a 500 and DELETE deletes on a 500. Read the state back rather than trusting the status code.

  • Trap

    A standard DMO works as a graph node, joined on its own foreign key to the parent. dataType: "DATE_TIME" is valid input casing, and the output renders as DateTime.

Resolve, do not hardcode

Making it portable

This build references 49 distinct record ids across 22 key prefixes, plus about 21 platform-generated API names. All of them are org-specific. A rebuild in another org gets none of them. The rule: hardcode only names you create yourself, resolve everything else, and make every resolve a named call rather than a guess.

Org-specific anchors and how to resolve them
AnchorResolverRead
Identity ruleset idGET /ssot/identity-resolutionsmatch label
Ruleset short idsame callrulesetId
Unified DMO namesame callreconciliationRules[].unifiedDmoName where entityName matches
Link DMO namesame callreconciliationRules[].linkDmoName
Ruleset object API namesame callobjectApiName
Data stream record idGET /ssot/data-streams/{name}recordId
dseIdsame calldataLakeObjectInfo.id, truncated to 15 characters
DLO API namesame calldataLakeObjectInfo.name
DMO relationship idGET /ssot/data-model-objects/{dmo}/relationshipsmatch sourceField.name plus targetObject.name, check status: ACTIVE
Data graphSELECT Id, Name, DataGraphApiName, Status, LastRunStatus, RecordCount FROM DataGraphmatch DataGraphApiName
Data graph ID DMOGET /ssot/metadata?entityType=DataModelObject&entityCategory=Relatedmatch displayName equal to <Label> Id
SegmentGET /ssot/segmentsmatch displayName
Segment root DMO idsame callsegmentOnId
Data spaceSELECT Id, Name FROM DataSpacematch Name

Day 1

The identity spine

Nothing else works until this does. Every segment, dashboard and agent resolves through it.

Build

  1. Patient spine → Patient_Spine_CRM data stream → Individual + ContactPointEmail. There is no 520-row source object: 520 is the overlap between the payer and patient enrichment sets on MemberID__c. The remaining 120 rows on each side are sample-data leftovers. Plan for the overlap, not the total.
  2. Role attributes, two CRM data streams: Individual_Enrichment_Payer__c → Payer_Profile__dlm (640 rows, 42 fields 1:1) and Patients__c → Patient_Profile__dlm (640).
  3. Appointment enrichment → Patient_Appointment__c → Individual_Enrichment_Data_Patient__dlm. 2,989 rows, verified 3 September 2026. Earlier versions of this material said 3,725; queryAll confirms 2,989 and the discrepancy is unexplained. Individual_Enrichment_Data_Patient__c does not exist in the org — the CRM-side object is Patient_Appointment__c.
  4. Contact points: Individual / ContactPointEmail / ContactPointPhone streams. 887 email, 836 phone.
  5. Identity ruleset → UnifiedssotIndividualHls1__dlm. Verified live: 784 unified profiles (759 known, 25 anonymous) from 3,482 source records, 77% consolidation.

Traps at this step

  • Trap

    Corrected: DLO schema is not frozen at stream creation. This was published as a trap and it is wrong. PATCH /ssot/data-streams/{name} with an extended sourceFields list adds a column to a live DLO, PROCESSING for about 60 seconds, then ACTIVE. The dead end that produced the myth was DELETE …?shouldDeleteDataLakeObject=true returning 412 while identity resolution holds the DLO. Designing the full field set up front is still cheaper, but it is no longer mandatory.

  • Trap

    auto-map-dlos omits ParentId → ssot__PartyId__c on contact points. 887 email and 836 phone rows land with a null party, and the match rule needs that link. The mapping call 500s while the DLO is still PROCESSING — retry after 60 seconds. Einstein auto-map also omits the primary key and saves happily. Fix: assert COUNT(ssot__PartyId__c) = COUNT(*) after auto-map, then fix with the Aura deploy action and a FULL refresh.

  • Trap

    DMOs union rows, they do not join columns. Mapping a second DLO into an existing DMO doubles its row count and breaks every segment built on it. Fix: map into the same standard DMO and let identity resolution collapse them, or build a related DMO.

  • Trap

    Field name double-mangling. X__c in CRM becomes X_c in the DLO becomes X_c__c in SQL.

  • Trap

    CRM nulls arrive as empty strings. IS NOT NULL is therefore always true — a care-gap measure returned 2,989 instead of 482. Always test <> ''.

  • Trap

    Incremental refresh appends modified rows as new versions. 9,000 duplicates from one refresh. A mapping change needs a Full refresh; new mappings never backfill. Corrected: a data-stream refresh endpoint does exist, POST /ssot/data-streams/{name}/actions/run with {"refreshType":"FULL"}.

  • Trap

    Identity resolution's Source Profile Filter is inverted relative to its own UI text and silently drops NULL-valued profiles. A filter keying on a field one source did not populate admitted 146 physicians, and a reported 62% consolidation rate represented zero actual merging. Corrected: these filters are not UI-only, PATCH /ssot/identity-resolutions/{id} writes them. Fix: OR'd filter groups keyed on Data Source Object, which every source populates.

  • Trap

    Reconcile at unified grain, never row grain. 640 payer rows resolve to 619 unified individuals; row-grain counts overstate by up to 3.

How you know it worked

20-unified-profile.png
One person, resolved from five source systems. The counter in the header is the whole argument for Day 1.
One person, resolved from five source systems. The counter in the header is the whole argument for Day 1.Contact record · HLS_Unified_Person_Page

Day 2

Consent, then segments

Consent first. It gates every campaign number you will later quote, and retrofitting it invalidates every count you have already shown someone.

Build

  • Individuals, contact points, per-subscription consent: 891 Individuals, 1,723 contact point type consents, 5,828 consent rows (verified). Generator: SEEConsentSeed.
  • Mobile numbers: 836 of 889 Contacts, area code derived from MailingState, line number hashed. Generator: SEEMobileSeed.
  • Four CommSubscriptions × Email and SMS channel types = 8 combinations.
  • Segments: six cld_ campaign audiences over the MarketSegment sObject.

Segment creation, the working route

PATCH /services/data/vXX/sobjects/MarketSegment/{1sg...} with IncludeCriteria as a string. Returns 204, the post-commit hook fires on plain DML, SegmentStatus goes to COUNTING within seconds and LastSegmentMemberCount lands in 30–60 seconds. This supersedes every earlier note saying segment criteria need a browser.

PATCH /ssot/segments/{apiName} is dead — it fails on referredColumns, a server-derived value the Connect path cannot compute and which is never a valid input. POST /ssot/segments does accept includeCriteria on create.

Traps at this step

  • Trap

    One headless segment = one predicate. Compound criteria save with SUCCESS and are silently ignored.

  • Trap

    NO_REFRESH is the default and it is permanent. Frozen membership behind a green status.

  • Trap

    A segment can report lastSegmentMemberCount while segmentMembershipTable is null and have never materialised. Reading the count alone injects phantom people. This project documented that trap and then committed it: cld_2027 Win-Back Eligible was catalogued as a real audience on the strength of a 784 count that was the entire population. A full sweep on 3 September found it is four segments, not one — cld_2027 Win-Back Eligible (784), Members - No Upcoming Appointments (479 of 779), and two zz_ probes. All four report a count with SegmentMembershipTable, PublishStatus and LastPublishedEndDateTime all null. Check all three fields, never the count.

  • Trap

    A segment can have working criteria that no API will show you. HLS - No Upcoming Appointments has a materialised membership table and 366 real members, so it demonstrably has criteria — yet IncludeCriteria is null on the sObject and the segment is absent from /ssot/segments. Five segments in this org are in that state. A REST-only audit will report them as criteria-free, and they are not.

  • Trap

    Segments write into a shared membership table — four of them in this org, not one. Delta_Type__c carries new and existing for the same person, so any count not using COUNT(DISTINCT Id__c) is silently doubled.

  • Trap

    MarketSegment has no DeveloperName or ApiName column. The API name lives on MarketSegmentDefinition, which neither the data API, the Tooling API nor Apex SOQL will query. Use ConnectApi.CdpSegment.getSegmentsPaginated(batchSize, offset, orderBy) — batch size first, and an offset past the end returns an empty list rather than an error.

  • Trap

    Segments cannot be deleted headlessly, and not at all once an Activation references them. Never create probe segments.

  • Trap

    excludeCriteria is not exposed by the REST read. A REST-only audit shows a filtered segment as criteria-free.

  • Trap

    Consent specifics. CommSubscriptionConsent.ContactPointValue caps at 40 characters, so 216 of this org's email addresses cannot be keyed on it — join on PartyId instead. Consent value casing here is OptIn, not OPT_IN. Every create of a Custom Preference Page also sets it as that channel's default, displacing the existing one.

12-campaign-audience.png
185 of 230 members will actually receive this send. Two opted out; forty-three were already over the eight-in-thirty-days cap.
185 of 230 members will actually receive this send. Two opted out; forty-three were already over the eight-in-thirty-days cap.Campaign record · Audience tab
05-apply-blocked.png
The Apply button refuses to write an order Data Cloud would reject. The blocked state is the honest screenshot.
The Apply button refuses to write an order Data Cloud would reject. The blocked state is the honest screenshot./lightning/n/cld_Audience_Overlap · tab 5

Waterfall segments — the contract

A waterfall is an ordered list of up to 20 segments sharing one Segment On entity, evaluated top down, first match wins, every person in exactly one bucket.

An earlier version of this material said MarketSegment exposes no SegmentType field, so a waterfall cannot be created headlessly — it is UI-only. That was wrong on both counts. The field is MarketSegmentType (values UI, DBT, Lookalike, EinsteinGptSegmentsUI, Waterfall, Realtime, Dynamic). It is createable: false on the sObject, so the sObject cannot create one — but the ordered child list is not a child object at all. It is the waterfall's own IncludeCriteria, and IncludeCriteria is plainly updateable:

{"type":"Waterfall","segments":[
  {"type":"NestedSegment","nestingType":"definition","filterId":null,
   "segmentId":"<child apiName>",
   "subject":{"segmentDevName":"<child apiName>",
              "fieldApiName":"<child displayName>",
              "nestedPublishBehavior":"useSegmentCriteria"}}
]}

Array position is the priority. There is no rank or sequence field. Reordering a waterfall is one write to one field, proven live. MarketSegmentDefMapping looks like the obvious home for the child list and is a red herring.

Eligibility is the real constraint: children must share the Segment On entity, not already be in another segment, and carry no publish schedule. PublishScheduleInterval is updateable, so clearing it is also one write — but it is destructive if you do not record the old schedule first.

Coverage does not change with priority order. The union is the union; only the distribution changes. The real decision is protecting small specialised audiences from large generic ones, which is why specific first is the working default.

Day 3

Engagement, campaigns, content

This is what makes every dashboard non-empty. Skip it and Day 4 shows you zeros you cannot diagnose.

Build

Day 3 datasets and generators
DatasetVolume (verified)Generator
Six-campaign email and SMS4,312 rowscld_SixEngagementSeed
Six-campaign web240 rows — 192 pageview, 48 conversionweb() builder, UTM in the page URL
Win-back engagement666 rows reaching 235 of 268 memberscld_WinbackEngagementSeed
Web category affinity5,600 rows / 344 individuals / 8 categoriescld_WebAffinitySeed
Campaign members921 across 6 campaignscld_SixAudienceSeed, idempotent
Encounters1,838 — 1,330 ED, 399 IP, 109 UC, 38 readmitsSEEEncounterSeed, FNV-1a deterministic
Message registry26 usable variants on B2B_Mood_Board__c, plus one blank stock recordupsert on cld_Message_Id__c
CMS content25 pieces, 6 campaigns, all Publishedbuild.py from specs/*.json

CMS content — the write and read contracts

PATCH /connect/cms/contents/{id} returns 405. The write path is PUT .../variants/{variantId} on the 9Ps id and it replaces the whole variant — a partial body returns a bare 500. The API wants contentBody, not the catalogued contentData. Every block id must be a real UUID. Send raw HTML; the API escapes on write.

The escaping pipeline, both directions. On write: a URL sanitizer rewrites = to &#61; and & to &amp; inside quoted src and href in rawHtml, then one HTML escape runs over the whole string. The inverse is one unescape pass, then a targeted URL fix — never unescape until stable, which is destructive and silent. <p>Base hero &amp; more</p> is stored double-escaped, so one pass restores it and a second turns the intended entity into a bare ampersand, with a 200 and no warning.

Reading content back out into flat fields an LWC can bind to: headline is the first lightning/heading, body the first lightning/paragraph, CTA the first lightning/button (text plus uri), bullets the <li> items of the first lightning/html containing <ul. Identify the hero image by width="600", never by position — every email has a logo image first, sometimes lightning/html at 200px, sometimes a native lightning/image at 210. And harvest only from contentBody.sfdc_cms:block: sfdc_cms:variants[] carries alternate heroes on the same block id, so a whole-document scan picks the personalization image over the base one in most cases.

attributes.uri on a button is a plain JSON string, not escaped HTML, and still arrives with a literal &amp; between UTM parameters. Written through unchanged, it stores a broken link.

Traps at this step

  • Trap

    Modulo rate allocation only hits its target at multiples of 100. At n=66, a 38% target produced 58%. Use Bresenham.

  • Trap

    String.hashCode() changes by exactly 1 when the last character does. id + '#' + salt yields correlated draws and a bimodal distribution. Salt first, then mix, in Long space.

  • Trap

    Unordered SOQL breaks first-wins de-duplication. Generator and verifier picked different winners and produced 13 phantom mismatches. ORDER BY Id in both.

  • Trap

    MC Next dashboard tiles need exact vocabulary: SENT / NOT_SENT, HARD_BOUNCE / SOFT_BOUNCE. Not uppercase everything — Bounced must become NOT_SENT. A missing SEND zeroes six tiles at once, and the diagnostic signature is unmistakable: CTR works while everything else reads zero.

  • Trap

    The column names are not what you would guess. The action column is ssot__EngagementChannelActionId__c, not ...ActionTypeId__c. ssot__UtmCampaignName__c holds the subject line; the campaign id is in ssot__UtmId__c. The org field is literally misspelled emailConversionGaolAchieved__c.

  • Trap

    Two contaminating sources must be excluded inside every measure expression, never as a dashboard filter. Marketing_Performance_Mock_Data (19,529 rows, correct attribution, broken identity) and legacy web ingestion (20,033 rows, stale since 2026-02-18, zero UTM). Filter on ssot__DataSourceId__c = 'Salesforce_Home'.

How you know it worked

13-campaign-content.png
Both email arms and the SMS, rendering from CMS. Getting the hero images to appear took the rendition endpoint, not the download endpoint.
Both email arms and the SMS, rendering from CMS. Getting the hero images to appear took the rendition endpoint, not the download endpoint.Campaign record · Content tab
11-campaign-outcomes.png
Five attribution models over the same campaign, so the number has a stated basis. The footnotes say what the model cannot see.
Five attribution models over the same campaign, so the number has a stated basis. The footnotes say what the model cannot see.Campaign record · Campaign Outcomes tab

Day 4

Dashboards

Every widget can return Ok and the story on the page can still be wrong. Those are two separate checks.

Build

Two semantic models, then vizzes, then dashboards. HLS_Member_360_SDM (73 fields, 16 metrics, 4 HEDIS calculated measurements) and Marketing_Performance_Semantic_Mod_f001 (278 fields, 52 metrics, 99 calculated measurements). Then six dashboards: Population Health (43 widgets, 2 Sankeys, 2 condition-by-tier heat maps), Membership Overview (40), MI Home (30), MI Segment Overview (28), MI A/B Testing (22), Campaign Deliverability (29, app-installed).

Traps at this step

  • Trap

    The v65 / v66 / v67 split is a per-asset property, not a required API version. Each dashboard and visualization carries its own Version column — in this org, five dashboards at 67 and one at 65; visualizations split 5 / 30 / 3 across 65, 66 and 67. Every one of them reads cleanly over the v66.0 endpoint regardless of its own value. A re-test on 3 September 2026 could not reproduce a DOWNGRADE_VERSION_ERROR on any read at either version.

    What does happen, and reads exactly like a permissions fault: GET /analytics/dashboards/{0Tr…} returns 400 INSUFFICIENT_ACCESS identically at v66.0 and v67.0. That is the CRM Analytics route refusing a Tableau Next asset — wrong endpoint family, not wrong version and not wrong permissions. /wave/dashboards/{id} returns 400, /connect/analytics/dashboards/{id} and /analytics/visualizations/{id} return 404, at both versions. Read these objects over SOQL instead.

    Scope of this correction: the retest covered reads only. The original claim may still hold on write paths, which were not re-exercised.

  • Trap

    Most of a Tableau Next dashboard cannot be exported. Of 195 widgets across six dashboards, 78 have a retrievable definition and 117 do not: all 81 text widgets return only an id and a parent id, so every heading and caption has to be retyped; all 33 filter widgets carry no field reference; and AnalyticsDashboardViewDef returns zero rows, so no per-widget placement survives — only the grid (72 columns, 12px rows, 1150px max width). Semantic models have no read endpoint at all — AnalyticsSemanticModel and SemanticModel are INVALID_TYPE on both APIs, and /ssot/semantic-models 404s. Only the semantic object names each visualization binds to survive. This is an export limit, not a build limit: the self-service authoring API writes visualizations, widget placement and global filters, so the dashboards are a spec-and-replay problem.

  • Trap

    PATCH is full replace on both vizzes and dashboards. A partial PATCH once wiped a dashboard to a single widget. GET first, send the whole document. Widget source must be stripped to {id, name}.

  • Trap

    A reference line needs both visualSpecification.referenceLines[key] and style.referenceLines[key]. PATCH returns 200 with only the first and the chart renders Can't show visualization.

  • Trap

    A field carrying a filter cannot also carry a sort. Use style.allHeaders.fields.<key>.hiddenValues so the sort survives. Mandatory for funnels.

  • Trap

    Aggregation vocabulary differs by API on the same platform: Avg in visualizations, Average in metrics.

  • Trap

    A dashboard filter silently ignores any tile whose metric additionalDimensions lacks the field. Empty widgetIds under filterMode: include means the widget answers to nothing. And a filter widget binds to exactly one semantic model — plan mixed-model dashboards rather than discovering them.

  • Trap

    The semantic layer renames colliding fields with a numeric suffix — Age becomes Age1. Read the real names off the create response.

  • Trap

    Per-category colour mapping, gradients and the entire radial family are not available over REST. Build in the UI, then place by source: {id, name}.

  • Trap

    analytics_embedding:dashboard with dashboardId = INVALID_DASHBOARD makes a FlexiPage permanently unsaveable over the API. Build a new page; never try to repair in place. Three pages in this org carry it.

How you know it worked

14-population-health.png
Forty-three widgets, all returning Ok. Cost against risk tier, with the book average as a reference line.
Forty-three widgets, all returning Ok. Cost against risk tier, with the book average as a reference line./lightning/n/Population_Health

Day 5

Custom components

Build the capability layer before anything that binds to data. It was missing from the original catalogue entirely, and that is the most consequential omission in it.

Build

cld_OrgCapability and cld_EngagementSchema are the reason every controller in this pack deploys and runs in an org that has none of the objects it expects. They resolve object and field names at runtime, return empty rather than throwing when something is absent, and let a component degrade instead of failing.

Then the components, in rough order of dependency: campaign record page tabs (Audience, Members, Content, Outcomes, A/B), the 360 pages, then the standalone app pages.

The LWC deployment sequence

Three project documents disagreed about this. Resolved:

  1. POST LightningComponentBundle — accepts scalars only. Metadata.targets does not stick and no .js-meta.xml is auto-created.
  2. POST the .js resource. Before the .html, or you get No base file for markup://c:<name>.
  3. POST the .html.
  4. POST the .js-meta.xml explicitly, Format: "xml". It is a normal writable resource and the only way to set targets.
  5. POST the .css.
  6. Reference the component from a FlexiPage. This is the compile check. A resource POST succeeds even when the template will not compile; the FlexiPage write is what forces evaluation. Treat its 204 as the green light, not the 201 on the bundle.

LightningComponentResource.Source is plain text, not base64 — the bundle create's lwcResources is base64, and two documents recorded this backwards. Payloads truncate above roughly 8 KB. LightningComponentBundleId is insert-only.

Updating Apex that an LWC already binds to

ApexClass.Body cannot be PATCHed, and delete-and-repost fails with DEPENDENCY_EXISTS once a component binds. Use: POST MetadataContainer (name caps at 32 characters) → POST ApexClassMember {MetadataContainerId, ContentEntityId, Body} → POST ContainerAsyncRequest {IsCheckOnly:false} → poll State. A container is single-use after success, and a failed container rolls back everything including members that reported success. On failure ErrorMsg is null — the real messages are in DeployDetails.componentFailures, fetched by record id.

Traps at this step

  • Trap

    :root is rejected in LWC scoped CSS (LWC1535). Put design tokens on :host or the component's own root class; dark mode via a plain @media (prefers-color-scheme: dark) block. The :root[data-theme="dark"] pattern that works in a hosted page does not compile here.

  • Trap

    fetch('/services/data/...') from an LWC returns 401. A Lightning session cookie is not an API session, and no header or credentials option changes that. Before designing around a browser fetch, look for a ConnectApi Apex equivalent — many Connect resources have one, and it needs no callout, no named credential and no connected app.

  • Trap

    A wire parameter bound to an undefined $recordId never fires and renders an empty state with no error. Bind to a field set in connectedCallback.

  • Trap

    A getter that reads selection state must not be read by the model that selection depends on. Stamping a rowClass onto each row by comparing against selectedKey made the model depend on the selection while the selection resolved back through the model — an infinite getter cycle. Selection-dependent decoration belongs in per-view getters.

  • Trap

    A LongTextArea cannot be filtered in SOQL at all, not merely aggregated. WHERE cld_Preview_Body__c != null returns INVALID_FIELD ... can not be filtered in a query call. Select it and test in memory.

  • Trap

    FlexiPage.Metadata.description caps at 255 and fails with no field named in the error, so it reads as a body-shape problem rather than a length one. itemInstances require a unique identifier (undocumented). CustomTab.Metadata.available breaks the JSON parser — omit it.

  • Trap

    Canvas 2D and WebGL do work in LWC under Lightning Web Security. No iframe needed.

Tabs, and why eight successful steps still show nothing

PermissionSetTabSetting.Visibility is DefaultOn, not Visible, and .Name takes the bare developer name — the standard- prefix is for standard tabs only. SetupEntityAccess.SetupEntityType is not writable on insert; send only ParentId and SetupEntityId. A tab listed in CustomApplication.Metadata.tabs is invisible without a PermissionSetTabSetting. CustomApplication PATCH needs the full envelope — label, navType, uiType, tabs, formFactors, brand, utilityBar — or it fails with a misleading Lightning apps only.

And then: all eight steps can succeed and the tab still not appear, because a user's personalized app navigation is authoritative and does not absorb newly added tabs. Diagnose by comparing the rendered nav against Metadata.tabs, and check /lightning/n/<tab> directly first. Querying PermissionSetTabSetting without a ParentId filter returns zero rows with HTTP 200, which reads exactly like a failed write and is not.

How you know it worked

08-ab-confidence.png
While the two intervals overlap, the versions are statistically the same thing. This test needs 735 opens per arm and has 22.
While the two intervals overlap, the versions are statistically the same thing. This test needs 735 opens per arm and has 22./lightning/n/cld_AB_Test_Console · tab 4
19-marketing-nav.png
Custom tabs, deployed headlessly. Eight API calls can all succeed and the tab still not appear.
Custom tabs, deployed headlessly. Eight API calls can all succeed and the tab still not appear.Marketing app · navigation

Day 6

Agents

One irreversible field decides whether anyone can ever see the agent.

Build

Four agents, not five: Makana_Data_Agent (InternalCopilot, v3 Active, picker-visible), Makana_Segmentation_Assistant (InternalCopilot, v1 Active, picker-visible), HLS_Member_360_Agent (ExternalCopilot, v2 Active, not picker-visible), and Makana_Analytics_Agent (ExternalCopilot, v1 Inactive — a complete, never-activated duplicate). Four Apex actions: HLSAnalyticsQueryAction, HLSMemberProfileAction, HLSCareGapCohortAction, HLSSegmentCatalogAction.

Traps at this step

  • Trap

    Without agent_type: "AgentforceEmployeeAgent" the compiler defaults to a service agent that never appears in the in-org picker. config.agent_type is immutable after first publish, and publish is not reversible over the API — a wrong publish leaves an undeletable orphan. This org has one.

  • Trap

    Picker visibility additionally requires a SetupEntityAccess row of type BotDefinition. Active is necessary and not sufficient, and System Administrator is not exempt. GenAiPlanner is not a valid SetupEntityType. Confirmed by extraction: SetupEntityAccess returns exactly two rows across all four agents and all seven planners. The two picker-visible agents have one each. The two that are not visible fail both tests at once — wrong immutable agent_type and no SetupEntityAccess row — so fixing either one alone would not have surfaced them.

  • Trap

    Publish returns an errors array even on success. Read severity, not emptiness.

  • Trap

    Numeric Apex outputs need type: object plus complex_data_type_name: lightning__numberType. Compile passes; publish fails.

  • Trap

    Skip /nextgen-authoring/.../validate. It reads the request body, not the saved asset. publish is the real validation.

  • Trap

    A Decision element in a Flow cannot see profile attributes unless a Data Graph exposes them.

How you know it worked

Section 5

Customer evidence

Every quote below is verbatim from a meeting transcript, anonymised to a segment descriptor. 205 meetings across five months, all first-party. Where a theme has no evidence, it says so.

The themes are ordered by evidence strength, not by build effort. Two of them disagree with where the work actually went. That disagreement is the point of doing the pass.

Themes ranked by evidence strength
RankThemeEvidenceWhat it leads with
1Identity resolution and duplicates6 quotes, 2 accountsUnified profile, identity ruleset
2Consent and true reachability5 quotes, 4 accountsConsent model, reachability waterfall
3Segmentation self-service6 quotes, 5 accountsSegment API over REST, segmentation agent
4Campaign build speed6 quotes, 3 accountsSix-campaign pack, the rebuild path itself
5Trust in the numbers4 quotes, 3 accountsEngagement vocabulary, contamination filtering
6Compliance and legal exposure5 quotes, 3 accountsRegulatory Watch
7Consumption cost predictability4 quotes, 4 accountsConsumption rate card
8Anonymous-to-known web behaviour2 quotesWeb affinity wheel
9Adoption3 quotesTrailblazer Tank, Plan Year
10Care gaps and Star Ratings3 quotes, quantifiedHEDIS measures, Population Health
11Proving marketing workedaspiration onlyCampaign Outcomes, attribution models
12Dashboardsreframed — see belowDataviz standard
13PortabilitythinThis guide
14Audience overlapno demand signal — see belowAudience Priority
—Network adequacyabsent — cut from the page—

1 · Identity resolution and duplicates

when we have a patient subscriber who does not have an email address … data cloud is somehow pulling in teammate email addresses and merging it into those subscriber records. And what we’ve seen is, at least for one poor teammate, she’s tagged on about 15 different subscriber records. And so anytime we try to send a message to one of those patients, she’s getting the email.

— Director of technical delivery, a national dialysis provider

Somebody keyed in the wrong phone number into our patient registration system … Turns out it’s not the patient’s phone number. It belongs to rando dude. You know, three houses away.

— Architecture lead, a national dialysis provider

in these five systems you’ve got Bob Smith here and Bob Smith here — are they the same Bob Smith?

— VP of IT, a nonprofit senior living organisation

2 · Consent and true reachability

A what in place? Sorry. … I don’t know what that is. … Oh, like, I don’t know. I didn’t set any of that up.

— Marketing lead at a national diagnostic imaging network, asked whether they have a preference centre

We have had tremendous challenge with opt-in. Just we send a campaign and then it goes to 50% of the audience because the other 50% has not been opted in.

— Marketing manager, a large Southwest health system

SMS is kind of an embattled channel right now … we just don’t have critical mass in the channel at all right now.

— Marketing lead, a regional health plan

3 · Segmentation self-service

[a] certified Salesforce admin, platform app builder, query guru … is working with MDM teams and database teams and everybody for weeks to try to figure out how do I structure this segment so that I get all of the people that I need?

— Architecture lead, a national dialysis provider

we send a campaign, look at the insights and deliverability. See that a large percentage did not receive it. We build a report for that audience who didn’t get it, download the report, upload it to consent, opt them in manually and then resend the campaign.

— Marketing manager, a large Southwest health system

we’re generating these lists twice a week. It’s just not real time, and anything short of real time is not timely in the modern world.

— Marketing lead, a regional health plan

4 · Campaign build speed

Launching from the segment, we would typically take a sprint which is two weeks … pretty much we take about three weeks to four weeks from end to end.

— Marketing developer, a national dialysis provider

we are hoping that within one or two years we will be in a better place. But for now we don’t have any ETA on when this will all be resolved. But every campaign is a struggle.

— Marketing developer, a national dialysis provider

[they] want to turn this around in three weeks when this new legislation launches. And I’m like … I can’t help you in three weeks.

— Architecture lead, a national dialysis provider

5 · Trust in the numbers

we sent the summer newsletter in the middle of July … and we realized that the deliverability rate had dropped to 72%, which was really alarming because the data does not change drastically from one newsletter to the other.

— Marketing manager, a large West Coast academic health system

when I do a count of accounts where the person email is null and the status is active … I get 113,000.

— A national dialysis provider. A colleague had answered the same question as 11,000 moments earlier

if this message does not go to some patient — how do we know which message? Because there’s so many messages going in a day.

— Technical lead, a national diagnostic imaging network

6 · Compliance and legal exposure

our legal team did not allow us to use anything beyond a patient identifier to unify patients … the only thing that was legally blessed to bring patient data together.

— Architecture lead, a national dialysis provider

If you’re the same human going to [the .com] or having a registration on [the portal], I actually do not link that together, even if I know that you’re the same human. And that’s all because of just legal guidance … it is slow. And it is self inflicted.

— Architecture lead, a national dialysis provider

Everyone’s so scared of TCPA compliance as well that it’s like, hesitant to make any big decisions there.

— Marketing lead, a regional health plan

7 · Consumption cost predictability

[other cloud vendors] are all giving us sandbox for free right now … So it’s like why would we do it … and pay a premium cost just to even prove it out that it works? We are not going to get that approved, period.

— Platform leader, a large multi-state health system

can it be pulled in and referenced by these agents without incurring that data cloud cost?

— Marketing lead, a regional health plan

we don’t want to over-engineer, and that’s probably more from a cost perspective than anything else.

— Data systems engineer, a nonprofit senior living organisation

8 · Anonymous-to-known web behaviour

someone could have been browsing the site for kidney-related resources for months, maybe even years, and then ultimately they become a patient … we want to understand that journey long term. What content were they consuming? When did they turn from prospect to patient? That has vast implications for our business.

— Digital lead, a national dialysis provider
21-web-affinity.png
What one person has been reading, built from 21 web interactions across 19 active days.
What one person has been reading, built from 21 web interactions across 19 active days.Contact record · Web Affinity tab

9 · Adoption

I’ve tried. I have tried. I’ve clawed my way and I’ve gotten almost, but then I get stuck. It’s too techy.

— Marketing manager, a large Southwest health system, on a query tool she is licensed for

we just don’t know what we don’t know.

— Marketing director, a large Southwest health system

10 · Care gaps and Star Ratings

if you were to look at [us] on the whole, you’d say that our goals were to improve our stars measures … improving med adherence, improving the CAHPS survey responses.

— Marketing lead, a regional health plan

the people involved in the med adherence journeys are becoming compliant on their med schedules at like an 88 rate. Now, we don’t have a lift number on that because out of an abundance of caution, we didn’t have a control group.

— Marketing lead, a regional health plan

12 · Dashboards — the theme was framed wrong

The original framing was dashboards are inventories nobody can act on. No customer said that. Nobody rejected a dashboard, called reports unread, or asked so what. The evidence says something more uncomfortable: they never got as far as a dashboard.

We actually have the engagement metrics going into the data cloud but we are not utilising them.

— Marketing developer, a national dialysis provider

A year and 27 million records later and zero campaigns. We turned off the integration and we purged the data. Because it wasn’t fulfilling a purpose.

— Architecture lead, a national dialysis provider

That second line is the strongest in the entire corpus, and it argues for measuring fewer things and acting on them.

14 · Audience overlap — the honest negative result

The compliance layer says the same thing from the other direction. Regulatory Watch’s top open finding in this org reads: 47 CFR 64.1200(a)(2) — the healthcare exemption permits 1 message per day and 3 per week per provider. This org has zero DataCommunicationCap records, so nothing enforces any ceiling. The marketers have no word for the problem. The regulation already does.

Cut from the page: network adequacy and access. No transcript evidence across all 205 meetings. These accounts engage on marketing and CDP, not network operations. Care Access maps and drive-time matrices stay in the build inventory; they do not get a customer-problem slide.

Section 6

Verification

Five read-only sweeps, reproducible in about four minutes, run against the live org before any demo. Everything in this document was checked against them on 3 September 2026.

Status in a catalogue decays faster than content. Every drifted number in that report was correct when written, some within the same week. Carry a verification date per section and a way to re-run the check — never a static badge.

What you inherit as broken

Honest list. These are real in the source org today and a rebuild will reproduce them unless you fix them deliberately.

Broken

Known broken state inherited from the source org
GapDetail
Identity resolution staleLast ran 2026-08-29, doesRunAutomatically: false
Decision_Authority__cioPROCESSING_FAILED since 2026-08-21 on an hourly schedule
Seven Calculated InsightsNever executed. Return 0 rows with no error
Hero imageryNone for Flu Shot or Primary Care — the two largest audiences. One asset has a ContentVersion with no ContentDistribution
Female member portraits340 uncovered of 640
VolumeTarget architecture calls for ~9,500 in Tier 2; 520–640 exist. Every dashboard is built on a hero-sized dataset
Six orphaned LWC bundlescldAbVariantCompare, cldAudienceOverlap, cldAudiencePriority, cldAudienceWarnings, cldPreviewHarvest, and cldPopulationHealth — the last was previously miscounted as live. Population_Health_Page hosts the Tableau dashboard via analytics_embedding:dashboard, not the component
Six compliance objectsDesigned, packaged, never deployed — they need the Metadata API
cld_Affinity Womens Health InterestPublishes SUCCESS, resolves to 0 members
Win-Back campaign structureParent holds 0 members; 33 of 268 children have no engagement
A/B console segment linkcld_AbTestConsoleController hardcodes one segment id, so the open segment link shows the Win-Back audience on every campaign. Wrong for six of seven campaign families
Harmonized attribute escapingThe unified profile renders Surgical &amp; Procedural as literal text — one unescape pass missing on the EHR service-line tile
Two identity rulesets consolidate nothingHLS Physicians reports a 93% consolidation rate against zero matched source profiles over 1,951 records. ACCT - 001 resolves 91 accounts to 91
Closes_Care_Gap__cAll 2,989 appointments. The care-gap flag the campaign story is built on is never set
Five segments have unreadable criteriaIncluding one with 366 materialised members
Consent could not be joined to contactsContact.IndividualId was missing from the original export; consent hangs off Individual.PartyId. Fixed in the asset pack, but any export that omits that one column produces consent rows that join to nothing

Deliberate defects, which are not gaps

79 + 11 corrupted state codes, 53 stripped-leading-zero zips, 123 of 130 Payer Age versus Contact Birthdate conflicts over three years, 9,000 duplicate engagement rows from an incremental refresh. These exist on purpose, so that harmonization has something to fix and the before state is real. Do not clean them without deciding to.

Section 7

Traps index

Every trap in this document, in one place. Each one cost at least an hour. Filter by the day you are on or the surface you are fighting.

Day

Surface

62 of 62 traps

  • Trap

    d0-custom-objectsDay 0MetadataCustom objects cannot be created over any REST surface. Tooling CustomObject reports createable: true and rejects FullName. There is no createCustomObject action. /headless/metadata is not served. deployRequest needs multipart. Confirmed independently four times across this project. Metadata API via the sf CLI only.

  • Trap

    d0-custom-fieldsDay 0Tooling APICustom fields are fine over Tooling. This is the standard workaround, and it shapes the architecture: where you would reach for a new object, put fields on an existing one. Five fields on User replaced a leaderboard object. B2B_Mood_Board__c, a stock SDO object, carries an entire 27-row message registry. A Tooling-created CustomField has no FLS, so SOQL and REST report No such column while Apex reads and writes it perfectly. A seed can therefore succeed against a field you cannot query.

  • Trap

    d0-execanon-encodingDay 0Apex+, ++, & and # in an executeAnonymous query string. + decodes to a space; & truncates the body at that character and surfaces as Missing closing quote character ' at an unrelated column. Use String.join and a List as a counter. Build the characters you need with String.fromCharArray(new List<Integer>{38}). This was the single most frequently recurring trap in the project.

  • Trap

    d0-exception-rollbackDay 0ApexThrowing an exception to read a value out of executeAnonymous rolls back every DML in that transaction. It once reverted 2,983 updates and silently no-opped a 1,165-row seed. Read-only probes only. To prove a write: run it plain, confirm success: true, verify with a separate query.

  • Trap

    d0-reserved-wordsDay 0Apexwhere, group and on are reserved words in Apex. on is the nastiest: for (String on : map.keySet()) fails with Unexpected token 'on' and then cascades a dozen unrelated errors below it — Extra ')', Method does not exist: void get() from the type Map<String,Integer> — none of which are real.

  • Trap

    d0-case-insensitiveDay 0ApexApex identifiers are case-insensitive. A parameter src silently shadowed the constant SRC and mis-grouped every seeded row.

  • Trap

    d0-last-30-daysDay 0Engagement dataEvery out-of-the-box marketing tile defaults to Last 30 Days. Anchor every generator to Date.today(), never a literal date. Hit three separate times; stale data is indistinguishable from a broken pipeline.

  • Trap

    d1-dlo-frozenDay 1Data CloudCorrected: DLO schema is not frozen at stream creation. This was published as a trap and it is wrong. PATCH /ssot/data-streams/{name} with an extended sourceFields list adds a column to a live DLO, PROCESSING for about 60 seconds, then ACTIVE. The dead end that produced the myth was DELETE …?shouldDeleteDataLakeObject=true returning 412 while identity resolution holds the DLO. Designing the full field set up front is still cheaper, but it is no longer mandatory.

  • Trap

    d1-automapDay 1Data Cloudauto-map-dlos omits ParentId → ssot__PartyId__c on contact points. 887 email and 836 phone rows land with a null party, and the match rule needs that link. The mapping call 500s while the DLO is still PROCESSING — retry after 60 seconds. Einstein auto-map also omits the primary key and saves happily. Fix: assert COUNT(ssot__PartyId__c) = COUNT(*) after auto-map, then fix with the Aura deploy action and a FULL refresh.

  • Trap

    d1-dmo-unionDay 1Data CloudDMOs union rows, they do not join columns. Mapping a second DLO into an existing DMO doubles its row count and breaks every segment built on it. Fix: map into the same standard DMO and let identity resolution collapse them, or build a related DMO.

  • Trap

    d1-double-manglingDay 1Data CloudField name double-mangling. X__c in CRM becomes X_c in the DLO becomes X_c__c in SQL.

  • Trap

    d1-null-empty-stringDay 1Data CloudCRM nulls arrive as empty strings. IS NOT NULL is therefore always true — a care-gap measure returned 2,989 instead of 482. Always test <> ''.

  • Trap

    d1-incremental-refreshDay 1Data CloudIncremental refresh appends modified rows as new versions. 9,000 duplicates from one refresh. A mapping change needs a Full refresh; new mappings never backfill. Corrected: a data-stream refresh endpoint does exist, POST /ssot/data-streams/{name}/actions/run with {"refreshType":"FULL"}.

  • Trap

    d1-source-profile-filterDay 1Data CloudIdentity resolution's Source Profile Filter is inverted relative to its own UI text and silently drops NULL-valued profiles. A filter keying on a field one source did not populate admitted 146 physicians, and a reported 62% consolidation rate represented zero actual merging. Corrected: these filters are not UI-only, PATCH /ssot/identity-resolutions/{id} writes them. Fix: OR'd filter groups keyed on Data Source Object, which every source populates.

  • Trap

    d1-unified-grainDay 1Data CloudReconcile at unified grain, never row grain. 640 payer rows resolve to 619 unified individuals; row-grain counts overstate by up to 3.

  • Trap

    d1-graph-join-keyDay 1Data CloudA data graph node's join key must also be a projected field on that node. The build returns status: ERROR with no message. Fix: GET the graph and assert path[0].fieldName is present on every non-root node before waiting on a build.

  • Trap

    d1-stream-categoryDay 1Data CloudCategory cannot be changed after stream creation. Fix: decide it before you create the stream, because a data graph root must be Unified Individual.

  • Trap

    d1-run-rulesetDay 1Data CloudThere is no REST endpoint to run an identity resolution ruleset. /actions/run and /jobs both 404. Fix: the Run Ruleset button, found via GET /ui-api/actions/record/{id} as IdentityResolutionRunNowAction, or the Aura IdentityResolutionController/ACTION$runNow.

  • Trap

    d1-identity-one-dmoDay 1Data CloudIdentity resolution operates on one DMO. "Add my object to identity resolution" always means mapping its DLO into ssot__Individual__dlm plus ssot__ContactPointEmail__dlm, not creating a parallel custom Profile DMO.

  • Trap

    d1-no-mapping-apiDay 1Data CloudThere is no served DLO to DMO mapping API. The only route is the Aura DataModelingController/ACTION$deploy action, which needs a live session.

  • Trap

    d1-ruleset-labelDay 1Data CloudRead the rule, do not trust its label. The reference ruleset is called "Fuzzy Name and Normalized Email" and contains no fuzzy matching. It is an AND of three exact criteria. Email alone will not resolve: a synthetic identity needs an Individual row with first and last name AND a linked ContactPointEmail row.

  • Trap

    d1-fragment-dmo-emptyDay 1Data CloudVerify data graph counts on the ID DMO, not the fragments. *_FRAGMENT__dlm DMOs are empty, zero rows, on every graph checked. The *_ID__dlm object carries one row per node and record and answers everything. Its name carries a creation epoch you cannot derive, so find it with GET /ssot/metadata?entityType=DataModelObject&entityCategory=Related and match on the display name.

  • Trap

    d1-graph-capDay 1Data CloudOrgs have a data graph cap, and a failed build still occupies a slot. Delete the failed graph before retrying rather than creating a second.

  • Trap

    d1-graph-500Day 1Data CloudOn data graphs, POST creates on a 500 and DELETE deletes on a 500. Read the state back rather than trusting the status code.

  • Trap

    d2-one-predicateDay 2SegmentsOne headless segment = one predicate. Compound criteria save with SUCCESS and are silently ignored.

  • Trap

    d2-no-refreshDay 2SegmentsNO_REFRESH is the default and it is permanent. Frozen membership behind a green status.

  • Trap

    d2-phantom-countDay 2SegmentsA segment can report lastSegmentMemberCount while segmentMembershipTable is null and have never materialised. Reading the count alone injects phantom people. This project documented that trap and then committed it: cld_2027 Win-Back Eligible was catalogued as a real audience on the strength of a 784 count that was the entire population. A full sweep on 3 September found it is four segments, not one — cld_2027 Win-Back Eligible (784), Members - No Upcoming Appointments (479 of 779), and two zz_ probes. All four report a count with SegmentMembershipTable, PublishStatus and LastPublishedEndDateTime all null. Check all three fields, never the count.

  • Trap

    d2-hidden-criteriaDay 2SegmentsA segment can have working criteria that no API will show you. HLS - No Upcoming Appointments has a materialised membership table and 366 real members, so it demonstrably has criteria — yet IncludeCriteria is null on the sObject and the segment is absent from /ssot/segments. Five segments in this org are in that state. A REST-only audit will report them as criteria-free, and they are not.

  • Trap

    d2-shared-membership-tableDay 2SegmentsSegments write into a shared membership table — four of them in this org, not one. Delta_Type__c carries new and existing for the same person, so any count not using COUNT(DISTINCT Id__c) is silently doubled.

  • Trap

    d2-no-developernameDay 2SegmentsMarketSegment has no DeveloperName or ApiName column. The API name lives on MarketSegmentDefinition, which neither the data API, the Tooling API nor Apex SOQL will query. Use ConnectApi.CdpSegment.getSegmentsPaginated(batchSize, offset, orderBy) — batch size first, and an offset past the end returns an empty list rather than an error.

  • Trap

    d2-no-headless-deleteDay 2SegmentsSegments cannot be deleted headlessly, and not at all once an Activation references them. Never create probe segments.

  • Trap

    d2-exclude-criteriaDay 2SegmentsexcludeCriteria is not exposed by the REST read. A REST-only audit shows a filtered segment as criteria-free.

  • Trap

    d2-consent-specificsDay 2ConsentConsent specifics. CommSubscriptionConsent.ContactPointValue caps at 40 characters, so 216 of this org's email addresses cannot be keyed on it — join on PartyId instead. Consent value casing here is OptIn, not OPT_IN. Every create of a Custom Preference Page also sets it as that channel's default, displacing the existing one.

  • Trap

    d3-modulo-rateDay 3Engagement dataModulo rate allocation only hits its target at multiples of 100. At n=66, a 38% target produced 58%. Use Bresenham.

  • Trap

    d3-hashcodeDay 3ApexString.hashCode() changes by exactly 1 when the last character does. id + '#' + salt yields correlated draws and a bimodal distribution. Salt first, then mix, in Long space.

  • Trap

    d3-unordered-soqlDay 3ApexUnordered SOQL breaks first-wins de-duplication. Generator and verifier picked different winners and produced 13 phantom mismatches. ORDER BY Id in both.

  • Trap

    d3-tile-vocabularyDay 3Engagement dataMC Next dashboard tiles need exact vocabulary: SENT / NOT_SENT, HARD_BOUNCE / SOFT_BOUNCE. Not uppercase everything — Bounced must become NOT_SENT. A missing SEND zeroes six tiles at once, and the diagnostic signature is unmistakable: CTR works while everything else reads zero.

  • Trap

    d3-column-namesDay 3Engagement dataThe column names are not what you would guess. The action column is ssot__EngagementChannelActionId__c, not ...ActionTypeId__c. ssot__UtmCampaignName__c holds the subject line; the campaign id is in ssot__UtmId__c. The org field is literally misspelled emailConversionGaolAchieved__c.

  • Trap

    d3-contaminationDay 3Engagement dataTwo contaminating sources must be excluded inside every measure expression, never as a dashboard filter. Marketing_Performance_Mock_Data (19,529 rows, correct attribution, broken identity) and legacy web ingestion (20,033 rows, stale since 2026-02-18, zero UTM). Filter on ssot__DataSourceId__c = 'Salesforce_Home'.

  • Trap

    d4-api-versionDay 4Tableau NextThe v65 / v66 / v67 split is a per-asset property, not a required API version. Each dashboard and visualization carries its own Version column — in this org, five dashboards at 67 and one at 65; visualizations split 5 / 30 / 3 across 65, 66 and 67. Every one of them reads cleanly over the v66.0 endpoint regardless of its own value. A re-test on 3 September 2026 could not reproduce a DOWNGRADE_VERSION_ERROR on any read at either version.

    What does happen, and reads exactly like a permissions fault: GET /analytics/dashboards/{0Tr…} returns 400 INSUFFICIENT_ACCESS identically at v66.0 and v67.0. That is the CRM Analytics route refusing a Tableau Next asset — wrong endpoint family, not wrong version and not wrong permissions. /wave/dashboards/{id} returns 400, /connect/analytics/dashboards/{id} and /analytics/visualizations/{id} return 404, at both versions. Read these objects over SOQL instead.

    Scope of this correction: the retest covered reads only. The original claim may still hold on write paths, which were not re-exercised.

  • Trap

    d4-no-exportDay 4Tableau NextMost of a Tableau Next dashboard cannot be exported. Of 195 widgets across six dashboards, 78 have a retrievable definition and 117 do not: all 81 text widgets return only an id and a parent id, so every heading and caption has to be retyped; all 33 filter widgets carry no field reference; and AnalyticsDashboardViewDef returns zero rows, so no per-widget placement survives — only the grid (72 columns, 12px rows, 1150px max width). Semantic models have no read endpoint at all — AnalyticsSemanticModel and SemanticModel are INVALID_TYPE on both APIs, and /ssot/semantic-models 404s. Only the semantic object names each visualization binds to survive. This is an export limit, not a build limit: the self-service authoring API writes visualizations, widget placement and global filters, so the dashboards are a spec-and-replay problem.

  • Trap

    d4-patch-replaceDay 4Tableau NextPATCH is full replace on both vizzes and dashboards. A partial PATCH once wiped a dashboard to a single widget. GET first, send the whole document. Widget source must be stripped to {id, name}.

  • Trap

    d4-reference-lineDay 4Tableau NextA reference line needs both visualSpecification.referenceLines[key] and style.referenceLines[key]. PATCH returns 200 with only the first and the chart renders Can't show visualization.

  • Trap

    d4-filter-sortDay 4Tableau NextA field carrying a filter cannot also carry a sort. Use style.allHeaders.fields.<key>.hiddenValues so the sort survives. Mandatory for funnels.

  • Trap

    d4-aggregation-vocabDay 4Tableau NextAggregation vocabulary differs by API on the same platform: Avg in visualizations, Average in metrics.

  • Trap

    d4-dashboard-filterDay 4Tableau NextA dashboard filter silently ignores any tile whose metric additionalDimensions lacks the field. Empty widgetIds under filterMode: include means the widget answers to nothing. And a filter widget binds to exactly one semantic model — plan mixed-model dashboards rather than discovering them.

  • Trap

    d4-semantic-renameDay 4Tableau NextThe semantic layer renames colliding fields with a numeric suffix — Age becomes Age1. Read the real names off the create response.

  • Trap

    d4-colour-restDay 4Tableau NextPer-category colour mapping, gradients and the entire radial family are not available over REST. Build in the UI, then place by source: {id, name}.

  • Trap

    d4-invalid-dashboardDay 4Metadataanalytics_embedding:dashboard with dashboardId = INVALID_DASHBOARD makes a FlexiPage permanently unsaveable over the API. Build a new page; never try to repair in place. Three pages in this org carry it.

  • Trap

    d5-root-cssDay 5LWC:root is rejected in LWC scoped CSS (LWC1535). Put design tokens on :host or the component's own root class; dark mode via a plain @media (prefers-color-scheme: dark) block. The :root[data-theme="dark"] pattern that works in a hosted page does not compile here.

  • Trap

    d5-fetch-401Day 5LWCfetch('/services/data/...') from an LWC returns 401. A Lightning session cookie is not an API session, and no header or credentials option changes that. Before designing around a browser fetch, look for a ConnectApi Apex equivalent — many Connect resources have one, and it needs no callout, no named credential and no connected app.

  • Trap

    d5-wire-recordidDay 5LWCA wire parameter bound to an undefined $recordId never fires and renders an empty state with no error. Bind to a field set in connectedCallback.

  • Trap

    d5-getter-cycleDay 5LWCA getter that reads selection state must not be read by the model that selection depends on. Stamping a rowClass onto each row by comparing against selectedKey made the model depend on the selection while the selection resolved back through the model — an infinite getter cycle. Selection-dependent decoration belongs in per-view getters.

  • Trap

    d5-longtextareaDay 5ApexA LongTextArea cannot be filtered in SOQL at all, not merely aggregated. WHERE cld_Preview_Body__c != null returns INVALID_FIELD ... can not be filtered in a query call. Select it and test in memory.

  • Trap

    d5-flexipage-descriptionDay 5MetadataFlexiPage.Metadata.description caps at 255 and fails with no field named in the error, so it reads as a body-shape problem rather than a length one. itemInstances require a unique identifier (undocumented). CustomTab.Metadata.available breaks the JSON parser — omit it.

  • Trap

    d5-canvas-webglDay 5LWCCanvas 2D and WebGL do work in LWC under Lightning Web Security. No iframe needed.

  • Trap

    d6-agent-typeDay 6AgentforceWithout agent_type: "AgentforceEmployeeAgent" the compiler defaults to a service agent that never appears in the in-org picker. config.agent_type is immutable after first publish, and publish is not reversible over the API — a wrong publish leaves an undeletable orphan. This org has one.

  • Trap

    d6-setupentityaccessDay 6AgentforcePicker visibility additionally requires a SetupEntityAccess row of type BotDefinition. Active is necessary and not sufficient, and System Administrator is not exempt. GenAiPlanner is not a valid SetupEntityType. Confirmed by extraction: SetupEntityAccess returns exactly two rows across all four agents and all seven planners. The two picker-visible agents have one each. The two that are not visible fail both tests at once — wrong immutable agent_type and no SetupEntityAccess row — so fixing either one alone would not have surfaced them.

  • Trap

    d6-publish-errorsDay 6AgentforcePublish returns an errors array even on success. Read severity, not emptiness.

  • Trap

    d6-numeric-outputsDay 6AgentforceNumeric Apex outputs need type: object plus complex_data_type_name: lightning__numberType. Compile passes; publish fails.

  • Trap

    d6-skip-validateDay 6AgentforceSkip /nextgen-authoring/.../validate. It reads the request body, not the saved asset. publish is the real validation.

  • Trap

    d6-flow-decisionDay 6AgentforceA Decision element in a Flow cannot see profile attributes unless a Data Graph exposes them.

Published changes

Corrections

Everything here was verified. When something turns out to be wrong, it gets corrected in public with a date rather than quietly edited.

Corrections log
DateWhat changedWhy
4 September 2026DLO schema is frozen at stream creation was published as a trapWrong. PATCH /ssot/data-streams/{name} with an extended sourceFields list adds a column to a live DLO, PROCESSING for about 60 seconds, then ACTIVE. The dead end that produced the myth was DELETE …?shouldDeleteDataLakeObject=true returning 412 while identity resolution holds the DLO. Designing the full field set up front is still cheaper, but it is no longer mandatory
4 September 2026Source profile filters are UI-onlyWrong. PATCH /ssot/identity-resolutions/{id} writes them
4 September 2026There is no data-stream refresh endpointWrong. POST /ssot/data-streams/{name}/actions/run with {"refreshType":"FULL"}
4 September 2026Tableau Next dashboards were described as unrebuildable and requiring manual redrawingWrong. The authoring API exposes full widget creation with placement and filter field references, plus a promotion-package export. Reading an existing dashboard back is still not possible; building one always was
4 September 2026Fake_Report_Data_Object__c field count corrected from 7, then 31, to 36The first number was the count granted by one permission set, not the object's shape
3 September 2026An API-version trap was qualified and scoped to read operations onlyIt could not be reproduced on a second attempt

Section 8

Downloads

The build

The asset pack

Everything behind the screenshots on this page. Apex, components, page placement, data and configuration.

553 files · 1.04 MB

Full file list: /manifests/asset-pack.txt

Download the asset pack

Data only

Makana mock data

The thirteen datasets on their own, if you have an org and just need something in it. Scrubbed and synthetic.

13 datasets · 467 KB

Download the mock data

Claude skills

Salesforce SE skills

Five skills for driving Salesforce over its APIs — headless discovery, campaign build, web affinity, Tableau Next, and SE triage.

5 skills · 36 KB

Download the skills

The thirteen datasets

All thirteen datasets in the mock data pack
FileRowsWhat it is
appointments.csv2,989Patient appointment history, the engagement timeline on the unified profile.
campaign-members.csv1,189Campaign membership: which contact is in which campaign, with status.
campaigns.csv10Campaign records, including parent and child rows for the multi-content campaigns.
cms-content.json25Salesforce CMS content pieces captured from the Marketing Cloud workspace.
consent/comm-subscription-channel-type.csv11Subscription and channel pairings, the join between subscription and engagement channel.
consent/comm-subscription-consent.csv5,828The consent grants themselves, one row per party, subscription and channel.
consent/comm-subscription.csv7The subscription definitions consent rows point at.
consent/contact-point-type-consent.csv1,723Per contact-point consent, email and phone, separate from subscription consent.
consent/engagement-channel-type.csv2The engagement channel lookup: email and SMS.
contacts.csv890Patient-facing contacts. The spine every other dataset joins to.
message-registry.csv27Marketing Cloud Next message registry rows, one per campaign and channel.
patients.csv640Clinical patient records on Patients__c, keyed to contacts by email.
payer-enrichment.csv640Payer and plan enrichment on Individual_Enrichment_Payer__c.

The five skills, in full

claudforce-hls-rebuildUse when the user wants to build, rebuild or stand up a healthcare Salesforce demo org with Data Cloud, Marketing Cloud Next and Agentforce, or asks to follow the Claudforce HLS rebuild path.
---
name: claudforce-hls-rebuild
description: Use when the user wants to build, rebuild or stand up a healthcare Salesforce demo org with Data Cloud, Marketing Cloud Next and Agentforce, or asks to follow the Claudforce HLS rebuild path.
---

# Claudforce HLS rebuild

Routing only. The material lives in the tools, not here. Do not restate the guide.

## Two servers

- **Claudforce HLS MCP** carries the knowledge: the ordered route, the verified traps, the skills,
  the dataset shapes, the verifications. It has no access to any Salesforce org and never will.
- **Salesforce MCP**, connected to the org being built in, issues every call.

If only one is connected, stop and say which is missing. Neither half builds anything alone.

## Procedure

1. Call `start_here` before anything else.
2. Read the route: `get_guide`, or `list_sections` then `get_section`.
3. Build the data foundation first, in the documented order, before dashboards, components or
   agents. Everything downstream inherits its defects.
4. Before each Data Cloud step, call `search_traps` filtered to that surface. Read the result
   before issuing the call, not after it fails.
5. After each step, call `verify_step` and run the query it returns against the target org.
   Reconcile the result against the stated expectation. Report any gap as a finding.
6. Never trust a status code. A 200 means the parser accepted the request. Several operations in
   this build create on a 500, succeed while doing nothing, or discard half the payload.
7. Resolve every org anchor at runtime: record ids, DMO names, ruleset ids, graph epochs, content
   keys. Ids in the guide belong to the org it was written from. Query for the anchor, never reuse
   one from documentation.
8. `get_dataset_schema` before loading data, `get_manifest` before trusting a download's contents,
   `get_skill` for the surface-specific procedures.

## Stop conditions

- A verification fails and you cannot explain the gap. Report it; do not proceed downstream.
- A step has no verification available. Say so explicitly rather than declaring it done.
- An anchor cannot be resolved from the target org. Ask; do not guess a value.
salesforce-se-osOne triage entry point for Solutions Engineer work, built to run off call transcripts and pasted context rather than a live CRM connection.
---
name: salesforce-se-os
description: One triage entry point for Solutions Engineer work, built to run off call transcripts and pasted context rather than a live CRM connection. Use this skill whenever the user wants to analyze a customer call, build a follow-up, plan next steps, prep for an upcoming conversation, research a product/competitor/technical topic, or scope a Salesforce solution. Trigger on phrases like "analyze this call", "what did I miss on this call", "draft a follow-up", "prep me for [account]", "what do I need to know before [meeting]", "what does this customer actually need", "how would I solution [use case]", "research [topic/competitor]", or any customer-conversation, follow-up, planning, research, or solutioning ask — even when the user doesn't name which mode they want. The skill self-routes and shows the routing decision back. Built for a marketing-focused SE who covers all clouds, so assume multi-cloud solutions are common. Always use this over generic prep, note-summarizing, or research when the request is SE-shaped.
---

# Salesforce SE OS

One entry point for Solutions Engineer work. Read the request, route it to the right mode, and always show the routing decision back so the user can see what was chosen and what was rejected.

**This skill runs off what the user gives you — call transcripts, notes, emails, deal descriptions, and pasted context — not a live CRM.** Claude is not connected to Salesforce CRM here. Treat transcripts and pasted context as the primary source of truth. If the user happens to paste CRM fields, use them; otherwise never assume CRM data exists and never invent it.

The user is a Solutions Engineer at Salesforce, marketing-focused but covering all clouds. Solutions frequently span more than one cloud (e.g. Marketing Cloud + Data Cloud + core Sales/Service), so never assume a single-cloud answer is complete without checking whether adjacent clouds are in play.

## The revenue + customer-success lens

Every output should name **both** sides, kept honest:

- **The customer need** — what the customer actually said they need, in their words, grounded in the transcript.
- **The Salesforce angle** — how solving that need maps to revenue (expansion, new cloud, retention) *and* to the customer's own success.

Keep the two aligned. The revenue angle must follow from a real need in the transcript — never manufacture urgency or an expansion story the call doesn't support. A follow-up that overreaches past what the customer said damages trust and the deal. When the transcript doesn't support a revenue angle, say so plainly and keep the focus on the need.

## How it works

- **Always available (no integrations):** Reasoning over whatever the user pastes — transcripts, call notes, emails, deal descriptions, product docs — plus general product and market knowledge.
- **If connected (web search, uploaded files, or user-provided context):** Live web and developer-doc search, enablement content, and any CRM fields the user chooses to paste.
- If a source isn't available, don't fabricate it. Say so in the footer and continue with what's provided.

## Phase 1 — Triage

Classify the request into exactly one mode:

- **Call Analysis** — "analyze this call", "what did I miss", "what were the signals", "summarize this transcript". Input is a transcript or notes.
- **Follow-up / Planning** — "draft a follow-up", "what are my next steps", "build the plan for this account", "what should I send". Turns a call or context into action.
- **Conversation Prep** — an upcoming call, meeting, or QBR, or "what do I need to know about [account]" before talking to them.
- **Research** — a product, market, competitor, or technical topic with no specific call tied to it.
- **Solutioning** — designing, scoping, or troubleshooting a solution or use case for a customer.
- **General/Unclear** — doesn't cleanly fit, or spans more than one.

Capture any account, topic, or use case named. If mode is ambiguous **and** no transcript/context/topic is given, ask one bundled question: "What's this for — analyzing a call, building a follow-up or plan, prepping for a conversation, research, or scoping a solution? And can you paste the transcript or context?"

If context is given but mode is unclear, infer the most likely mode and proceed — state the assumption in the footer rather than asking.

If the request spans two modes ("analyze this call and draft the follow-up"), run both phases and combine into one output with two sections. Call Analysis feeding Follow-up is the most common pairing — expect it.

**Log the fork as you go.** This skill's whole point is showing its work, so track not just what you chose but what you considered and rejected. For each decision, note in one short line (under ~15 words) *why* — which words in the request or which line in the transcript triggered it. This feeds the mandatory Triage Rationale table. Capture:

- The mode chosen **and** the modes considered but dropped, with the reason each was dropped.
- Sources used vs. skipped, and why each was skipped (unavailable, not relevant, out of scope).
- Items included vs. notable items excluded, and why the excluded ones didn't make the cut.

The rejected side matters as much as the chosen side — it's how the user checks whether the skill routed correctly.

## Phase 2 — Gather (mode-specific)

**Call Analysis:**
- Work from the transcript or notes the user pasted. Pull out: stated needs and pains, explicit and implicit requirements, objections, buying/expansion signals, competitor mentions, who was in the room and their apparent role, and any commitments made by either side.
- Separate what the customer *said* from what you're *inferring*. Label inferences as such.
- Don't invent details the transcript doesn't contain. Gaps are findings too — flag what wasn't covered but should have been.

**Follow-up / Planning:**
- Ground every action in something from the call or context — a stated need, an open question, a commitment made. Quote or reference the source line.
- Draft follow-ups (email, next-step list, mutual plan) that reflect what the customer actually asked for. Surface any commitment the SE made on the call so it doesn't get dropped.
- Flag open questions the SE still needs answered before the deal can progress.

**Conversation Prep:**
- Work from whatever the user pastes about the account — prior call notes, email threads, context. If they paste CRM fields (opportunities, amounts, stages), use them; otherwise proceed on context alone and note the absence in the footer.
- Surface: what's known about the account's needs, open threads from last contact, and what to confirm or advance in this conversation.

**Research:**
- Search the web and connected enablement content for the topic.
- For anything technical, search Salesforce developer documentation dynamically — see "Developer documentation search" below.
- No external search available → rely on general knowledge but label it unverified rather than sourced fact.

**Solutioning:**
- Work from the requirement as described in the transcript or context. Restate the use case in your own words and confirm it against what the customer said.
- Identify **which clouds the requirement touches** before searching — marketing use cases routinely pull in Data Cloud for unified profiles, core platform for records, and Service or Commerce depending on the flow. Name the cloud combination explicitly.
- Search for relevant solution patterns, architecture references, and product capabilities — see "Developer documentation search" below. Label the source of each.

### Developer documentation search

For Research and Solutioning, search Salesforce technical sources **dynamically** rather than citing a fixed link list — the right page depends on the clouds in play. When web search is available, search live and cite what you find; when it isn't, point the user to the right hub to search themselves and label it as a pointer, not a sourced answer.

Match the source to the clouds the requirement touches. Common starting points:

- **Developer hub** — `developer.salesforce.com/docs` — the index for all API, Apex, and platform references.
- **Core platform** — Apex, SOQL/SOSL, REST API, Bulk API, Metadata API references under the developer hub.
- **Marketing Cloud** — Marketing Cloud Engagement APIs and SDKs; Marketing Cloud Growth on the core platform.
- **Data Cloud** — Data Cloud developer docs (data model, ingestion, identity resolution, calculated insights) — where most modern marketing solutioning lands.
- **Reference architectures** — `architect.salesforce.com` — for solution patterns and multi-cloud blueprints.
- **Enablement framing** — Trailhead — for how to position or explain a capability.

Because solutions often span clouds, expect to search more than one of these for a single requirement, and surface related links across them rather than stopping at the first cloud that fits. Prefer live search results over general knowledge whenever search is available.

## Phase 3 — Synthesize

- Ground everything in the transcript or pasted context. Never invent financial figures, dates, stages, or commitments — if the user pasted them, use them; if not, mark "[not in transcript]" rather than guessing.
- Apply the revenue + customer-success lens: for the needs surfaced, name both the customer's success outcome and the Salesforce revenue angle, kept honest against what the call supports.
- For Research and Solutioning, tie findings back to the customer need they address (e.g. "this answers the identity-resolution need the customer raised at [point in call]"). If no need is tied, state findings as general enablement.
- For multi-cloud solutions, make the cloud dependencies explicit — which cloud owns which part of the flow — since that's where scoping and licensing questions surface.

## Phase 4 — Output

Match the output to the triaged mode, using this exact structure:

```
# [Mode]: [Account / Topic]

**Assumed mode:** [state only if inferred rather than confirmed; otherwise omit this line]

## Triage Rationale
(this is the audit — chosen vs. rejected, so you can see if it routed right)

| Decision | Chose | Rejected / skipped | Why |
|---|---|---|---|
| Mode | [mode chosen] | [modes considered and dropped] | [phrase/context that decided it] |
| Sources | [sources used] | [sources skipped, or "none"] | [why each was skipped] |
| Items | [items kept] | [notable items left out] | [why they were excluded] |

--- (if Call Analysis) ---

## What the customer said
[stated needs, pains, requirements, objections — grounded in the transcript, sourced to points in the call]

## Signals & inferences
[buying/expansion signals, competitor mentions, room dynamics — labeled as inference where not explicit]

## Gaps
[what wasn't covered but should have been]

--- (if Follow-up / Planning) ---

## Next steps
[each action tied to a source line from the call/context]

## Draft follow-up
[email or message reflecting what the customer actually asked for]

## Open questions
[what the SE still needs answered]

--- (if Conversation Prep) ---

## What's known
[account needs and open threads from prior context]

## Advance in this conversation
[what to confirm or move forward]

--- (if Research or Solutioning) ---

## Key Findings
[bulleted, each cited to source — live search / dev docs / architect.salesforce.com / general knowledge, labeled accordingly]

**Clouds involved:** [list the clouds the solution touches, or "single cloud: [name]"]

--- (all modes) ---

## Need + revenue lens
- **Customer need:** [what they actually need, from the transcript]
- **Salesforce angle:** [revenue + customer-success mapping, honest to what the call supports, or "transcript doesn't support a revenue angle yet"]

---

**Footer:** [sources used; anything skipped and why; assumptions made]
```

## Key principles

- Transcripts and pasted context are the source of truth. Claude is not connected to CRM — never assume or invent CRM data.
- Never invent financial figures, dates, stages, or commitments. Missing → "[not in transcript]".
- The revenue angle must follow from a real need in the call. Never manufacture urgency or an expansion story the transcript doesn't support — overreaching past what the customer said costs trust and the deal.
- The Triage Rationale table is mandatory on every run. Always show both the chosen and rejected side.
- Default to the mode the evidence supports; ask only when both mode and context are missing.
- Assume multi-cloud until proven otherwise for solutioning — surface adjacent clouds rather than stopping at the obvious one.
- Search developer docs dynamically and cite what you find; label general knowledge as such.
sfdc-headless-discoveryFind an unknown Salesforce API contract instead of guessing or escalating to a human: the enumerators, the three oracles, route families to try in order, error messages that mislead, and the escalation gate.
---
name: sfdc-headless-discovery
description: "Find an unknown Salesforce API contract instead of guessing or escalating to a human: the enumerators, the three oracles, route families to try in order, error messages that mislead, and the escalation gate. Use whenever a Salesforce step looks impossible over the API, a name or shape is unknown, a doc says something needs the UI, or you are about to hand a step back to the user."
---

# Headless discovery

Every "impossible over the API" met so far was one of six things: a missing request field, a wrong API version, an unexamined Aura call, a stale assumption in your own docs, a name guessed instead of enumerated, or **the wrong route family**. Zero were real capability gates. Read this before recording an impossibility or asking someone to click.

## The rule

When you do not know a NAME or a SHAPE, find the thing that ENUMERATES it. The tell that you are guessing: candidates are coming from intuition rather than from a response. Bulk guessing has never converged in practice (60 rejected definition names on one occasion, 32 on another); a single enumerator call has, repeatedly.

## Enumerators by question

| Question | Enumerator |
|---|---|
| What operations exist here? | MCP `discover` in plain words, then `describe` for the path and schema |
| What buttons does a record page have? | `GET /ui-api/actions/record/{id}` |
| Is there a standard invocable? | `GET /actions/standard`, grep the name. This is how segment publish was found (`cdpPublishSegment`) |
| Is the sObject writable where Connect is not? | `GET /sobjects/{Object}/describe` and check `updateable` per field |
| What components exist and what props? | `GET /component-catalog/components?target=...`, then `/component/{ns}/{name}/{Module or Component}/source` |
| What does a valid body look like? | GET a complete existing object of the same type, ideally one the UI created |
| What does the UI call? | Intercept `POST /aura`, read the descriptor, replay it |
| What DMOs and fields exist? | `GET /ssot/metadata?entityName=...` |

## The three oracles

1. **Schema oracle.** A strict validator with `additionalProperties: false` names every rejected and required property and lists enum values. Send `{}` to learn what is required; send a batch of guesses and whatever is not named as rejected is real.
2. **Processor oracle.** On a schema free `object`, a 500 means a recognised key with a wrong shape, and a transformed read back (HTML escaping) means recognised and processed. A 200 there proves nothing.
3. **Editor oracle, the cheapest and most overlooked.** The API only names keys you send; it never volunteers one. So the fastest schema source is an object the UI already wrote. SOQL the records of that type, GET one, diff against yours. Check this FIRST in a new org. It costs one query and one GET, and it has repeatedly beaten hours of probing.

## Route families, in order

1. Connect API (`/connect/...`, `/ssot/...`)
2. **Standard invocable actions** (`/actions/standard/{name}`, invoked with `{inputs:[{...}]}`)
3. sObject API, including objects that look internal (MarketSegment, FlowRecord, ManagedContentVariant)
4. Tooling API, including `MetadataContainer` for in place Apex updates and `PackageInstallRequest` for managed packages
5. Aura capture and replay (needs a browser)

Metadata API deploys are not reachable through the MCP connector, so custom objects and org wide overrides stay clicks.

**Two routes that solved things a "proper" route could not:**
- `PackageInstallRequest` installed a data kit that the product's own deploy endpoint silently no-opped on, and unlike that endpoint it has a real per request status reader.
- `MetadataContainer` plus `ApexClassMember` plus `ContainerAsyncRequest` updates Apex in place when a `Body` PATCH is refused, without deleting a class other components depend on.

## Errors that are not what they say

| Message | Meaning |
|---|---|
| `Set the segmentType to Dbt or Lookalike` | You did not send `segmentType` |
| `Expected referredColumns to be not empty` | This route cannot write; use the sObject route |
| `500 Internal error` on a data graph write | It committed. GET before retrying |
| `No such column` right after a 201 field create | FLS. Grant it on a standalone permission set |
| Aura `200` with `actions:[]` | Wrong descriptor, or stale captured token |
| `INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY` on a Tooling Apex Body PATCH | Use MetadataContainer |
| `AURA_COMPILE_ERROR ... missing label` on an LWC bundle POST | You sent `targetConfigs` as raw XML, or a `.js-meta.xml` |
| A list route 404 | It may need a filter parameter to serve at all. `data-model-object-mappings` only responds with `?dmoDeveloperName=` |
| Any `200` or `SUCCESS` | Nothing. Verify with an independent read |

An error naming a field is a missing field error, not a capability gate.

## Small traps that cost real time

- A `+` in an `executeAnonymous` query string decodes as a space and the compile error points at the wrong token. Build output with a `List<String>` and `String.join`.
- A `throw` in `executeAnonymous` rolls back all DML in that block.
- Never send back HTML that a GET returned. Where a write applies a sanitizer plus an escape, the correct inverse is to unescape until stable, and it must cover every text bearing field including URLs.
- `FieldPermissions` cannot be written to a permission set inside a permission set group.
- A record page that sets `parentFlexiPage` inherits regions you cannot edit or remove, and the parent may not exist in Tooling at all. Build standalone if you need control of the whole page.
- Some list endpoints page at 10 regardless of `limit` and 500 on a larger one. Read by name instead.

## When a subagent or a long run is involved

Cap each unit at roughly 20 to 25 calls and ten minutes, and report at the cap even if incomplete. A partial result with the exact blocking error is worth more than an overrun. State a hard rule that a run must not delete anything it did not create, because a delete-and-recreate that fails halfway leaves a worse state than not starting.

## Escalation gate

Hand a step to a human only when all five are true: the enumerator for this class was used and does not cover it; the newest API version was tried; the UI can do it and its captured call does not replay, or no browser is available and you say so; no OOTB or editor authored example exists to read; no equivalent route or outcome exists.

Then escalate the **cheapest possible action** ("build one in the UI once and I will read it back", "authorize the target once"), say exactly what you will do with it, and keep building everything around it.

## Doc hygiene and honesty

A documented impossibility that was never re-tested against a named endpoint is a hypothesis, not a fact. When you disprove one, correct the doc in the same pass with the route that worked, the exact body, and the trap that hid it.

Never report a UI outcome you have not seen. "Persisted and processor recognised" is a different claim from "renders in the editor", and conflating them wastes someone's afternoon.
sfdc-mcnext-campaign-buildBuild Marketing Cloud Next campaigns headlessly through the Salesforce MCP connector: campaign records, Data Cloud segments with criteria and publish, email and SMS content, Dynamic Content personalization points, Journey flows with real Path Experiment elements, campaign members, and mock engagement that actually renders in the OOTB dashboards.
---
name: sfdc-mcnext-campaign-build
description: "Build Marketing Cloud Next campaigns headlessly through the Salesforce MCP connector: campaign records, Data Cloud segments with criteria and publish, email and SMS content, Dynamic Content personalization points, Journey flows with real Path Experiment elements, campaign members, and mock engagement that actually renders in the OOTB dashboards. Use when asked to create, rebuild, or package a marketing campaign, segment, flow, email or SMS content, dynamic or personalized content, campaign goals, or mock engagement data in a Salesforce demo org."
---

# MC Next campaign build, headless

Every contract here ran live in a healthcare demo org on 2026-09-01/02 through `mcp__Salesforce_-_Beta__dispatch` alone. No browser, no CLI, no Data Kit. Six campaigns end to end took about 90 minutes once these traps were known. Read the traps before the steps.

## Operating rules

- Work in units of one campaign or one layer, each under ~25 API calls, and post a one line status after each. A silent 90 call agent reads as "stuck".
- Never delete anything that existed before the run. Segments cannot be deleted over the API; name probes `zz_`.
- A 200 or 201 is a claim. Read the object back and reconcile counts against an independent `POST /ssot/queryv2` at the same grain.
- Never send back text that a GET returned (see escaping below).
- **Long waits belong outside the run.** A data stream takes 5 to 11 minutes to surface rows and an identity resolution job takes 10 to 30. Fire those and check on a later turn; never sleep inside an agent waiting for them.
- No em dashes in any generated copy.

## Order

```
campaigns -> segments -> content -> dynamic content -> flows -> members and mock engagement -> web -> dashboards
```
Ids flow downstream: campaign ids into content UTMs, segment ids into flow starts, content keys into flow sends.

## Campaigns

`POST /services/data/v67.0/composite/sobjects` with Campaign records. Put the brief in `Description`; downstream agents read it for the content angle.

## Segments, fully headless

| Step | Call |
|---|---|
| Create | `POST /ssot/segments` `{displayName, segmentOnApiName, segmentType:"EinsteinGptSegmentsUI"}` |
| Criteria | `PATCH /sobjects/MarketSegment/{1sg}` `{"IncludeCriteria":"<JSON string>"}` -> 204 |
| Schedule | same PATCH: `PublishScheduleInterval`, `PublishScheduleStartDateTime`, `PublishType`, `PublishScheduleInfo` (JSON string) |
| Publish now | `POST /actions/standard/cdpPublishSegment` `{inputs:[{segmentId}]}` |

The Connect `PATCH /ssot/segments/{apiName}` cannot write anything, not even a rename: `referredColumns` is server derived. The sObject route is the write path. `saveAndCount` and the sObject route both silently ignore compound AND/OR criteria and count everyone, so one predicate per segment; for compound audiences compute a flag field on the CRM source and segment on `contains`. `GET /ssot/segments` 500s in some orgs; use SOQL `FIELDS(STANDARD) FROM MarketSegment`. An unpublished segment has no membership rows and will not appear on a contact card.

**The segment apiName is not on the sObject.** `MarketSegment` has no `DeveloperName` and no `ApiName`. The Data Cloud api name, which Dynamic Content targeting rules require, comes only from `GET /ssot/segments/{1sg id}` -> `segments[0].apiName`. It is the display name with non-alphanumeric runs collapsed to single underscores.

Profile DMO attributes are RELATED (three hops: Unified, UnifiedLink, ssot__Individual, profile DMO). Read the path off an existing segment; never guess it.

**Audience size is a design input.** A segment returning ten people cannot express a rate: opens, clicks and bounces all round to something absurd, and any guaranteed-minimum in the mock generator dominates. Widen the predicate before that campaign goes in a demo rather than inflating its data.

## Content

Create `POST /connect/cms/contents`, publish `POST /services/data/v62.0/connect/cms/contents/publish`. Flow reference is `marketing--Default_Content_Workspace.sfdc_cms__email--<contentKey>`.

Build from a generator with JSON specs, not by hand: subject <= 50 chars, H1 <= 9 words, one paragraph with `{!$recipient.FirstName}`, one `lightning/button` with `uri`, a three item list, plain language footer. SMS is `<Brand>: <benefit <= 20 chars> <link>?src=<code> Reply STOP to opt out.` at <= 160 chars with ONE query param.

**Image hosting is the biggest time sink.** `ContentVersion` needs base64 in JSON, so the model transcribes 15 to 45 KB per image and one will come back truncated. Host hero images on the public demo website instead and reference them from a `lightning/html` img tag. Upload only small assets like a logo (a 200px lockup is about 2 KB base64).

**A PUT on a content variant is a full replace and there is no PATCH** (the route allows DELETE, GET, HEAD, PUT). A partial body returns a bare 500 UNKNOWN_EXCEPTION, not a validation error. Send the complete `contentBody` including `sfdc_cms:block` on every write.

**Locate the hero block by `width="600"` in its rawHtml**, never by position. The logo is a `lightning/html` img on some emails and a `lightning/image` contentKey block on others, so "the first lightning/html block" picks the logo on half of them.

### The escaping algorithm, and its exact inverse

The API applies two stages on write: a URL sanitizer that rewrites `=` to `&#61;` and `&` to `&amp;` **inside quoted src and href values inside rawHtml only**, then a single HTML escape over the whole string. The `uri` of `lightning/button` never goes through stage one, which is why it stores a bare `=` and a single `&amp;`.

So the inverse is **one** html.unescape pass, then `&#61;` to `=` and `&amp;` to `&` inside quoted src and href values only.

Unescaping until the string stops changing is WRONG and silently destructive. Writing `<p>Base hero &amp; more</p>` stores `&lt;p&gt;Base hero &amp;amp; more&lt;/p&gt;`, so one pass returns the original and a second turns an intentional `&amp;` into a bare `&`. Write the inverse as a script, not by hand, and have it refuse to emit a body containing residual `&amp;amp;` or `&amp;#61;`.

The sanitizer also appends `noopener noreferrer` to every `rel` on every write, so collapse it to one pair on read; API written content then sits stably at two pairs. `&#39;` reappearing after a write is correct. `&amp;amp;` or `&amp;#61;` in a button `uri` is corruption.

### Publish returns 400 when there is nothing to publish

`POST /connect/cms/contents/publish` returns `400 INVALID_API_INPUT "Your content wasn't published. Try again."` when the pieces are already Published with no pending delta. Retrying, splitting the batch and changing API version never clear it. Verify with `status.status` and `isPublished` on the variant instead of trusting the publish call, and note a single deployment can flip pieces beyond the ids you listed.

## Dynamic Content, fully headless

Three objects, not one. The email holds no rule; it holds a name reference to a decision.

**Step 1, the personalization point.** `POST /services/data/v67.0/personalization/personalization-points`:

```json
{"name":"cld_<campaign>_<piece>_v1","label":"...","description":"email:<content title>",
 "dataSpaceName":"default","profileDataGraphName":"<the graph the email declares>",
 "schemaEnum":"ExperienceVariation","source":"BlockBuilder",
 "sourceRecordId":"<the ManagedContent 20Y id, NOT the 9Ps variant id>",
 "isAuthenticationRequired":false,
 "decisions":[{"name":"<decision>","label":"...","description":"...","state":"Live",
   "attributeValues":[{"attributeEnum":"Variation","value":"<the SAME decision name>"}],
   "targetingRules":{"operator":"And","type":"Group",
     "rules":[{"operator":"IsIn","segmentName":"<segment apiName>","type":"Segment"}]}}]}
```

Do not send `status`; it is rejected and server set, going Processing then Active in seconds. Priority is the decision's `Priority`. The Default or Fallback the editor shows is not a stored object, it is the base content. One point can hold several priority-ordered decisions when you want more than two creative variants on one email.

**Step 2, bind it on the email**, in the same full body PUT:

```json
"sfdc_cms:variants":[
 {"id":"<uuidA>","name":"<one variation name>","type":"personalization",
  "body":{"subjectLine":"...","preheader":"..."}},
 {"id":"<uuidB>","name":"<the SAME name>","type":"personalization",
  "body":{"sfdc_cms:block":{"children":[{"id":"<target block id>","definition":"lightning/html",
    "type":"block","attributes":{"rawHtml":"<img ... />"}}]}}}],
"sfdc_cms:operations":[
 {"definition":"sfdc_cms__pspVariantOperation",
  "attributes":{"personalizationPoint":{"dataspace":"default","name":"<point name>"},
    "decisionToVariantList":[{"decisionName":"<decision>","variantId":"<uuidA>"}]}},
 {"definition":"sfdc_cms__pspVariantOperation","targetId":"<target block id>",
  "attributes":{"personalizationPoint":{"dataspace":"default","name":"<point name>"},
    "decisionToVariantList":[{"decisionName":"<decision>","variantId":"<uuidB>"}]}}]
```

One variant per scope. Subject line and preheader are one scope, each overridden block is another; a variation touching both is two variants sharing one name, which is what the editor shows as Linked. `targetId` absent means email level, present means that block. The block level variant body is flat: `sfdc_cms:block.children[]` holds the overriding block with the SAME id, no section or column wrapper. `dataspace` is lowercase inside the operation and `dataSpaceName` is camelCase on the point; both are correct.

**`lightning:expressions[]` is not involved and stays empty**, including on editor authored variations. Guessing definition names there is the classic dead end; the definition you want is `sfdc_cms__pspVariantOperation`.

**Vary the image AND the copy, then prove it.** A variation whose variant hero is the same file as the base and whose subject matches the base is wired correctly and shows the recipient nothing different. Diff the variant `src` against the base `src` (compare on the `ids=` parameter or the filename, not the escaped string) before calling it done.

Design rule: target a segment OTHER than the campaign's own audience. Targeting a campaign at its own segment matches 100 percent of the send and makes the default dead.

Other traps: changing a block's `definition` after operations are bound returns `DeleteRestrictedByFkException` and writes nothing, so restructure before attaching. A point bound to content can never be deleted, even after the content is deleted; an unbound point deletes cleanly. SMS content is flat with no blocks, so it carries no dynamic image.

## Flows, with a real Path Experiment

`POST /tooling/sobjects/Flow` `{FullName:"flow_<campaignId>_<epoch>", Metadata:{processType:"Journey", status:"Draft", start:{triggerType:"Segment", segment:"<18 char MarketSegment Id>", connector}, decisions, actionCalls, waits, experiments, exitRules}}`.

**A Journey Flow POST creates the FlowRecord automatically**; FlowRecord itself has zero createable fields. Link to the campaign with `PATCH /sobjects/FlowRecord/{2aF}` `{"AssociatedRecordId":"<701>"}`.

The Path Experiment element, verified accepted:

```json
"experiments": [{
  "name": "cld_Path_Experiment",
  "label": "A/B: <the two angles>",
  "type": "Automatic",
  "testGroupPercentage": 20,
  "duration": 2,
  "durationUnit": "Weeks",
  "fallbackMode": "BestPerformer",
  "primaryMetric": "Conversion",
  "paths": [
    {"name":"Path_A","label":"Path A","percentage":50,"connector":{"targetReference":"Send_Email_A"}},
    {"name":"Path_B","label":"Path B","percentage":50,"connector":{"targetReference":"Send_Email_B"}}
  ]
}]
```

Do not model an A/B split as a Decision. The real element exists and the API accepts it.

Other flow facts: `waits[]` need `defaultConnectorLabel`; `offsetUnit: "Hours"`; `SECOND()` needs `TIMEVALUE()`. A Tooling PATCH on a Draft Journey flow **re-issues the Flow Id**, so re-query `FlowDefinition.LatestVersionId` after every PATCH. `InvalidDraft` status is normal until From address, subscription, SMS sender code and a segment schedule are set, and is acceptable in a demo org.

## Members and mock engagement that actually renders

Apex generators, deployed with `POST /tooling/sobjects/ApexClass`. Use **Bresenham style allocation**, not modulo: a modulo cycle only hits the target rate when n is a multiple of 100 and is wrong in every real cell.

### The vocabulary that decides whether the OOTB dashboards show anything

This is the difference between a campaign that looks alive in the standard Insights and Deliverability tabs and one that shows a wall of zeros. Event types alone are not enough; two status fields decide it.

| Field | MUST be | Not |
|---|---|---|
| `ssot__EmailRecipientSendStatus__c` | `SENT`, and `NOT_SENT` on a bounce | `Sent`, `Bounced`, `Delivered` |
| `ssot__EmailBounceType__c` | `HARD_BOUNCE` / `SOFT_BOUNCE` | `Hard`, `Soft` |
| `ssot__EngagementChannelActionId__c` | `SEND`, `SEND_STATUS`, `OPEN`, `CLICK`, `BOUNCE`, `UNSUBSCRIBE` | anything partial |

Note the trap inside the trap: it is not "uppercase everything". `Bounced` becomes `NOT_SENT`, because that field describes whether the send succeeded, not what happened afterwards.

**The diagnostic signature: Click-Through Rate renders correctly while every other tile reads zero.** CTR is clicks over opens and applies no send-status filter; Sends, Open Rate, Click Rate, Delivery Rate, Bounces and Opt-Out Rate all count or divide by sends. If you see that pattern, it is the vocabulary, not missing data. Confirm by diffing your rows against a pre-existing dataset in the same org that does render.

More rules:

- **Emit the full lifecycle.** Missing `SEND` zeroes six tiles at once because it is the denominator.
- **Guarantee an EMAIL-channel floor.** At a realistic 1 to 2 percent, a 135 person audience can produce a single bounce and land it on SMS by chance, leaving every Email deliverability tile blank. Force the first recipient of each variant to bounce and the second to unsubscribe.
- **Bounces and unsubscribes must exist on the EMAIL channel specifically**; the Deliverability tab filters `ssot__EngagementChannelTypeId__c = EMAIL`.
- **Fill the whole 30 day window.** Anchor to `Datetime.now()` and spread sends across roughly now-26d to now-6d. Data at a fixed offset ages out of a Last 30 Days filter while the org sits idle.
- **Make the seed idempotent** (delete by a group field, re-insert) so it is safe to re-run, and re-run it after any idle period.
- Verify by joining `ssot__EmailEngagement__dlm` through `ssot__BulkEmailMessageId__c` to `ssot__BulkEmailMessage__dlm.ssot__CampaignId__c`; there is no campaign column on the engagement DMO. The action column is `ssot__EngagementChannelActionId__c`, not `...ActionTypeId__c`.

Plausible seeding ranges, so the out-of-the-box dashboards read as a real campaign rather than a wall of zeros: open 32 to 45 percent, click to open 12 to 18, SMS response 15 to 22, conversions 2 to 4 percent of sends. Click to open is the most stable of these across industries and the least distorted by Apple Mail Privacy Protection, so it is the one worth generating carefully. Make B beat A on most campaigns but not all. Cells under n = 60 cannot express a rate.

### Apex mechanics

**Updating a class in place** (a PATCH of `Body` fails with INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, and deleting a class an LWC or guest site depends on is unsafe):
```
POST /tooling/sobjects/MetadataContainer   {"Name":"..."}
POST /tooling/sobjects/ApexClassMember     {MetadataContainerId, ContentEntityId, Body}
POST /tooling/sobjects/ContainerAsyncRequest {MetadataContainerId, IsCheckOnly:false}
poll ContainerAsyncRequest for State
```

Apex traps: a `+` in an `executeAnonymous` query string decodes as a space and produces a compile error pointing at the wrong token, so build output with a `List<String>` and `String.join` and never use `i++`. A `throw` in the same block rolls back all DML, so commit with a plain call and read counts in a separate throwing call. **`when` is a reserved word** and cannot be a variable name. Apex identifiers are case insensitive, so a parameter `src` shadows a constant `SRC`. DLO columns are `<field>_c__c`, CRM fields are `<field>__c`.

Data stream refresh is `POST /ssot/data-streams/{name}/actions/run` `{}`. The verb is `run`, not `refresh`.

## Campaign outcomes and goals

Before trusting a custom-built outcomes panel, read its controller. Common defects found in one: objective and conversion signal were restricted picklists with defaults, so unset campaigns displayed a confident wrong answer instead of a blank; actual counted CampaignMembers at one specific status; channel credit was derived from the campaign **name**, making the attribution model selector inert; and the "web is not connected" caveat was a hardcoded literal that checked nothing.

Derive channel touches from real engagement rows, allocate credit per model (first, last, linear, time decay with a 7 day half life, position based), and compute percent in Apex because `SUM OVER PARTITION` is unavailable in Data Cloud SQL here. Set targets from the real converted contacts so attainment lands between roughly 60 and 115 percent with variety; every campaign at exactly 100 reads as fake.

## Reporting

Per unit: a table of ids, counts against predicted counts, every error verbatim, and the human steps that remain. Write a log doc per layer to the project.
sfdc-web-affinityStand up website behavioural data in a Salesforce demo org: a portable instrumented website, category tagging, the Web SDK and connector, DLO to DMO mapping, a category affinity Calculated Insight, an affinity wheel on the contact card, a guest write endpoint for an instant web-to-contact demo, and what it actually takes to segment on any of it.
---
name: sfdc-web-affinity
description: "Stand up website behavioural data in a Salesforce demo org: a portable instrumented website, category tagging, the Web SDK and connector, DLO to DMO mapping, a category affinity Calculated Insight, an affinity wheel on the contact card, a guest write endpoint for an instant web-to-contact demo, and what it actually takes to segment on any of it. Use when asked about web engagement, affinity wheels, category tagging, web attribution, the Web SDK, personalization zones, or connecting a website to Data Cloud."
---

# Web engagement and category affinity

Built and verified 2026-09-02 in a healthcare demo org. This covers the website, the pipeline into Data Cloud, the affinity insight, the contact card component, and the limits of each.

## The chain

```
page or article tagged with one of N categories
  -> event carries the category (in the URL path and as an attribute)
  -> DLO
  -> mapped to ssot__WebsiteEngagement__dlm.engagementServiceLine__c
  -> Calculated Insight: person x category x count x last seen
  -> Apex controller -> affinity wheel LWC on the Contact page
```

Two sources feed the same DMO by design: seeded mock rows through a CRM object, and live rows through a guest endpoint or the Web connector. Everything downstream is source agnostic, which lets the whole story be built and demoed before a connector exists.

## Know what the pipeline costs before promising a demo

Measured, not estimated:

| Hop | Trigger | Time |
|---|---|---|
| Browser to CRM row | immediate | under a second |
| CRM row to Data Cloud DMO | data stream run | **5 to 11 minutes** |
| DMO to affinity CI | CI run | seconds once triggered |
| CI to wheel | page load | immediate |
| CRM Contact to unified profile | identity resolution job | **10 to 30 minutes** |

Neither middle step fires on its own. A CI on a 24 hour schedule means today's clicks surface tomorrow unless you run it. Identity resolution may have `doesRunAutomatically: false`, in which case it has not run since somebody last pressed the button. **Read `lastJobCompleted` before assuming anything is current.**

Consequence for agents: never sleep inside a run waiting for these. Fire the job, end the turn, check later.

## What needs identity resolution and what does not

This distinction decides whether a demo works, and people assume wrongly in both directions.

| Capability | Needs identity resolution |
|---|---|
| Affinity wheel and recent web engagement on the contact card | **No.** Key on email and record id directly |
| Segment membership, campaign entry, activation | **Yes.** Segments run on the unified DMO |

So a person can appear on a contact card with a full affinity wheel minutes after typing their email, and still be invisible to every segment. Say this out loud when handing the kit over; a teammate will assume the wheel appearing means the person is targetable.

And even once unified, a web-only visitor matches nothing if every segment filters on payer or patient profile attributes they do not have. Behaviour-based targeting needs a segment built on web engagement or the affinity insight, not on profile fields.

## Taxonomy first, and keep it fixed

Pick 6 to 8 categories and never vary them. They appear in the site tags, the seed, the DMO field, the CI group by, and the LWC palette; changing the list means touching all five. Fewer than about six makes a thin, unconvincing wheel.

**Every category must map to something already in the org** (a condition flag, a quality measure, a campaign), or the wheel is decorative. The point is to enable "reads diabetes content and has an open A1C gap", not a pretty chart.

## Seeding realistic affinity

The weighting matters more than the volume. Per person: a dominant category at about 45 percent of their events, a secondary at 25, the rest spread over two or three others. Event counts varied (3 to 30). Timestamps across 90 days weighted recent. Derive everything from a hash of the person id so it is reproducible rather than random.

**Derive the dominant category from the person's real profile**, first match wins: diabetes flag to a diabetes category, hypertension to cardiovascular, an open screening gap to that screening category, Medicare or 60 plus to benefits, and so on, with a small percentage overridden to a rare category so it is represented.

A uniform random seed produces a flat wheel that reads as noise. Across eight categories the flat baseline is 12.5 percent; a real preference needs to sit three to four times above it. The same applies to a live visitor: four categories at two events each draws an evenly quartered wheel that is technically correct and visually meaningless, so coach the demo to click one category repeatedly.

Idempotency: a regenerate of thousands of rows exceeds the 10,000 DML row limit, so have `run(true)` purge and ask to be called again. Two calls for a clean rebuild.

## Identity: key on email, not a record id

The single most important design decision. A live visitor is identified by **email**, not a CRM record id, so seed the mock rows with the email too. `ssot__WebsiteEngagement__dlm.ssot__AccountContactId__c` declares a relationship to `ssot__ContactPointEmail__dlm.ssot__EmailAddress__c` and beacon mappings typically write the email into both that and `ssot__IndividualId__c`. Match on both, case insensitively; `LOWER()` works in the CdpQuery dialect.

Email matching email needs no identity resolution, which is what makes a live demo possible.

Know the limits and say them out loud: browsing done **before** someone identifies themselves carries no email and never joins. That is true of every web personalization story, not a defect.

## DLO to DMO mapping contract

| Fact | Detail |
|---|---|
| List | `GET /ssot/data-model-object-mappings?dmoDeveloperName=<dmo>`. **The bare list route 404s**; the query parameter is what makes it serve |
| Item route | `GET`, `HEAD`, `DELETE` only. `PATCH` returns METHOD_NOT_ALLOWED |
| Adding a field | Delete the mapping, re-POST the full field list plus the new pair. A second POST alongside fails with `DUPLICATE_DLO_TO_DMO_MAPPING` |
| Field name mangling | A CRM field `X__c` becomes `X_c__c` in the mapping body |

Refresh a stream with `POST /ssot/data-streams/{name}/actions/run` and an empty body. The verb is `run`, not `refresh`; `refresh` 404s.

One DLO can map into more than one DMO. If a web mapping reuses a field that an email mapping also uses (for example a send-status field carrying `utm_medium` for the web rows), never bulk-rewrite that field without excluding the web rows by channel.

## Calculated Insight contract

| Step | Call |
|---|---|
| Create | `POST /ssot/calculated-insights` with exactly `apiName`, `displayName`, `definitionType: "CALCULATED_METRIC"`, `publishScheduleInterval`, `publishScheduleStartDateTime`, `expression`. Do NOT send `dimensions`, `measures` or `dataSpace`; they are derived and the create fails |
| Interval value | `"TWENTYFOUR"`, echoed back as `TWENTY_FOUR`. `DAILY`, `Daily`, `DAY` and `Days` are all rejected |
| Run now | `POST /ssot/calculated-insights/{apiName}/actions/run` `{}` |
| Read | `GET /ssot/calculated-insights/{apiName}`. The `-definitions` path and `/runs` are 404s. Query its output at `{apiName}`, not `{apiName}__dlm` |

**Validate the SQL on queryv2 first**, but know the limit: queryv2 and the CI engine are different dialects. `DATE_SUB` exists in the CI dialect and fails on queryv2. So queryv2 validates grain, joins and aggregation only.

**Dimensions are frozen at create.** Measures and the expression patch freely; changing a dimension means delete and re-POST. Decide the grain first, and when in doubt include both candidate person keys as dimensions so the CI does not go blind when the live key differs from the seeded one. Note that a CI dimensioned on email and a CRM record id does not automatically join to the unified individual, which is the entity segmentation runs on.

## The wheel component

Apex controller plus an inline SVG donut LWC on the Contact page. Rules that matter:

- Compute percent in **Apex**, never in Data Cloud SQL (`SUM OVER PARTITION` is unavailable).
- Restrict to the known category list. The DMO field is polluted beyond null: real values include `SMS`, `WEB` and stray record ids, so filtering with `<> ''` grows junk categories.
- Always return every category, so a partial ring still draws a complete circle, and return an explicit empty flag rather than a broken wheel for people with no browsing.
- Read Data Cloud first, fall back to CRM SOQL both on exception **and on zero usable rows**, and say which path ran in a `dataSource` string. Given the 5 to 11 minute ingestion lag, the CRM fallback is what makes a live demo work at all; consider making it the primary path for records carrying the live-visitor marker.
- Use a categorical palette that cannot be confused with semantic red, amber and green used for compliance status elsewhere.

LWC bundle traps: a POST rejects a supplied `.js-meta.xml` as auto generated, and `targetConfigs` as raw XML triggers a misleading `AURA_COMPILE_ERROR` about a missing label. Send only html, js and css, and put `masterLabel`, `isExposed`, `apiVersion` and `targets` in the bundle metadata.

## Portable website

Remix rather than rebuild. Regenerating a site from a prompt produces different markup, and the sitemap binds to `data-event` attributes and path patterns, so a rebuild means re-deriving every rule.

Strip the personalization theater but **keep the identity plumbing**: the hidden admin identity page, every `data-event` attribute, the sitemap and schema, and the category tags. Removing the identity switcher kills affinity entirely.

One value cannot be copied: the beacon GUID is per connector. Put it, and any endpoint URL, in **one config file** so a teammate changes one file.

No credentials are needed anywhere. The beacon GUID is a public identifier in a CDN URL, and a Salesforce Site guest user serves anonymous traffic. If a website project asks for OAuth client secrets, something is architecturally wrong; remove it.

**Check that capture actually fires on the action the user takes.** A common and invisible failure: the handoff is called from a page-view handler, while every form submit sets local state and shows an inline success message without changing route. The forms then capture an email that never leaves the browser, and the only thing that ever posts is a later navigation. Test one form end to end and count the records; do not read the code and assume.

**Attributes are not wiring.** `data-event` attributes on buttons document intent. Unless the SDK reads them or an onClick calls the tracker, they do nothing. Check which.

**A remix call that times out has usually still succeeded.** Re-sending creates a duplicate project and burns credits; check the project list before retrying.

## The instant demo path, and the bug that will bite you

Real beacon events take minutes to reach Data Cloud, which kills a three minute demo. For the demo moment only, a guest accessible Apex REST endpoint on a Salesforce Site can take an email plus the session's browsing history, find or create a Contact, and write engagement rows directly, so the wheel paints in seconds.

**The Guest User cannot SEE Contact records under `with sharing`.** A class declared `global with sharing` runs its match query, gets zero rows every single time, and inserts a NEW Contact on every call. Eight page views produce eight duplicate contacts each holding one event, so no record ever has enough history to draw a wheel. The symptom looks like a broken affinity pipeline rather than a sharing problem, which is what makes it expensive.

Fix: put the lookup and insert in a private `without sharing` inner class, scoped as narrowly as possible, one exact-email query and one insert. Also give every event a stable id key and skip keys already stored, so a resent visit log cannot inflate the affinity.

This is a **demo only pattern, never production**. Guard it: a shared token in the body (not a secret, it ships in client JavaScript, so say so in the code), an allowlist of categories, a cap on events per call, write only with no data returned beyond the record id, and a marker field on everything created so it is deletable. Gate any created-versus-matched response behind the token or the endpoint becomes an email enumeration oracle.

Guest access needs: an Apex class grant, object create and field permissions on a permission set assigned to the site guest user (all API writable), and a `CorsWhitelistEntry` for the site origin. **Guest reachability can only be proven from a browser**; an authenticated call proves nothing.

## Before claiming a site is connected to Data Cloud

Check both halves and report which exist:

- **Site:** an SDK script tag in `index.html`, an init call, and a real beacon GUID. A `BEACON_GUID` constant whose value is the literal string `BEACON_GUID`, imported by nothing, is a placeholder.
- **Org:** a Web and Mobile App connector among the data connections, and an uploaded schema.

A site that console-logs, dispatches a `CustomEvent` and writes `localStorage` is an event-log demo, not an SDK integration, and it captures nothing anonymously. Calling that "web affinity is set up" when the affinity is entirely seeded plus one guest endpoint is the kind of claim that falls apart in front of a customer.
tableau-next-dashboard-craftBuild, style and embed Tableau Next (Salesforce) dashboards, visualizations, metrics and semantic models over the REST API in any demo or customer org, with the eye of a data-viz engineer and the discipline of a technical PM.
---
name: tableau-next-dashboard-craft
description: "Build, style and embed Tableau Next (Salesforce) dashboards, visualizations, metrics and semantic models over the REST API in any demo or customer org, with the eye of a data-viz engineer and the discipline of a technical PM. Use whenever someone mentions Tableau Next, Tableau Einstein, Data 360 analytics dashboards, semantic models, metric tiles, \"Can't show visualization\", embedding analytics in a Lightning page, or wants a dashboard that looks designed (goal lines, colour by category, title cards, section bands) rather than a default grid of charts."
---

# Tableau Next dashboard craft

You are acting as a technical product manager who used to be a data-viz engineer and still cares how a dashboard feels in the hand. Two beliefs drive everything below. First, the REST API is the real authoring surface: a dashboard generated from a script is reproducible, reviewable and portable across orgs, and the UI is for discovering shapes you cannot guess. Second, a dashboard is an argument, not an inventory. Every chart title states a finding, every section answers a question, every colour means one thing.

This skill was distilled from ~35 build passes in a healthcare payer demo org (membership, population health) between Aug 29 and Sep 1 2026. Grades used throughout: **[org]** executed live; **[doc]** Salesforce Help; **[gap]** tried and rejected or never found. Do not promise a prospect anything marked [gap].

The full reference set (exact JSON contracts, design system, every gotcha, learning links, and Python generators) lives in the packaged skill folder `tableau-next-dashboard-craft/` (references/api-contract.md, references/design-system.md, references/gotchas-and-challenges.md, references/learning-links.md, scripts/), which is not included in this public pack. When those files are available, read the matching one before building. When they are not, the essentials are below.

## The workflow that works

### 0. Get the org facts first

1. Confirm Tableau Next Creator/Consumer permission set licenses are Active.
2. `GET /services/data/v67.0/tableau/workspaces` and `GET /services/data/v67.0/ssot/semantic/models`.
3. **List existing instances of whatever you are about to create** (`GET /services/data/v66.0/tableau/visualizations`, `/services/data/v67.0/tableau/dashboards`) and read one complete body. OOTB dashboards (Campaign Insights, Consumption Analytics, Marketing Performance) are the schema documentation the API does not give you. This habit cracked every blocker we hit.
4. Note the semantic model id (`2SM…`), workspace id (`1Dy…`), and the semantic **object** apiName (e.g. `PayerProfile`), which is not the DMO name.

### 1. Build bottom-up: semantic model → metrics → vizzes → dashboard → embed

- **Semantic model**: `POST /ssot/semantic/models`, then `data-objects` with `dataObjectType: "Dmo"` and `shouldIncludeAllFields: true`. Relationships use `joinType: "Auto"` and semantic field api names (digit-suffixed on collision). Calculated Insights cannot be added as data objects [gap].
- **Metrics** `POST …/models/{model}/metrics`: `aggregationType` is `Average`/`Sum`/`Count` (not `Avg`), `timeDimensionReference` required in practice, `additionalDimensions` must include every field a dashboard filter uses or the filter silently ignores the tile. PUT/DELETE only, no PATCH.
- **Visualizations** `POST /services/data/v66.0/tableau/visualizations`: v66.0, because `marks`/`rows`/`columns`/`style` cap at API 66.07 (the "not allowed for API version 67.0" error is a version window, not a permission gate). Use `viewSpecification.filters` (plural). Viz `function` is `Avg`. Label ≤ 80 chars. `style.fit: "Entire"` on every dashboard viz. `style.axis[key]` for every continuous field. PATCH is a full replace.
- **Dashboards** `POST/PATCH /services/data/v67.0/tableau/dashboards`: `workspaceIdOrApiName` is the field that unblocks create (the "ask your admin" message is a missing workspace). PATCH is a full replace: send `label`, `name`, `workspaceIdOrApiName`, `layouts`, `widgets` every time. Widget `source` on input is `{id, name}` only. Response carries `status: Ok` per widget; read it.
- **Embed**: Lightning App Builder Tableau Next Dashboard component, or Tooling API FlexiPage component `analytics_embedding:dashboard` with `dashboardId` = api name, `height`, `hideTitle true`, `navigationMode Inline`. Height ≈ rows × rowHeight + gaps + 60.

### 2. Render-breaking rules

1. A reference line needs both halves: `visualSpecification.referenceLines[key] = ["Line", {"type":"Line","fieldKey":"F2","scope":"Table","line":{"valueType":"Value","value":0.75,"label":{"type":"Custom","labelText":"Goal 75%"}}}]` AND `style.referenceLines[key] = {"isVisible":true,"lineFormat":{"color":"#B91C1C","type":"Solid"},"labelAlignment":{"vertical":"Top","horizontal":"Right"}}`. Spec alone returns 200 and renders "Can't show visualization". Read-back drops the wrapper array; restore it before the next PATCH. `Dashed` is rejected.
2. A Color encoding (`marks.ALL.encodings: [{"fieldKey":"F3","type":"Color"}]`) needs `legends.F3` with a `position`, `style.marks.ALL.color.color: ""`, and F3 absent from `allHeaders.fields`. Auto palette only; per-category colour maps, gradients, `Funnel`, `Pie` are [gap] over REST. Build in the UI, GET, copy.
3. Crosstab needs `style.axis[<MeasureValues key>]`.
4. Dashboard `maxWidth` wider than the Lightning region makes the whole canvas blurry (CSS-scaled). 1000–1150 for a full-width app page.
5. Viz label does not render on the dashboard; the row field label does. Hide it (`style.fieldLabels.rows.showLabels: false`) and use a text title card.

### 3. Design pass (where the wow comes from)

- Grid: 72 columns, `rowHeight 12`, `cellSpacingX/Y 8`. Filters 11 cols × 5 rows, brand block 17 cols × 5 rows (15px bold + 12px subtitle), divider rule 1 row, hero 8 rows, section bands 3 rows, title cards 6 rows, charts 18 rows, tiles 24 rows, tables 40. Halves and full width only; thirds clip a 13px sentence.
- Hero: one sentence with the number in it (20px bold `#2E1065` on `#EDE9FE`) plus what to do about it (13px `#5B21B6`).
- Section band: `#E8EAF0`, 4px left border in the family colour, 12px caps label.
- Title card above every chart: 13px bold ink `#042339` takeaway + 11px muted `#5A6B7B` subtitle (denominators, time frame, caveats), tinted family background, 2px family bottom rule, radius 8; chart below white with left/right/bottom `#E5E5E5` border so the pair reads as one card.
- One colour family per meaning: blue `#1D4ED8` cost, teal `#0F766E` membership/brand, purple `#6D28D9` clinical, amber `#B45309` retention, green `#15803D` quality, red `#B91C1C` goal lines and utilization pressure, slate `#5A6B7B` neutral. Tints: `#EFF6FF #F0FDFA #F5F3FF #FFFBEB #F0FDF4 #FEF2F2 #F1F5F9`.
- Metric tiles: white, 4px top border in the family colour; `insights` on for at most two headline tiles.
- Goal bars = horizontal bar + red labelled reference line. This replaces gauges and bullet graphs.
- Titles state findings with the number in them; rates over counts when cohorts differ; denominators and thin cells (n<30) in the subtitle; say "placeholder" when a goal is one.

### 4. Verify live, then write it down

PATCH → read per-widget `status` → reload the embedded page → screenshot. A 200 proves the parser accepted it, not that it renders. Log ids, accepted and rejected values. Call out anything added unasked. When an unknown shape survives three error-walk attempts, stop and build one in the UI, GET it, copy it.

## Still open (Sep 2026)

Per-category colour mapping, gradient shading, Funnel and heat-map marks, dynamic text bound to metrics, measure filters, viz-level calcs, metric value formatting (0.77 vs 77%), Flow actions, Summary/Parameter/Image widget REST shapes. All exist in the UI; REST shapes are [gap].

## Learning links

Help hub: https://help.salesforce.com/s/articleView?id=analytics.tua_create.htm · Dashboards: https://help.salesforce.com/s/articleView?id=analytics.tua_create_dashboard.htm · Reference lines: https://help.salesforce.com/s/articleView?id=analytics.tua_create_viz_reference_line_about.htm · REST API: https://developer.salesforce.com/docs/analytics/tableau-next-rest-api/overview · Semantics APIs: https://developer.salesforce.com/docs/data/semantic-layer/guide/get-started.html · Embedding SDK: https://developer.salesforce.com/docs/analytics/sdk/guide/sdk-overview.html · Trailhead trail: https://trailhead.salesforce.com/content/learn/trails/unlock-actionable-data-insights-with-tableau-next · Craft: https://www.vizwiz.com/2018/07/visual-vocabulary.html, https://www.storytellingwithdata.com/blog/2020/3/5/transforming-slide-titles, https://www.perceptualedge.com/articles/misc/Bullet_Graph_Design_Spec.pdf

The datasets: schema and first 20 rows

appointments.csv2,989 rows · 19 columns

Join keys: Patient__c -> patients.Id · Patient_Email__c -> contacts.Email

ColumnType
Idsalesforce id
Nametext
Patient_Email__ctext
Patient__csalesforce id
Appointment_External_Id__ctext
Appointment_DateTime__cdatetime
Status__ctext
Appointment_Type__ctext
Modality__ctext
Service_Line__ctext
Provider_Key__ctext
Clinic_Location__ctext
Cancellation_Reason__ctext
No_Show_Reason__ctext
Lead_Time_Days__cinteger
Booking_Channel__ctext
Reminder_Sent__cboolean
Closes_Care_Gap__cboolean
Care_Gap_Type__ctext

First 20 rows

IdNamePatient_Email__cPatient__cAppointment_External_Id__cAppointment_DateTime__cStatus__cAppointment_Type__cModality__cService_Line__cProvider_Key__cClinic_Location__cCancellation_Reason__cNo_Show_Reason__cLead_Time_Days__cBooking_Channel__cReminder_Sent__cCloses_Care_Gap__cCare_Gap_Type__c
a37Hu000008OlkZIASAPT-0000001arthur.ashcombe1@example.coma2uHu00000ALL6fIAHAPT-a2uHu00000ALL6fIAH-02026-07-27T13:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-000Makana - Greater Indianapolis31WebTrueFalse
a37Hu000008OlkaIACAPT-0000002arthur.ashcombe1@example.coma2uHu00000ALL6fIAHAPT-a2uHu00000ALL6fIAH-12026-07-26T14:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-000Makana - Greater Indianapolis34Mobile AppTrueFalse
a37Hu000008OlkbIACAPT-0000003arthur.ashcombe1@example.coma2uHu00000ALL6fIAHAPT-a2uHu00000ALL6fIAH-22026-07-25T15:00:00.000+0000No ShowInitial VisitIn PersonPrimary CarePRV-000Makana - Greater IndianapolisForgot20In PersonTrueFalse
a37Hu000008OlkcIACAPT-0000004arthur.ashcombe1@example.coma2uHu00000ALL6fIAHAPT-a2uHu00000ALL6fIAH-F2026-09-26T16:00:00.000+0000ScheduledFollow Up VisitIn PersonPrimary CarePRV-000Makana - Greater Indianapolis29PhoneFalseFalse
a37Hu000008OlkdIACAPT-0000005arthur.brightwater1@example.coma2uHu00000ALL6gIAHAPT-a2uHu00000ALL6gIAH-02025-08-25T14:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-017Makana - Chicago3WebTrueFalse
a37Hu000008OlkeIACAPT-0000006arthur.brightwater1@example.coma2uHu00000ALL6gIAHAPT-a2uHu00000ALL6gIAH-12025-08-26T13:00:00.000+0000CompletedPreventive ScreeningIn PersonPrimary CarePRV-017Makana - Chicago5PhoneTrueFalse
a37Hu000008OlkfIACAPT-0000007arthur.brightwater1@example.coma2uHu00000ALL6gIAHAPT-a2uHu00000ALL6gIAH-F2026-09-29T13:00:00.000+0000ScheduledFollow Up VisitIn PersonPrimary CarePRV-017Makana - Chicago32PhoneFalseFalse
a37Hu000008OlkgIACAPT-0000008arthur.caldwell1@example.coma2uHu00000ALL6hIAHAPT-a2uHu00000ALL6hIAH-02025-07-18T14:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-018Makana - Boston14WebTrueFalse
a37Hu000008OlkhIACAPT-0000009arthur.caldwell1@example.coma2uHu00000ALL6hIAHAPT-a2uHu00000ALL6hIAH-12025-07-17T15:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-018Makana - Boston40In PersonTrueFalse
a37Hu000008OlkiIACAPT-0000010arthur.caldwell1@example.coma2uHu00000ALL6hIAHAPT-a2uHu00000ALL6hIAH-22025-07-16T16:00:00.000+0000CancelledFollow Up VisitIn PersonPrimary CarePRV-018Makana - BostonPatient Conflict42PhoneTrueFalse
a37Hu000008OlkjIACAPT-0000011arthur.caldwell1@example.coma2uHu00000ALL6hIAHAPT-a2uHu00000ALL6hIAH-32025-07-15T17:00:00.000+0000CancelledFollow Up VisitIn PersonPrimary CarePRV-018Makana - BostonTransportation12Mobile AppTrueFalse
a37Hu000008OlkkIACAPT-0000012arthur.caldwell1@example.coma2uHu00000ALL6hIAHAPT-a2uHu00000ALL6hIAH-42025-07-14T18:00:00.000+0000CancelledFollow Up VisitIn PersonPrimary CarePRV-018Makana - BostonProvider Rescheduled15PhoneFalseFalse
a37Hu000008OlklIACAPT-0000013arthur.caldwell1@example.coma2uHu00000ALL6hIAHAPT-a2uHu00000ALL6hIAH-52025-07-13T19:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-018Makana - Boston17AgentforceTrueFalse
a37Hu000008OlkmIACAPT-0000014arthur.dunmore1@example.coma2uHu00000ALL6iIAHAPT-a2uHu00000ALL6iIAH-02025-06-13T12:00:00.000+0000CompletedFollow Up VisitIn PersonPrimary CarePRV-035Makana - Los Angeles25In PersonTrueFalse
a37Hu000008OlknIACAPT-0000015arthur.dunmore1@example.coma2uHu00000ALL6iIAHAPT-a2uHu00000ALL6iIAH-12025-06-12T13:00:00.000+0000CompletedTelehealth ConsultVirtualPrimary CarePRV-035Makana - Los Angeles12WebTrueFalse
a37Hu000008OlkoIACAPT-0000016arthur.dunmore1@example.coma2uHu00000ALL6iIAHAPT-a2uHu00000ALL6iIAH-22025-06-11T14:00:00.000+0000CompletedTelehealth ConsultVirtualPrimary CarePRV-035Makana - Los Angeles38Mobile AppTrueFalse
a37Hu000008OlkpIACAPT-0000017arthur.dunmore1@example.coma2uHu00000ALL6iIAHAPT-a2uHu00000ALL6iIAH-32025-06-10T15:00:00.000+0000CompletedProcedureIn PersonCardiometabolicPRV-035Makana - Los Angeles40WebTrueFalse
a37Hu000008OlkqIACAPT-0000018arthur.dunmore1@example.coma2uHu00000ALL6iIAHAPT-a2uHu00000ALL6iIAH-42025-06-09T16:00:00.000+0000RescheduledLab WorkIn PersonSurgical & ProceduralPRV-035Makana - Los Angeles26PhoneTrueFalse
a37Hu000008OlkrIACAPT-0000019arthur.dunmore1@example.coma2uHu00000ALL6iIAHAPT-a2uHu00000ALL6iIAH-F2026-10-29T12:00:00.000+0000ScheduledFollow Up VisitIn PersonPrimary CarePRV-035Makana - Los Angeles62Mobile AppFalseFalse
a37Hu000008OlksIACAPT-0000020arthur.ellsworth1@example.coma2uHu00000ALL6jIAHAPT-a2uHu00000ALL6jIAH-02024-11-07T15:00:00.000+0000CompletedFollow Up VisitVirtualPrimary CarePRV-036Makana - Main Campus37AgentforceTrueFalse
campaign-members.csv1,189 rows · 8 columns

Join keys: CampaignId -> campaigns.Id · ContactId -> contacts.Id

ColumnType
Idsalesforce id
CampaignIdsalesforce id
ContactIdsalesforce id
LeadIdempty
Statustext
HasRespondedboolean
FirstRespondedDatedate
CreatedDatedatetime

First 20 rows

IdCampaignIdContactIdLeadIdStatusHasRespondedFirstRespondedDateCreatedDate
00vHu00002z0o3uIAA701Hu000002dAmQIAU003Hu00004BF7t5IADSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o4wIAA701Hu000002dAmQIAU003Hu00004BF7t6IADSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o3hIAA701Hu000002dAmQIAU003Hu00004BF7tAIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o69IAA701Hu000002dAmQIAU003Hu00004BF7tBIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o58IAA701Hu000002dAmQIAU003Hu00004BF7tCIATRe-EnrolledTrue2026-09-012026-09-01T06:25:05.000+0000
00vHu00002z0o4AIAQ701Hu000002dAmQIAU003Hu00004BF7tEIATRe-EnrolledTrue2026-09-012026-09-01T06:25:05.000+0000
00vHu00002z0o7lIAA701Hu000002dAmQIAU003Hu00004BF7tHIATSentFalse2026-09-01T06:25:06.000+0000
00vHu00002z0o47IAA701Hu000002dAmQIAU003Hu00004BF7tIIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o5PIAQ701Hu000002dAmQIAU003Hu00004BF7tLIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o4IIAQ701Hu000002dAmQIAU003Hu00004BF7tMIATRespondedTrue2026-09-012026-09-01T06:25:05.000+0000
00vHu00002z0o6KIAQ701Hu000002dAmQIAU003Hu00004BF7tTIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o4cIAA701Hu000002dAmQIAU003Hu00004BF7tUIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o4NIAQ701Hu000002dAmQIAU003Hu00004BF7tZIATSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o4pIAA701Hu000002dAmQIAU003Hu00004BF7thIADRespondedTrue2026-09-012026-09-01T06:25:05.000+0000
00vHu00002z0o51IAA701Hu000002dAmQIAU003Hu00004BF7tjIADSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o3wIAA701Hu000002dAmQIAU003Hu00004BF7tlIADRespondedTrue2026-09-012026-09-01T06:25:05.000+0000
00vHu00002z0o6hIAA701Hu000002dAmQIAU003Hu00004BF7toIADRespondedTrue2026-09-012026-09-01T06:25:05.000+0000
00vHu00002z0o4sIAA701Hu000002dAmQIAU003Hu00004BF7ttIADSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o5JIAQ701Hu000002dAmQIAU003Hu00004BF7txIADSentFalse2026-09-01T06:25:05.000+0000
00vHu00002z0o5DIAQ701Hu000002dAmQIAU003Hu00004BF7tzIADSentFalse2026-09-01T06:25:05.000+0000
campaigns.csv10 rows · 34 columns

Join keys: Id -> campaign-members.CampaignId, message-registry.cld_Campaign_Id__c · ParentId -> campaigns.Id

ColumnType
Idsalesforce id
Nametext
ParentIdsalesforce id
Typetext
Statustext
StartDatedate
EndDatedate
CurrencyIsoCodetext
ExpectedRevenueempty
BudgetedCostempty
ActualCostempty
ExpectedResponseinteger
IsActiveboolean
Descriptiontext
NumberOfLeadsinteger
NumberOfContactsinteger
NumberOfResponsesinteger
OwnerIdsalesforce id
CampaignMemberRecordTypeIdempty
cld_Goal_Label__ctext
cld_Goal_Metric__ctext
cld_Goal_Target__cinteger
cld_Goal_Baseline__cinteger
cld_Goal_Direction__ctext
cld_Goal_Period_Start__cdate
cld_Goal_Period_End__cdate
cld_Goal_Min_Sample__cinteger
cld_Objective__ctext
cld_Conversion_Signal__ctext
cld_Conversion_Identifier__ctext
cld_Attribution_Window_Days__cinteger
cld_Attribution_Model__ctext
cld_Conversion_Value__cinteger
cld_Message_Cap_30d__cempty

First 20 rows

IdNameParentIdTypeStatusStartDateEndDateCurrencyIsoCodeExpectedRevenueBudgetedCostActualCostExpectedResponseIsActiveDescriptionNumberOfLeadsNumberOfContactsNumberOfResponsesOwnerIdCampaignMemberRecordTypeIdcld_Goal_Label__ccld_Goal_Metric__ccld_Goal_Target__ccld_Goal_Baseline__ccld_Goal_Direction__ccld_Goal_Period_Start__ccld_Goal_Period_End__ccld_Goal_Min_Sample__ccld_Objective__ccld_Conversion_Signal__ccld_Conversion_Identifier__ccld_Attribution_Window_Days__ccld_Attribution_Model__ccld_Conversion_Value__ccld_Message_Cap_30d__c
701Hu000002dAmLIAUcld_2027 Plan Year Win-BackOtherIn Progress2026-08-102026-12-07USD0TrueParent campaign for the 2027 plan-year win-back program. Targets lapsed members (Renewal Status = Not Renewed) ahead of and through Medicare Advantage Annual Enrollment (Oct 15 - Dec 7 2026) for a 2027-01-01 effective date. Three consent-based child campaigns roll up here. Audience and channel eligibility are governed by the Plan and Benefits Updates communication subscription.000005000000000000AAA2027 plan year re-enrollmentsRe-Enrollments6441Higher is better2026-07-012026-09-15100Plan Re-EnrollmentWeb Form Submitcld-2027-reenroll-form28Position Based 40-20-401200
701Hu000002dAmQIAUcld_2027 Win-Back - Email Only701Hu000002dAmLIAUEmailIn Progress2026-08-102026-12-07USD0TrueLapsed members opted in to Plan and Benefits Updates on Email only. A/B on offer framing: plan value vs care continuity.014842005000000000000AAARe-enrollments from email-only membersRe-Enrollments1812Higher is better2026-07-012026-09-15100Plan Re-EnrollmentWeb Form Submitcld-2027-reenroll-form28Position Based 40-20-401200
701Hu000002dAmSIAUcld_2027 Win-Back - Multi-Channel701Hu000002dAmLIAUOtherIn Progress2026-08-102026-12-07USD0TrueLapsed members opted in on both Email and SMS. A/B on channel sequence: email first with SMS nudge at 72h, vs SMS first with email detail at 72h.06046005000000000000AAARe-enrollments from multi-channel membersRe-Enrollments3220Higher is better2026-07-012026-09-15100Plan Re-EnrollmentWeb Form Submitcld-2027-reenroll-form28Position Based 40-20-401200
701Hu000002dAmRIAUcld_2027 Win-Back - SMS Only701Hu000002dAmLIAUOtherIn Progress2026-08-102026-12-07USD0TrueLapsed members opted in to Plan and Benefits Updates on SMS only. A/B on call to action: reply for callback vs enrollment link.06029005000000000000AAARe-enrollments from SMS-only membersRe-Enrollments149Higher is better2026-07-012026-09-15100Plan Re-EnrollmentWeb Form Submitcld-2027-reenroll-form28Position Based 40-20-401200
701Hu000002dAmWIAUcld_Payer Improve Star Ratings before CAHPSOtherIn Progress2026-08-152026-11-30USD0TrueMakana Health Plans quality and retention. Active Medicare Advantage members with an open HEDIS gap are prompted to book an Annual Wellness Visit and close the gap before the CAHPS survey window. Goal: appointment scheduled. Email A/B on motivation (your health vs your benefits), SMS reminder with one-tap booking link.023012005000000000000AAAAnnual wellness visits scheduledEmails Delivered1411Higher is better2026-07-252026-09-08100Appointment ScheduledCampaign Member Status45Last Touch310
701Hu000002dAmXIAUcld_Payer Increase Mail Order Pharmacy EnrollmentOtherIn Progress2026-08-152026-12-31USD0TrueMakana Health Plans adherence and cost. Members managing a chronic condition on maintenance medication are enrolled in 90-day mail order. Goal: mail order enrollment completed on the member portal. Email A/B on lead benefit (never miss a refill vs save on copays), SMS with enrollment link. Drives Part D adherence Star measures and PMPM.01267005000000000000AAAMail order pharmacy enrollmentsEmails Delivered86Higher is better2026-07-152026-09-13100Mail Order EnrollmentCampaign Member Status60Last Touch640
701Hu000002dAmVIAUcld_Payer Medicare Age-InOtherIn Progress2026-08-152026-12-07USD0TrueMakana Health Plans acquisition. Commercial and Exchange members turning 65 within 12 months are guided to compare Medicare Advantage plans before their Initial Enrollment Period closes. Goal: plan comparison started on the website. Email A/B on framing (cost certainty vs keep your doctors), SMS nudge, paid social lookalike audience built from the segment.0102005000000000000AAAMedicare plan comparisons startedEmails Delivered33Higher is better2026-08-102026-09-0910Lead CaptureCampaign Member Status30Last Touch1400
701Hu000002dAmYIAUcld_Provider Care Gap Management - MammographyOtherIn Progress2026-09-012026-10-31USD0TrueMakana Health provider care-gap closure. Women overdue for breast cancer screening (HEDIS BCS non-compliant) are invited to book a mammogram during Breast Cancer Awareness Month. Goal: mammography appointment scheduled. Email A/B on tone (reassurance vs urgency), SMS with booking link.01358005000000000000AAAMammograms scheduledEmails Delivered77Higher is better2026-08-082026-09-07100Appointment ScheduledCampaign Member Status30Last Touch290
701Hu000002dAmaIAEcld_Provider Engage New Members for Primary CareOtherIn Progress2026-09-012026-12-31USD0TrueMakana Health new-patient onboarding. Patients whose only visit was an initial visit are nurtured to establish care with a primary care provider. Goal: primary care appointment scheduled. Three-touch nurture; Email A/B on lead content (meet your care team vs what to expect), SMS check-in.022612005000000000000AAAPrimary care visits scheduledEmails Delivered1110Higher is better2026-07-102026-09-08100Appointment ScheduledCampaign Member Status60Last Touch520
701Hu000002dAmZIAUcld_Provider Flu Shot ReminderOtherIn Progress2026-09-012026-11-15USD0TrueMakana Health seasonal outreach. Patients with no flu vaccination on record are reminded to get vaccinated at a Makana clinic or pharmacy partner. Goal: flu shot appointment scheduled or walk-in check-in. SMS-first with email detail; Email A/B on hook (protect your family vs walk in, no appointment).01949005000000000000AAAFlu shot appointments and walk-insEmails Delivered118Higher is better2026-07-222026-09-05100Appointment ScheduledCampaign Member Status45Last Touch95
cms-content.json25 rows · 22 columns

JSON, not CSV. It is the only non-CSV file in the pack and loads through a different path than the CSVs: the CSVs go in as records, these are CMS content pieces created in a content space, so they land through the CMS surface rather than a data load.

ColumnType
apiNametext
contentBodyobject
contentFqntext
contentKeytext
contentSpaceobject
contentTypeobject
contentVersionnumber
createdByobject
createdDatedatetime
externalIdtext
folderobject
isPublishedboolean
languagetext
lastModifiedByobject
lastModifiedDatedatetime
managedContentIdtext
managedContentVariantIdtext
managedContentVersionIdtext
statusobject
titletext
urlNametext
variantVersiontext

First 20 rows

apiNamecontentBodycontentFqncontentKeycontentSpacecontentTypecontentVersioncreatedBycreatedDateexternalIdfolderisPublishedlanguagelastModifiedBylastModifiedDatemanagedContentIdmanagedContentVariantIdmanagedContentVersionIdstatustitleurlNamevariantVersion
MCMS6AZLBOOFCDLB6G3MVM7YVQPQ{"backgroundColor":"#f7f7f7","lightning:dataProviders":[{"attributes":{"dataGraphApiName":"Demo_HLS_2"},"definition":"sfdc_cms__dataGraphDataProvider","sfdcExpressionKey":"$dataGraph"}],"lightning:expressions":[],"messagePurpose":"promotional","preheader":"Compare plans, keep your doctors, and re-enroll in about five minutes.","sfdc_cms:attachments":[],"sfdc_cms:block":{"definition":"sfdc_cms/root...marketing--Default_Content_Workspace.sfdc_cms__email--MCMS6AZLBOOFCDLB6G3MVM7YVQPQMCMS6AZLBOOFCDLB6G3MVM7YVQPQ{"id":"0ZuHu000001NIHUKA4","resourceUrl":"/services/data/v66.0/connect/cms/spaces/0ZuHu000001NIHU"}{"fullyQualifiedName":"sfdc_cms__email","name":"Email"}2{"id":"005000000000000AAA","name":"Demo Admin","resourceUrl":"/services/data/v66.0/chatter/users/005000000000000AAA"}2026-09-01T06:54:40.000Z{"id":"9PuHu000001NSojKAG","resourceUrl":"/services/data/v66.0/connect/cms/folders/9PuHu000001NSojKAG"}trueen_US{"id":"005000000000000AAA","name":"Demo Admin","resourceUrl":"/services/data/v66.0/chatter/users/005000000000000AAA"}2026-09-01T21:52:19.000Z20YHu00000BIkFgMAL9PsHu00000kkFISKA25OUHu00001mR4CROA0{"label":"Published","status":"Published"}cld_2027 Win-Back - Email Only Emailcld-2027-win-back---email-only-email2.1
MCHU35PNMRNNFJXEYOCBL5PGKAMA{"backgroundColor":"#f7f7f7","lightning:dataProviders":[{"attributes":{"dataGraphApiName":"Demo_HLS_2"},"definition":"sfdc_cms__dataGraphDataProvider","sfdcExpressionKey":"$dataGraph"}],"lightning:expressions":[],"messagePurpose":"promotional","preheader":"Plus dental, vision, and a $0 monthly premium on select Makana plans.","sfdc_cms:attachments":[],"sfdc_cms:block":{"definition":"sfdc_cms/rootC...marketing--Default_Content_Workspace.sfdc_cms__email--MCHU35PNMRNNFJXEYOCBL5PGKAMAMCHU35PNMRNNFJXEYOCBL5PGKAMA{"id":"0ZuHu000001NIHUKA4","resourceUrl":"/services/data/v66.0/connect/cms/spaces/0ZuHu000001NIHU"}{"fullyQualifiedName":"sfdc_cms__email","name":"Email"}1{"id":"005000000000000AAA","name":"Demo Admin","resourceUrl":"/services/data/v66.0/chatter/users/005000000000000AAA"}2026-09-01T06:54:45.000Z{"id":"9PuHu000001NSojKAG","resourceUrl":"/services/data/v66.0/connect/cms/folders/9PuHu000001NSojKAG"}trueen_US{"id":"005000000000000AAA","name":"Demo Admin","resourceUrl":"/services/data/v66.0/chatter/users/005000000000000AAA"}2026-09-01T20:14:27.000Z20YHu00000BIkFhMAL9PsHu00000kkFITKA25OUHu00001mR4CSOA0{"label":"Published","status":"Published"}cld_2027 Win-Back - Email Only Email (1)cld-2027-win-back---email-only-email-11.2
MC3W7PRJIAABHK3JLFHKSNFUBQAU{"backgroundColor":"#f7f7f7","lightning:dataProviders":[{"attributes":{"dataGraphApiName":"Demo_HLS_2"},"definition":"sfdc_cms__dataGraphDataProvider","sfdcExpressionKey":"$dataGraph"}],"lightning:expressions":[],"messagePurpose":"promotional","preheader":"A licensed Makana advisor can compare plans with you in one short call.","sfdc_cms:attachments":[],"sfdc_cms:block":{"definition":"sfdc_cms/roo...marketing--Default_Content_Workspace.sfdc_cms__email--MC3W7PRJIAABHK3JLFHKSNFUBQAUMC3W7PRJIAABHK3JLFHKSNFUBQAU{"id":"0ZuHu000001NIHUKA4","resourceUrl":"/services/data/v66.0/connect/cms/spaces/0ZuHu000001NIHU"}{"fullyQualifiedName":"sfdc_cms__email","name":"Email"}1{"id":"005000000000000AAA","name":"Demo Admin","resourceUrl":"/services/data/v66.0/chatter/users/005000000000000AAA"}2026-09-01T06:27:09.000Z{"id":"9PuHu000001NSojKAG","resourceUrl":"/services/data/v66.0/connect/cms/folders/9PuHu000001NSojKAG"}trueen_US{"id":"005000000000000AAA","name":"Demo Admin","resourceUrl":"/services/data/v66.0/chatter/users/005000000000000AAA"}2026-09-01T20:14:27.000Z20YHu00000BIkFbMAL9PsHu00000kkFINKA25OUHu00001mR4CMOA0{"label":"Published","status":"Published"}cld_2027 Win-Back - Multi-Channel Emailcld-2027-win-back---multi-channel-email1.2
consent/comm-subscription-channel-type.csv11 rows · 19 columns

Join keys: CommunicationSubscriptionId -> consent/comm-subscription.Id · EngagementChannelTypeId -> consent/engagement-channel-type.Id

ColumnType
Idsalesforce id
OwnerIdsalesforce id
IsDeletedboolean
Nametext
CurrencyIsoCodetext
CreatedDatedatetime
CreatedByIdsalesforce id
LastModifiedDatedatetime
LastModifiedByIdsalesforce id
SystemModstampdatetime
MayEditboolean
IsLockedboolean
LastViewedDatedatetime
LastReferencedDatedatetime
CommunicationSubscriptionIdsalesforce id
EngagementChannelTypeIdsalesforce id
DataUsePurposeIdempty
MessagingChannelIdempty
MessagingChannelUsageIdempty

First 20 rows

IdOwnerIdIsDeletedNameCurrencyIsoCodeCreatedDateCreatedByIdLastModifiedDateLastModifiedByIdSystemModstampMayEditIsLockedLastViewedDateLastReferencedDateCommunicationSubscriptionIdEngagementChannelTypeIdDataUsePurposeIdMessagingChannelIdMessagingChannelUsageId
0eBHu00000096whMAA005000000000000AAAfalseAppointment Reminders EmailUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvpKAG0eFHu000000p5MJMAY
0eBHu00000096wiMAA005000000000000AAAfalseAppointment Reminders SMSUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvpKAG0eFHu000000p5MKMAY
0eBHu00000096wjMAA005000000000000AAAfalseCare Gap Outreach EmailUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvqKAG0eFHu000000p5MJMAY
0eBHu00000096wkMAA005000000000000AAAfalseCare Gap Outreach SMSUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvqKAG0eFHu000000p5MKMAY
0eBHu00000096vAMAQ005000000000000AAAfalseCommunity Newsletter EmailUSD2026-07-13T21:33:06.000+0000005000000000000AAA2026-07-13T21:33:06.000+0000005000000000000AAA2026-07-13T21:33:06.000+0000truefalse2026-07-13T21:33:06.000+00002026-07-13T21:33:06.000+00000XlHu000000HUuSKAW0eFHu000000p5MJMAY
0eBHu000000kPhUMAU005000000000000AAAfalseGeneral Marketing EmailUSD2025-11-04T06:46:15.000+0000005000000000000AAA2026-07-13T21:34:05.000+0000005000000000000AAA2026-07-13T21:34:05.000+0000truefalse2026-07-13T21:34:05.000+00002026-07-13T21:34:05.000+00000XlHu000000obdAKAQ0eFHu000000p5MJMAY
0eBHu00000096wnMAA005000000000000AAAfalseHealth Tips EmailUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvsKAG0eFHu000000p5MJMAY
0eBHu00000096woMAA005000000000000AAAfalseHealth Tips SMSUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvsKAG0eFHu000000p5MKMAY
0eBHu00000096wlMAA005000000000000AAAfalsePlan and Benefits EmailUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvrKAG0eFHu000000p5MJMAY
0eBHu00000096wmMAA005000000000000AAAfalsePlan and Benefits SMSUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+00000XlHu000000HUvrKAG0eFHu000000p5MKMAY
0eBHu00000096vFMAQ005000000000000AAAfalseResearch & Advancements EmailUSD2026-07-13T21:33:49.000+0000005000000000000AAA2026-07-13T21:33:49.000+0000005000000000000AAA2026-07-13T21:33:49.000+0000truefalse2026-07-13T21:33:49.000+00002026-07-13T21:33:49.000+00000XlHu000000HUuXKAW0eFHu000000p5MJMAY
consent/comm-subscription-consent.csv5,828 rows · 27 columns

Load order: subscription, channel type, then consent. PartyId must already exist as an Individual.

Join keys: PartyId -> contacts.IndividualId · CommSubscriptionChannelTypeId -> consent/comm-subscription-channel-type.Id · EngagementChannelTypeId -> consent/engagement-channel-type.Id

ColumnType
Idsalesforce id
OwnerIdsalesforce id
IsDeletedboolean
Nametext
CurrencyIsoCodetext
CreatedDatedatetime
CreatedByIdsalesforce id
LastModifiedDatedatetime
LastModifiedByIdsalesforce id
SystemModstampdatetime
MayEditboolean
IsLockedboolean
LastViewedDateempty
LastReferencedDateempty
ConsentGiverIdempty
ContactPointIdsalesforce id
EffectiveFromDatedate
ConsentCapturedDateTimedatetime
ConsentCapturedSourcetext
CommSubscriptionChannelTypeIdsalesforce id
PartyRoleIdempty
BusinessBrandIdempty
PrivacyConsentStatustext
DataUsePurposeIdempty
EngagementChannelTypeIdsalesforce id
PartyIdsalesforce id
ContactPointValuetext

First 20 rows

IdOwnerIdIsDeletedNameCurrencyIsoCodeCreatedDateCreatedByIdLastModifiedDateLastModifiedByIdSystemModstampMayEditIsLockedLastViewedDateLastReferencedDateConsentGiverIdContactPointIdEffectiveFromDateConsentCapturedDateTimeConsentCapturedSourceCommSubscriptionChannelTypeIdPartyRoleIdBusinessBrandIdPrivacyConsentStatusDataUsePurposeIdEngagementChannelTypeIdPartyIdContactPointValue
0dYHu000000p8y2MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse9VlHu000001kTAYKA22025-07-282025-07-28T12:00:00.000+0000Preference Center0eBHu00000096whMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CLOA0rohan.delacroix1@example.com
0dYHu000000p8y3MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse9VlHu000001kTAYKA22025-07-282025-07-28T12:00:00.000+0000Preference Center0eBHu00000096wjMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CLOA0rohan.delacroix1@example.com
0dYHu000000p8y4MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse9VlHu000001kTAYKA22025-07-282025-07-28T12:00:00.000+0000Preference Center0eBHu00000096wlMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CLOA0rohan.delacroix1@example.com
0dYHu000000p8y5MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse9VlHu000001kTAYKA22025-07-282025-07-28T12:00:00.000+0000Preference Center0eBHu00000096wnMAAOptOut0eFHu000000p5MJMAY0PKHu000004Y5CLOA0rohan.delacroix1@example.com
0dYHu000000p8y6MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAZKA22026-07-222026-07-22T12:00:00.000+0000Preference Center0eBHu00000096whMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CMOA0
0dYHu000000p8y7MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAZKA22026-07-222026-07-22T12:00:00.000+0000Preference Center0eBHu00000096wjMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CMOA0
0dYHu000000p8y8MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAZKA22026-07-222026-07-22T12:00:00.000+0000Preference Center0eBHu00000096wlMAAOptOut0eFHu000000p5MJMAY0PKHu000004Y5CMOA0
0dYHu000000p8y9MAA005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAZKA22026-07-222026-07-22T12:00:00.000+0000Preference Center0eBHu00000096wnMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CMOA0
0dYHu000000p8yAMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAaKAM2026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096whMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CNOA0
0dYHu000000p8yBMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse0OwHu000002qNVNKA22026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096wiMAAOptIn0eFHu000000p5MKMAY0PKHu000004Y5CNOA0(317) 555-0114
0dYHu000000p8yCMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAaKAM2026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096wjMAAOptOut0eFHu000000p5MJMAY0PKHu000004Y5CNOA0
0dYHu000000p8yDMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse0OwHu000002qNVNKA22026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096wkMAAOptOut0eFHu000000p5MKMAY0PKHu000004Y5CNOA0(317) 555-0114
0dYHu000000p8yEMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAaKAM2026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096wlMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CNOA0
0dYHu000000p8yFMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse0OwHu000002qNVNKA22026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096wmMAAOptIn0eFHu000000p5MKMAY0PKHu000004Y5CNOA0(317) 555-0114
0dYHu000000p8yGMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:11:27.000+0000TrueFalse9VlHu000001kTAaKAM2026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096wnMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5CNOA0
0dYHu000000p8yHMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse0OwHu000002qNVNKA22026-07-292026-07-29T12:00:00.000+0000Preference Center0eBHu00000096woMAAOptOut0eFHu000000p5MKMAY0PKHu000004Y5CNOA0(317) 555-0114
0dYHu000000p8yIMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse9VlHu000001kTAbKAM2026-02-092026-02-09T12:00:00.000+0000Preference Center0eBHu00000096whMAAOptIn0eFHu000000p5MJMAY0PKHu000004Y5COOA0andre.halloran1@example.com
0dYHu000000p8yJMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse0OwHu000002qNVOKA22026-02-092026-02-09T12:00:00.000+0000Preference Center0eBHu00000096wiMAAOptOut0eFHu000000p5MKMAY0PKHu000004Y5COOA0(317) 555-0115
0dYHu000000p8yKMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse9VlHu000001kTAbKAM2026-02-092026-02-09T12:00:00.000+0000Preference Center0eBHu00000096wjMAAOptOut0eFHu000000p5MJMAY0PKHu000004Y5COOA0andre.halloran1@example.com
0dYHu000000p8yLMAQ005000000000000AAAFalseSubscription ConsentUSD2026-08-29T08:11:27.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000005000000000000AAA2026-08-29T08:32:29.000+0000TrueFalse0OwHu000002qNVOKA22026-02-092026-02-09T12:00:00.000+0000Preference Center0eBHu00000096wkMAAOptOut0eFHu000000p5MKMAY0PKHu000004Y5COOA0(317) 555-0115
consent/comm-subscription.csv7 rows · 15 columns

Join keys: Id -> consent/comm-subscription-channel-type.CommunicationSubscriptionId

ColumnType
Idsalesforce id
OwnerIdsalesforce id
IsDeletedboolean
Nametext
CurrencyIsoCodetext
CreatedDatedatetime
CreatedByIdsalesforce id
LastModifiedDatedatetime
LastModifiedByIdsalesforce id
SystemModstampdatetime
MayEditboolean
IsLockedboolean
LastViewedDatedatetime
LastReferencedDatedatetime
BusinessUnitIdempty

First 20 rows

IdOwnerIdIsDeletedNameCurrencyIsoCodeCreatedDateCreatedByIdLastModifiedDateLastModifiedByIdSystemModstampMayEditIsLockedLastViewedDateLastReferencedDateBusinessUnitId
0XlHu000000HUvpKAG005000000000000AAAfalseAppointment RemindersUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+0000
0XlHu000000HUvqKAG005000000000000AAAfalseCare Gap and Preventive Care OutreachUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+0000
0XlHu000000HUuSKAW005000000000000AAAfalseCommunity NewsletterUSD2026-07-13T21:33:06.000+0000005000000000000AAA2026-07-13T21:33:06.000+0000005000000000000AAA2026-07-13T21:33:06.000+0000truefalse2026-07-13T21:33:06.000+00002026-07-13T21:33:06.000+0000
0XlHu000000obdAKAQ005000000000000AAAfalseGeneral MarketingUSD2025-11-04T06:46:15.000+0000005000000000000AAA2026-07-13T21:34:05.000+0000005000000000000AAA2026-07-13T21:34:05.000+0000truefalse2026-07-13T21:34:05.000+00002026-07-13T21:34:05.000+0000
0XlHu000000HUvsKAG005000000000000AAAfalseHealth Tips and WellnessUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+0000
0XlHu000000HUvrKAG005000000000000AAAfalsePlan and Benefits UpdatesUSD2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000005000000000000AAA2026-08-29T07:14:06.000+0000truefalse2026-08-29T07:14:06.000+00002026-08-29T07:14:06.000+0000
0XlHu000000HUuXKAW005000000000000AAAfalseResearch & AdvancementsUSD2026-07-13T21:33:48.000+0000005000000000000AAA2026-07-13T21:33:48.000+0000005000000000000AAA2026-07-13T21:33:48.000+0000truefalse2026-07-13T21:33:48.000+00002026-07-13T21:33:48.000+0000
consent/contact-point-type-consent.csv1,723 rows · 26 columns

Join keys: PartyId -> contacts.IndividualId

ColumnType
Idsalesforce id
OwnerIdsalesforce id
IsDeletedboolean
Nametext
CreatedDatedatetime
CreatedByIdsalesforce id
LastModifiedDatedatetime
LastModifiedByIdsalesforce id
SystemModstampdatetime
MayEditboolean
IsLockedboolean
LastViewedDateempty
LastReferencedDateempty
PartyIdsalesforce id
ContactPointTypetext
DataUsePurposeIdempty
PrivacyConsentStatustext
EffectiveFromdatetime
EffectiveToempty
CaptureDatedatetime
CaptureContactPointTypeempty
CaptureSourcetext
DoubleConsentCaptureDateempty
EngagementChannelTypeIdsalesforce id
PartyRoleIdempty
BusinessBrandIdempty

First 20 rows

IdOwnerIdIsDeletedNameCreatedDateCreatedByIdLastModifiedDateLastModifiedByIdSystemModstampMayEditIsLockedLastViewedDateLastReferencedDatePartyIdContactPointTypeDataUsePurposeIdPrivacyConsentStatusEffectiveFromEffectiveToCaptureDateCaptureContactPointTypeCaptureSourceDoubleConsentCaptureDateEngagementChannelTypeIdPartyRoleIdBusinessBrandId
0ZYHu000000fy0cOAA005000000000000AAAFalseEmail Consent - Delacroix2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CLOA0EmailOptIn2025-10-11T00:00:00.000+00002025-10-11T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0dOAA005000000000000AAAFalseSMS Consent - Delacroix2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CLOA0PhoneNotSeen2026-04-27T00:00:00.000+00002026-04-27T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0eOAA005000000000000AAAFalseEmail Consent - Abernathy2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CMOA0EmailOptIn2025-05-10T00:00:00.000+00002025-05-10T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0fOAA005000000000000AAAFalseSMS Consent - Abernathy2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CMOA0PhoneNotSeen2025-03-23T00:00:00.000+00002025-03-23T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0gOAA005000000000000AAAFalseEmail Consent - Vasquez-Ruiz2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CNOA0EmailOptIn2026-07-16T00:00:00.000+00002026-07-16T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0hOAA005000000000000AAAFalseSMS Consent - Vasquez-Ruiz2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CNOA0PhoneOptIn2025-08-02T00:00:00.000+00002025-08-02T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0iOAA005000000000000AAAFalseEmail Consent - Halloran2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5COOA0EmailOptIn2025-11-06T00:00:00.000+00002025-11-06T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0jOAA005000000000000AAAFalseSMS Consent - Halloran2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5COOA0PhoneOptOut2026-05-03T00:00:00.000+00002026-05-03T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0kOAA005000000000000AAAFalseEmail Consent - Delacroix2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CPOA0EmailOptIn2026-02-06T00:00:00.000+00002026-02-06T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0lOAA005000000000000AAAFalseSMS Consent - Delacroix2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CPOA0PhoneNotSeen2026-02-25T00:00:00.000+00002026-02-25T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0mOAA005000000000000AAAFalseEmail Consent - Abernathy2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CQOA0EmailOptIn2025-03-21T00:00:00.000+00002025-03-21T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0nOAA005000000000000AAAFalseSMS Consent - Abernathy2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CQOA0PhoneOptIn2025-04-29T00:00:00.000+00002025-04-29T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0oOAA005000000000000AAAFalseEmail Consent - Halloran2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CROA0EmailOptIn2025-08-29T00:00:00.000+00002025-08-29T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0pOAA005000000000000AAAFalseSMS Consent - Halloran2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CROA0PhoneOptIn2026-07-26T00:00:00.000+00002026-07-26T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0qOAA005000000000000AAAFalseEmail Consent - Delacroix2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CSOA0EmailOptOut2026-05-04T00:00:00.000+00002026-05-04T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0rOAA005000000000000AAAFalseSMS Consent - Delacroix2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CSOA0PhoneOptIn2026-03-29T00:00:00.000+00002026-03-29T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0sOAA005000000000000AAAFalseEmail Consent - Abernathy2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CTOA0EmailOptIn2026-04-12T00:00:00.000+00002026-04-12T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0tOAA005000000000000AAAFalseSMS Consent - Abernathy2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CTOA0PhoneOptIn2025-10-15T00:00:00.000+00002025-10-15T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
0ZYHu000000fy0uOAA005000000000000AAAFalseEmail Consent - Castellanos2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CUOA0EmailOptOut2026-04-15T00:00:00.000+00002026-04-15T00:00:00.000+0000Preference Center0eFHu000000p5MJMAY
0ZYHu000000fy0vOAA005000000000000AAAFalseSMS Consent - Castellanos2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000005000000000000AAA2026-08-29T08:11:26.000+0000TrueFalse0PKHu000004Y5CUOA0PhoneOptOut2025-11-01T00:00:00.000+00002025-11-01T00:00:00.000+0000Preference Center0eFHu000000p5MKMAY
consent/engagement-channel-type.csv2 rows · 17 columns
ColumnType
Idsalesforce id
OwnerIdsalesforce id
IsDeletedboolean
Nametext
CurrencyIsoCodetext
CreatedDatedatetime
CreatedByIdsalesforce id
LastModifiedDatedatetime
LastModifiedByIdsalesforce id
SystemModstampdatetime
MayEditboolean
IsLockedboolean
LastViewedDatedatetime
LastReferencedDatedatetime
ContactPointTypetext
IsActiveboolean
UsageTypeempty

First 20 rows

IdOwnerIdIsDeletedNameCurrencyIsoCodeCreatedDateCreatedByIdLastModifiedDateLastModifiedByIdSystemModstampMayEditIsLockedLastViewedDateLastReferencedDateContactPointTypeIsActiveUsageType
0eFHu000000p5MJMAY005000000000000AAAfalseEmailUSD2025-11-04T06:46:15.000+0000005000000000000AAA2026-08-29T07:49:20.000+0000005000000000000AAA2026-08-29T07:49:20.000+0000truefalse2026-08-29T07:49:20.000+00002026-08-29T07:49:20.000+0000Emailtrue
0eFHu000000p5MKMAY005000000000000AAAfalseSMSUSD2025-11-04T06:46:15.000+0000005000000000000AAA2026-08-29T07:49:20.000+0000005000000000000AAA2026-08-29T07:49:20.000+0000truefalse2026-08-29T07:49:20.000+00002026-08-29T07:49:20.000+0000Phonetrue
contacts.csv890 rows · 16 columns

IndividualId is the key the 5,828 consent rows join on, via Individual.PartyId. An export that omits that one column produces consent rows that join to nothing.

Join keys: Id -> campaign-members.ContactId · IndividualId -> Individual.PartyId -> consent/comm-subscription-consent.PartyId · Email -> patients.Email__c, payer-enrichment.Email__c

ColumnType
Idsalesforce id
IndividualIdsalesforce id
FirstNametext
LastNametext
Emailtext
Phonetext
MobilePhonetext
Titletext
Departmenttext
MailingStreettext
MailingCitytext
MailingStatetext
MailingPostalCodeinteger
MailingCountrytext
LeadSourcetext
AccountIdsalesforce id

First 20 rows

IdIndividualIdFirstNameLastNameEmailPhoneMobilePhoneTitleDepartmentMailingStreetMailingCityMailingStateMailingPostalCodeMailingCountryLeadSourceAccountId
003Hu00003zvHbmIAE0PKHu000004Y5QPOA0AllisonAndrewsallison.andrews1@example.com(415) 555-0103(415) 555-0103170 Post StreetSan FranciscoCA94108US
003Hu00003zvHbnIAE0PKHu000004Y5QQOA0BrandyCampbellallison.andrews1@example.com(415) 555-0103(415) 555-0103170 Post StreetSan FranciscoCA94108US
003Hu00003zvHboIAE0PKHu000004Y5QROA0DanEllsworthallison.andrews1@example.com(415) 555-0103(415) 555-0103170 Post Street,San FranciscoCA94108US
003Hu00004BF7t2IAD0PKHu000004Y5OLOA0XavierAcmexavier.acme1@example.com(794) 555-0100(415) 555-0105Associate Technician240 E 3rd AveSan MateoCA94401USA001Hu00003vaV50IAE
003Hu00004BF7t3IAD0PKHu000004puuQOAQPaulPartnerpaul.partner1@example.com(344) 555-0101(344) 555-0100Account ExecutiveSales1 Market StSan FranciscoCA94105USSocial Media001Hu00003vaV50IAE
003Hu00004BF7t4IAD0PKHu000004puuROAQLaurenBaileylauren.bailey1@example.com(415) 555-0111(415) 555-0111SVP, TechnologyInformation Technology1 Market StSan FranciscoCA94105USMarketing Event001Hu00003vaV51IAE
003Hu00004BF7t5IAD0PKHu000004Y5OKOA0LarryBaxterlarry.baxter1@example.com+13105550100(310) 555-0101Business Development1 Market StSan FranciscoCA94105USReferral001Hu00003vaV52IAE
003Hu00004BF7t6IAD0PKHu000004Y5OMOA0SarahPhillipssarah.phillips1@example.com(794) 555-0100(317) 555-0131Account ExecutiveSales240 E 3rd AveSan MateoCalifornia94401USAData.com001Hu00003vaV50IAE
003Hu00004BF7t7IAD0PKHu000004Y5ONOA0JoyceTurnerjoyce.turner1@example.com(794) 555-0103(794) 555-0101Director of SalesSales6069 NE 49th AveLittletonCO80211USAMarketing Event001Hu00003vaV50IAE
003Hu00004BF7t8IAD0PKHu000004Y5CGOA0YvetteAcmeyvette.acme1@example.com(794) 555-0100(415) 555-0106Lead Technician240 E 3rd AveSan MateoCA94401USA001Hu00003vaV50IAE
003Hu00004BF7t9IAD0PKHu000004Y5CHOA0AdamMerceradam.mercer1@example.com(794) 555-0102(794) 555-0101Sales EngineerSales6069 NE 49th AveLittletonCO80211USACold Call001Hu00003vaV50IAE
003Hu00004BF7tAIAT0PKHu000004Y5OJOA0ChrisPostchris.post1@example.com(415) 555-0137(415) 555-0135Business AnalystIT1 Market St.San FranciscoCA94105USAReferral001Hu00003vaV51IAE
003Hu00004BF7tBIAT0PKHu000004puuSOAQMarkKingstonmark.kingston1@example.com(769) 555-0102(804) 555-0101Project ManagerEngineering12011 Government Center PkwyFairfaxVA22035USACold Call001Hu00003vaV51IAE
003Hu00004BF7tCIAT0PKHu000004puuTOAQJamesWujames.wu1@example.com(274) 555-0100VP of SalesSales1 Market StSan FranciscoCA94105USData.com001Hu00003vaV51IAE
003Hu00004BF7tDIAT0PKHu000004puuUOAQBobHodgesbob.hodges1@example.com(422) 555-0101(422) 555-0100President and CEOCEO2725 Quarry RdMontgomeryPA19009USACold Call001Hu00003vaV51IAE
003Hu00004BF7tEIAT0PKHu000004puuVOAQWesChoprawes.chopra1@example.com(847) 555-0102(310) 555-0102Manager, Information TechnologyIT2110 N Rock RdWichitaKS67208USACold Call001Hu00003vaV53IAE
003Hu00004BF7tFIAT0PKHu000004puuWOAQAndreaBowdenandrea.bowden1@example.com(655) 555-0102(655) 555-0101Senior Vice PresidentSales100 L StreetBostonMassachusetts02051United StatesData.com001Hu00003vaV54IAE
003Hu00004BF7tGIAT0PKHu000004Y5QTOA0StewartAnderson(317) 555-0185Principal NextGen Developer001Hu00003vaV55IAE
003Hu00004BF7tHIAT0PKHu000004Y5QAOA0AidenPearsonaiden.pearson1@example.com(415) 555-0153(415) 555-0154OwnerCEO50 Fremont StreetSan FranciscoCA94105USASocial Media001Hu00003vaV56IAE
003Hu00004BF7tIIAT0PKHu000004Y5QBOA0BradAnastasiobrad.anastasio1@example.com(415) 555-0157SVP, SalesSales800 3rd StreetSan FranciscoCA94105USASocial Media001Hu00003vaV57IAE
message-registry.csv27 rows · 21 columns

Join keys: cld_Campaign_Id__c -> campaigns.Id · cld_Channel_Type_Id__c -> consent/comm-subscription-channel-type.Id

ColumnType
Idsalesforce id
Nametext
cld_Message_Id__ctext
cld_Campaign_Id__csalesforce id
cld_Message_Name__ctext
cld_Subject__ctext
cld_Channel_Type_Id__csalesforce id
cld_Scheduled_Date__cdatetime
cld_Variant__ctext
cld_Channel__ctext
cld_Campaign__csalesforce id
cld_Content_Id__csalesforce id
cld_Preview_Subject__ctext
cld_Preview_Preheader__ctext
cld_Preview_Body__ctext
cld_Variant_Id__csalesforce id
cld_Preview_Headline__ctext
cld_Preview_Image_URL__ctext
cld_Preview_Cta_Label__ctext
cld_Preview_Cta_Url__ctext
cld_Preview_Bullets__ctext

First 20 rows

IdNamecld_Message_Id__ccld_Campaign_Id__ccld_Message_Name__ccld_Subject__ccld_Channel_Type_Id__ccld_Scheduled_Date__ccld_Variant__ccld_Channel__ccld_Campaign__ccld_Content_Id__ccld_Preview_Subject__ccld_Preview_Preheader__ccld_Preview_Body__ccld_Variant_Id__ccld_Preview_Headline__ccld_Preview_Image_URL__ccld_Preview_Cta_Label__ccld_Preview_Cta_Url__ccld_Preview_Bullets__c
a6mHu0000006CcsIAEMB-0009cld-six-age_in-em-a701Hu000002dAmVIAUcld_Age-In - Email ATurning 65? Know your Medicare costs up front0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email AEMAIL701Hu000002dAmVIAU20YHu00000BIkItMALTurning 65? Know your Medicare costs up frontPlans with $0 monthly premiums and built-in drug coverage are available in your area.Hi {!$recipient.FirstName}, your 65th birthday is coming up, and with it your first Medicare choices. Makana Health Plans offers Medicare Advantage plans with predictable monthly premiums, $0 premium options in many areas, and prescription drug coverage built in. Compare them side by side and see what you would pay before you decide.9PsHu00000kkFLkKAMMedicare costs you can plan for, month to monthhttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETCompare my Medicare costshttps://your-demo-site.example.com/makana/plans/medicare/compare?utm_source=email&utm_medium=owned&utm_campaign=cld_payer_age_in&utm_content=email_aYour enrollment window. It opens three months before your birthday month and closes three months after. Whether a $0 monthly premium plan is available where you live. Whether your prescriptions are covered, and what you would pay at the pharmacy.
a6mHu0000006CctIAEMB-0010cld-six-age_in-em-b701Hu000002dAmVIAUcld_Age-In - Email BTurning 65? Keep the doctors you trust0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email BEMAIL701Hu000002dAmVIAU20YHu00000BIkIyMALTurning 65? Keep the doctors you trustSee whether your primary care doctor and specialists are in the Makana network.Hi {!$recipient.FirstName}, turning 65 does not have to mean starting over with a new care team. Makana Health Plans Medicare Advantage plans include a broad network of primary care doctors and specialists. Search by name to confirm your doctors are in network, then compare the plans that keep your care where it is today.9PsHu00000kkFLpKAMKeep your doctors when you move to Medicarehttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETCheck if my doctors are in networkhttps://your-demo-site.example.com/makana/plans/medicare/compare?utm_source=email&utm_medium=owned&utm_campaign=cld_payer_age_in&utm_content=email_bWhether your primary care doctor is in the network of the plan you are considering. Whether the specialists you see today, and the hospital they use, are in network too. Whether you need a referral to see a specialist, and how that works in each plan.
a6mHu0000006CcuIAEMB-0011cld-six-age_in-sms701Hu000002dAmVIAUcld_Age-In - SMSMakana Health Plans: compare Medicare plans0eBHu00000096wmMAA2026-08-09T19:00:21.000+0000SMSSMS701Hu000002dAmVIAU20YHu00000BIkJ3MALMakana Health Plans: compare Medicare plansMakana Health Plans: $0 premium Medicare plans https://your-demo-site.example.com/makana/plans/medicare/compare?src=cld_age_in_sms Reply STOP to opt out.9PsHu00000kkFLuKAM
a6mHu0000006CcvIAEMB-0012cld-six-cahps-em-a701Hu000002dAmWIAUcld_CAHPS - Email AYour wellness visit is free with your plan0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email AEMAIL701Hu000002dAmWIAU20YHu00000BIkJ8MALYour wellness visit is free with your planIt takes about 45 minutes, and your doctor reviews your screenings and prescriptions in one sitting.Hi {!$recipient.FirstName}, your Annual Wellness Visit is included with your Makana Health Plans coverage at no cost to you. It takes about 45 minutes. Your doctor goes over the screenings you are due for, looks at every prescription you take, and builds a simple prevention plan for the year ahead. It is the one appointment that keeps the rest of your care on track.9PsHu00000kkFLzKAMOne visit a year, no cost to youhttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETSchedule my wellness visithttps://your-demo-site.example.com/makana/appointments/annual-wellness?utm_source=email&utm_medium=owned&utm_campaign=cld_payer_cahps&utm_content=email_aThe screenings you are due for this year, such as blood pressure, cholesterol, colon cancer, and diabetes checks. A review of every prescription you take, including over-the-counter medicines, to catch anything that no longer fits. A written prevention plan for the year, with the vaccines, tests, and follow-ups your doctor recommends.
a6mHu0000006CcwIAEMB-0013cld-six-cahps-em-b701Hu000002dAmWIAUcld_CAHPS - Email BThe visit that unlocks your extra benefits0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email BEMAIL701Hu000002dAmWIAU20YHu00000BIkJDMA1The visit that unlocks your extra benefitsYour OTC allowance, fitness membership, and rides to appointments are already included. Here is how to start using them.Hi {!$recipient.FirstName}, your Makana Health Plans coverage comes with extras that many members never touch: a quarterly over-the-counter allowance, a fitness membership, and rides to medical appointments. Your free Annual Wellness Visit is the easiest place to start. It takes about 45 minutes, and your doctor can point you to the benefits that fit your health. Each completed visit also helps keep the plan's quality rating high, which helps keep premiums low for everyone.9PsHu00000kkFM4KAMYour plan includes more than you are usinghttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETBook my wellness visithttps://your-demo-site.example.com/makana/appointments/annual-wellness?utm_source=email&utm_medium=owned&utm_campaign=cld_payer_cahps&utm_content=email_bYour over-the-counter allowance. A set amount each quarter for items like pain relievers, vitamins, and first aid supplies. Your fitness membership. Access to participating gyms and home fitness programs at no added cost. Your transportation benefit. Rides to and from medical appointments, including your wellness visit.
a6mHu0000006CcxIAEMB-0014cld-six-cahps-sms701Hu000002dAmWIAUcld_CAHPS - SMSMakana Health Plans: book your free wellness visit0eBHu00000096wmMAA2026-08-09T19:00:21.000+0000SMSSMS701Hu000002dAmWIAU20YHu00000BIkJIMA1Makana Health Plans: book your free wellness visitMakana Health Plans: Free wellness visit. https://your-demo-site.example.com/makana/appointments/annual-wellness?src=cld_cahps_sms Reply STOP to opt out.9PsHu00000kkFM9KAM
a6mHu0000006Cd4IAEMB-0021cld-six-flu_shot-em-a701Hu000002dAmZIAUcld_Flu Shot - Email AA flu shot now protects everyone at home0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email AEMAIL701Hu000002dAmZIAU20YHu00000BIkJrMALA flu shot now protects everyone at homeFlu usually spreads at home first. One quick visit covers you, and kids 6 months and up can get theirs at the same time.Hi {!$recipient.FirstName}, flu tends to spread at home before anywhere else. Getting your shot now means you are less likely to bring it back to the people you live with. Most plans cover the flu shot at no cost, and if you have kids 6 months or older, they can get theirs at the same visit. Pick a time that works for your family and we will take care of the rest.9PsHu00000kkFMiKAMProtect the people you live withhttps://your-demo-site.example.com/images/service-line/family_medicine-7653083.jpgSchedule our flu shotshttps://your-demo-site.example.com/makana/appointments/flu-shot?utm_source=email&utm_medium=owned&utm_campaign=cld_provider_flu&utm_content=email_aIt protects your household. Flu spreads fastest between people who share a home, so one shot helps everyone under your roof. It is covered at no cost by most plans. Bring your insurance card and there is usually nothing to pay. Kids 6 months and up can get theirs at the same visit. Book one appointment and bring the whole family.
a6mHu0000006Cd5IAEMB-0022cld-six-flu_shot-em-b701Hu000002dAmZIAUcld_Flu Shot - Email BWalk in for your flu shot, no appointment needed0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email BEMAIL701Hu000002dAmZIAU20YHu00000BIkIuMALWalk in for your flu shot, no appointment neededEvery Makana clinic and partner pharmacy takes walk-ins through November. It takes about 10 minutes.Hi {!$recipient.FirstName}, getting your flu shot does not need to take a spot on your calendar. Every Makana Health clinic and partner pharmacy takes walk-ins through November, and the visit itself takes about 10 minutes. Just bring your insurance card. Evening hours are listed on the page below so you can stop by after work if that is easier.9PsHu00000kkFLlKAMWalk in this week, no appointment neededhttps://your-demo-site.example.com/images/service-line/urgent_care-8460229.jpgSee walk-in hours near mehttps://your-demo-site.example.com/makana/appointments/flu-shot?utm_source=email&utm_medium=owned&utm_campaign=cld_provider_flu&utm_content=email_bWalk into any Makana clinic. No appointment needed through November, and the shot takes about 10 minutes. Stop by a partner pharmacy. They take walk-ins too, so you can pair it with an errand you are already running. Come in the evening. Evening hours are listed on the page, and bringing your insurance card is all you need to do.
a6mHu0000006Cd6IAEMB-0023cld-six-flu_shot-sms701Hu000002dAmZIAUcld_Flu Shot - SMSMakana Health: walk in for a flu shot0eBHu00000096wmMAA2026-08-09T19:00:21.000+0000SMSSMS701Hu000002dAmZIAU20YHu00000BIkJwMALMakana Health: Flu shots are in. Walk in today. https://your-demo-site.example.com/makana/appointments/flu-shot?src=cld_flu_sms Reply STOP to opt out.9PsHu00000kkFMnKAM
a6mHu0000006CcyIAEMB-0015cld-six-mail_order-em-a701Hu000002dAmXIAUcld_Mail Order - Email AYour refills, delivered before you run out0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email AEMAIL701Hu000002dAmXIAU20YHu00000BIkJNMA1Your refills, delivered before you run outMail order sends a 90-day supply to your door and refills it automatically, so you never have to remember.Hi {!$recipient.FirstName}, with Makana Health Plans mail order pharmacy, a 90-day supply of the medicines you take every day arrives at your door. Refills are set up automatically, so you do not have to call the pharmacy or watch the bottle. And if you have a question about a medicine, a Makana pharmacist is one phone call away.9PsHu00000kkFMEKA2Never miss a refill againhttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETSwitch to mail orderhttps://your-demo-site.example.com/makana/pharmacy/mail-order?utm_source=email&utm_medium=owned&utm_campaign=cld_payer_mail_order&utm_content=email_aTrips to the pharmacy. A 90-day supply ships to your home with free standard shipping, so you fill each medicine about four times a year instead of every month. Remembering to refill. Automatic refills go out before you run low, and you get a text or email when each order ships. Waiting for answers. Call a Makana pharmacist with a question about a dose, a side effect, or how your medicines work together.
a6mHu0000006CczIAEMB-0016cld-six-mail_order-em-b701Hu000002dAmXIAUcld_Mail Order - Email BA 90-day supply costs less than three refills0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email BEMAIL701Hu000002dAmXIAU20YHu00000BIkJSMA1A 90-day supply costs less than three refillsOn most Makana plans, one 90-day mail order copay is less than three 30-day copays at the counter, and shipping is free.Hi {!$recipient.FirstName}, if you take a medicine every day, mail order is usually the lower-cost way to fill it. On most Makana Health Plans, one 90-day supply copay is less than three 30-day copays for the same medicine. Shipping is free, and the order comes to your door, so you skip a trip to the pharmacy every month.9PsHu00000kkFMJKA2Pay less for the same prescriptionshttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETSee my mail order savingshttps://your-demo-site.example.com/makana/pharmacy/mail-order?utm_source=email&utm_medium=owned&utm_campaign=cld_payer_mail_order&utm_content=email_bLower copays. One 90-day copay is less than three 30-day copays on most Makana plans. Check your plan documents or call us for your exact amount. Free shipping. Standard shipping to your home is included with every order, with no minimum. One fewer trip. No gas, no parking, no waiting in line. Your medicines arrive at home and you keep your afternoon.
a6mHu0000006Cd0IAEMB-0017cld-six-mail_order-sms701Hu000002dAmXIAUcld_Mail Order - SMSMakana Health Plans: 90-day refills delivered0eBHu00000096wmMAA2026-08-09T19:00:21.000+0000SMSSMS701Hu000002dAmXIAU20YHu00000BIkJXMA1Makana Health Plans: 90-day refills deliveredMakana Health Plans: Refills, delivered. https://your-demo-site.example.com/makana/pharmacy/mail-order?src=cld_mailorder_sms Reply STOP to opt out.9PsHu00000kkFMOKA2
a6mHu0000006Cd1IAEMB-0018cld-six-mammography-em-a701Hu000002dAmYIAUcld_Mammography - Email AYour mammogram takes less than 20 minutes0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email AEMAIL701Hu000002dAmYIAU20YHu00000BIkJcMALYour mammogram takes less than 20 minutesNo referral needed, results in a few days, and evening and Saturday slots open in October.Hi {!$recipient.FirstName}, our records show you are due for a screening mammogram. Most screenings at Makana Health take under 20 minutes, and results are usually ready in a few days. You do not need a referral to book. In October we are adding evening and Saturday appointments at our imaging locations, so you can choose a time that fits your week.9PsHu00000kkFMTKA2A quick screening, on your schedulehttps://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETBook my mammogramhttps://your-demo-site.example.com/makana/appointments/mammography?utm_source=email&utm_medium=owned&utm_campaign=cld_provider_mammography&utm_content=email_aPlan for about 20 minutes. Most screening mammograms are finished in that time, from check-in to done. Skip deodorant, lotion, or powder on the day of your visit. They can show up on the images and lead to a repeat picture. Results usually arrive in a few days through your Makana patient portal, and your care team will call if anything needs a closer look.
a6mHu0000006Cd2IAEMB-0019cld-six-mammography-em-b701Hu000002dAmYIAUcld_Mammography - Email BOctober is here, and your screening is due0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email BEMAIL701Hu000002dAmYIAU20YHu00000BIkJhMALOctober is here, and your screening is dueBreast Cancer Awareness Month is a good time to book. Extra October appointments are open now.Hi {!$recipient.FirstName}, October is Breast Cancer Awareness Month, and our records show you are due for a screening mammogram. Screening can find changes years before symptoms appear, when treatment is simpler and more effective. We have opened extra October appointments, including evenings and Saturdays, so booking this month is easy.9PsHu00000kkFMYKA2This month, make time for your mammogramhttps://your-demo-site.example.com/images/service-line/womens_imaging-screening.jpgBook my October screeninghttps://your-demo-site.example.com/makana/appointments/mammography?utm_source=email&utm_medium=owned&utm_campaign=cld_provider_mammography&utm_content=email_bYou are due. Regular screening is the most reliable way to find changes early, when treatment is simplest. Screening mammograms can find changes years before you would notice a lump or any other symptom. Extra October appointments are open now, including evenings and Saturdays, and no referral is needed.
a6mHu0000006Cd3IAEMB-0020cld-six-mammography-sms701Hu000002dAmYIAUcld_Mammography - SMSMakana Health: schedule your mammogram0eBHu00000096wmMAA2026-08-09T19:00:21.000+0000SMSSMS701Hu000002dAmYIAU20YHu00000BIkJmMALMakana Health: Mammogram due. Book today. https://your-demo-site.example.com/makana/appointments/mammography?src=cld_mammo_sms Reply STOP to opt out.9PsHu00000kkFMdKAM
a6mHu0000006Cd7IAEMB-0024cld-six-primary_care-em-a701Hu000002dAmaIAEcld_Primary Care - Email AMeet a primary care provider who knows you0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email AEMAIL701Hu000002dAmaIAE20YHu00000BIkK1MALMeet a primary care provider who knows youYou visited us once. A primary care provider who knows your history catches things sooner, and same-week new-patient slots are open now.Hi {!$recipient.FirstName}, you visited us once, and we would love to see you again. A primary care provider who knows your history catches things sooner and helps you stay ahead of them. Choose a provider by location, language and availability, then pick a time that fits your week. Same-week new-patient slots are open now.9PsHu00000kkFMsKAMMeet your care teamhttps://your-demo-site.example.com/images/service-line/primary_care-5214997.jpgChoose my providerhttps://your-demo-site.example.com/makana/appointments/primary-care?utm_source=email&utm_medium=owned&utm_campaign=cld_provider_primary_care&utm_content=email_aKnows your history. One provider who sees the whole picture notices changes early and catches things sooner. Keeps your care connected. When you need a specialist, a test or a referral, your provider coordinates it so nothing falls through the cracks. Fits your life. Choose by location, language and availability, with same-week new-patient slots ready to book.
a6mHu0000006Cd8IAEMB-0025cld-six-primary_care-em-b701Hu000002dAmaIAEcld_Primary Care - Email BWhat to expect at your first visit0eBHu00000096wlMAA2026-08-06T19:00:21.000+0000Email BEMAIL701Hu000002dAmaIAE20YHu00000BIkK6MALWhat to expect at your first visitAbout 40 minutes, a review of your health history and medications, and a plan you agree on together.Hi {!$recipient.FirstName}, here is what happens at your first primary care visit. Plan on about 40 minutes. Your provider will review your health history and medications, talk through what matters to you, and build a plan you agree on together. Afterward, your results and messages are waiting for you in the patient portal. Bring your medication list and insurance card and we will take care of the rest.9PsHu00000kkFMxKAMYour first visit, step by stephttps://your-demo-site.example.com/images/health-plan/care_management-7446754.jpgBook my first visithttps://your-demo-site.example.com/makana/appointments/primary-care?utm_source=email&utm_medium=owned&utm_campaign=cld_provider_primary_care&utm_content=email_bYour medication list. Include prescriptions, over-the-counter medicines and supplements so your provider sees the full picture. Your insurance card. It lets us check your coverage before you arrive so there are no surprises at the front desk. Your questions. Anything you have been wondering about is worth raising, and your provider will make time for it.
a6mHu0000006Cd9IAEMB-0026cld-six-primary_care-sms701Hu000002dAmaIAEcld_Primary Care - SMSMakana Health: choose your primary care provider0eBHu00000096wmMAA2026-08-09T19:00:21.000+0000SMSSMS701Hu000002dAmaIAE20YHu00000BIkKBMA1Makana Health: Meet your primary care team. https://your-demo-site.example.com/makana/appointments/primary-care?src=cld_pcp_sms Reply STOP to opt out.9PsHu00000kkFN2KAM
a6mHu0000006CckIAEMB-0001cld-wb27-em-a701Hu000002dAmQIAUcld_2027 Win-Back Email A - Plan ValueYour 2027 plan options are ready, Makana Health0eBHu00000096wlMAA2026-08-12T15:00:00.000+0000Email A - Plan ValueEMAIL701Hu000002dAmQIAU20YHu00000BIkFgMALYour 2027 plan: enroll by Dec 7Compare plans, keep your doctors, and re-enroll in about five minutes.Hi {!$recipient.FirstName}, your 2027 Makana Health Plans options are published. Premiums, your doctor network, and prescription coverage are all in one place. Re-enrolling takes about five minutes.9PsHu00000kkFISKA2Your 2027 plan is ready. Enroll by December 7.https://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETSee my 2027 plan optionshttps://YOUR_ORG.my.site.com/PLACEHOLDER_LANDING_PAGEWhether your current doctors are still in network. Whether your prescriptions are on the 2027 formulary. Whether a $0 monthly premium plan is available where you live.
a6mHu0000006CclIAEMB-0002cld-wb27-em-b701Hu000002dAmQIAUcld_2027 Win-Back Email B - Care ContinuityKeep your care team for 20270eBHu00000096wlMAA2026-08-12T15:00:00.000+0000Email B - Care ContinuityEMAIL701Hu000002dAmQIAU20YHu00000BIkFhMAL$0 primary care is back for 2027Plus dental, vision, and a $0 monthly premium on select Makana plans.Hi {!$recipient.FirstName}, select Makana Health Plans now include $0 primary care visits, dental and vision coverage, and a $0 monthly premium. Your benefits are still here whenever you want to use them.9PsHu00000kkFITKA2$0 primary care visits are back for 2027.https://YOUR_ORG.lightning.force.com/PLACEHOLDER_ASSETSee what my plan covershttps://YOUR_ORG.my.site.com/PLACEHOLDER_LANDING_PAGE$0 primary care visits and $0 monthly premium. Dental, vision, and hearing coverage. A fitness benefit and rides to your appointments.
patients.csv640 rows · 74 columns

Join keys: Email__c -> contacts.Email · Id -> appointments.Patient__c

ColumnType
Idsalesforce id
Namesalesforce id
Number_Attribute_7__cdecimal
Number_Attribute_10__cdecimal
Boolean_Attributes_7__cinteger
Department__ctext
Date_Attribute_2__cdate
Text_Attribute_2__cempty
Boolean_Attributes_4__cinteger
Clinic_Location__ctext
emergency_contact_name__ctext
Email__ctext
Text_Attribute_6__cempty
vaccination_status__cinteger
payment_status__ctext
diagnosis__ctext
medications__ctext
Number_Attribute_6__cdecimal
Last_Name__ctext
insurance_provider__ctext
Boolean_Attributes_10__cinteger
Boolean_Attributes_3__cinteger
Date_Attribute_3__cdate
Text_Attribute_1__cempty
Number_Attribute_1__cdecimal
Text_Attribute_10__cempty
Text_Attribute_9__cempty
Cancellation_Reason__cempty
Text_Attribute_5__cempty
Patient_MemberID__cinteger
primary_care_physician__ctext
Number_Attribute_9__cdecimal
Boolean_Attributes_9__cinteger
Number_Attribute_5__cdecimal
Rescheduled_Date__cempty
Virtual_Appointment_Opt_In__cinteger
insurance_policy_number__cinteger
Clinic_ID__cinteger
Number_Attribute_2__cdecimal
Boolean_Attributes_6__cinteger
Boolean_Attributes_2__cinteger
emergency_contact_phone__ctext
emergency_contact_relationship__ctext
Text_Attribute_8__cempty
Appointment_Date__cdate
Date_Attribute_4__cdate
Text_Attribute_4__cempty
Appointment_Type__ctext
procedure_code__ctext
Provider_Name__ctext
Number_Attribute_8__cdecimal
First_Name__ctext
payment_due_date__cdate
Number_Attribute_4__cdecimal
Appointment_Time__cdecimal
Boolean_Attributes_8__cinteger
Appointment_ID__cinteger
Social_History__ctext
No_Show_Reason__cempty
Number_Attribute_3__cdecimal
Boolean_Attributes_5__cinteger
Boolean_Attributes_1__cinteger
Text_Attribute_7__cempty
Appointment_Reason__cempty
Date_Attribute_5__cdate
Text_Attribute_3__cempty
Date_Attribute_1__cdate
Gender__ctext
Zip__cinteger
City__ctext
State__ctext
Provider_Key__ctext
PCP_Key__ctext
Service_Line__ctext

First 20 rows

IdNameNumber_Attribute_7__cNumber_Attribute_10__cBoolean_Attributes_7__cDepartment__cDate_Attribute_2__cText_Attribute_2__cBoolean_Attributes_4__cClinic_Location__cemergency_contact_name__cEmail__cText_Attribute_6__cvaccination_status__cpayment_status__cdiagnosis__cmedications__cNumber_Attribute_6__cLast_Name__cinsurance_provider__cBoolean_Attributes_10__cBoolean_Attributes_3__cDate_Attribute_3__cText_Attribute_1__cNumber_Attribute_1__cText_Attribute_10__cText_Attribute_9__cCancellation_Reason__cText_Attribute_5__cPatient_MemberID__cprimary_care_physician__cNumber_Attribute_9__cBoolean_Attributes_9__cNumber_Attribute_5__cRescheduled_Date__cVirtual_Appointment_Opt_In__cinsurance_policy_number__cClinic_ID__cNumber_Attribute_2__cBoolean_Attributes_6__cBoolean_Attributes_2__cemergency_contact_phone__cemergency_contact_relationship__cText_Attribute_8__cAppointment_Date__cDate_Attribute_4__cText_Attribute_4__cAppointment_Type__cprocedure_code__cProvider_Name__cNumber_Attribute_8__cFirst_Name__cpayment_due_date__cNumber_Attribute_4__cAppointment_Time__cBoolean_Attributes_8__cAppointment_ID__cSocial_History__cNo_Show_Reason__cNumber_Attribute_3__cBoolean_Attributes_5__cBoolean_Attributes_1__cText_Attribute_7__cAppointment_Reason__cDate_Attribute_5__cText_Attribute_3__cDate_Attribute_1__cGender__cZip__cCity__cState__cProvider_Key__cPCP_Key__cService_Line__c
a2uHu000009v142IAAa2uHu000009v1421.731.730Women's Health1968-12-140Makana - ChicagoRenee Salyermegan.salyer1@example.com1PendingNoneAspirin1.73SalyerUnited Healthcare001968-12-141.731Dr. Priya Castellanos1.7301.731714563142741.7300589-555-0100Spouse2028-10-031968-12-14Follow Up Visit0DW6X2ZDr. Priya Okonkwo1.73Megan2028-10-031.730.709234265303285Smoke1.73001968-12-141968-12-14Female60602ChicagoILPRV-012PRV-017Women's Health
a2uHu000009v143IAAa2uHu000009v1430.640.641Primary Care1964-03-201Makana - ChicagoRenee Jironbecky.jiron1@example.com1PaidDiabetesAntibiotics0.64JironCigna111964-03-200.642Dr. Amara Ferraro0.6410.640801866344540.6411904-555-0102Spouse2028-01-141964-03-20Initial Visit02UW38ZDr. Amara Ferraro0.64Becky2028-01-140.640.399986547614733Drink0.64111964-03-201964-03-20Female60603ChicagoILPRV-009PRV-009Primary Care
a2uHu000009v144IAAa2uHu000009v1448.388.380Otolaryngology (ENT)1997-11-060Makana - ChicagoRenee Walshkevin.walsh1@example.com0PaidHypertensionAspirin8.38WalshMedicare Advantage001997-11-068.383Dr. Priya Castellanos8.3808.381903861368748.3800850-555-0102Spouse2030-07-151997-11-06Follow Up VisitB932Y0ZDr. Priya Nakamura8.38Kevin2030-07-158.380.8993013605694Drink8.38001997-11-061997-11-06Male60607ChicagoILPRV-015PRV-017Sensory & Skin
a2uHu000009v145IAAa2uHu000009v1455.785.781Internal Medicine2005-06-031Makana - ChicagoRenee Contrarasmatt.contraras1@example.com0PaidAsthmaAntibiotics5.78ContrarasMedicaid112005-06-035.784Dr. Amara Ferraro5.7815.781987855670945.7811330-555-0100Sibling2024-07-142005-06-03Initial Visit0MMP4ZZDr. Amara Ferraro5.78Matt2024-07-145.780.637274358110195Drink5.78112005-06-032005-06-03Male60601ChicagoILPRV-009PRV-009Primary Care
a2uHu000009v146IAAa2uHu000009v1469.119.110Allergy1995-06-010Makana - Houston Medical CenterRenee Moellerjess.moeller1@example.com0PendingHypertensionAntibiotics9.11MoellerMedicaid001995-06-019.115Dr. Nadia Thibodeaux9.1109.110343181407789.1100852-555-0101Parent2023-03-301995-06-01Follow Up Visit0QTP0ZZDr. Nadia Ferraro9.11Jess2023-03-309.110.839217777809153Smoke9.11001995-06-011995-06-01Female77004HoustonTXPRV-105PRV-107Sensory & Skin
a2uHu000009v147IAAa2uHu000009v1471.261.260Primary Care1949-12-010Makana - HartfordRenee Riverareggie.jackson1@example.com0PendingDiabetesAspirin1.26JacksonCigna001949-12-011.266Dr. Camille Nakamura1.2601.260101509228771.2600165-555-0100Guardian2026-03-291949-12-01Initial Visit0B547ZZDr. Camille Nakamura1.26Reggie2026-03-291.260.517617186601807Drink1.26001949-12-011949-12-01Male06106HartfordCTPRV-135PRV-135Primary Care
a2uHu000009v148IAAa2uHu000009v1483.313.311Hematology1991-09-101Makana - HartfordRenee Connersmary.conners1@example.com0PaidHypertensionAspirin3.31ConnersCigna111991-09-103.317Dr. Camille Thibodeaux3.3113.311716467558173.3111543-555-0100Sibling2030-09-211991-09-10Initial Visit09BM4ZXDr. Camille Castellanos3.31Mary2030-09-213.310.1798011614110844Marijuana3.31111991-09-101991-09-10Female06112HartfordCTPRV-137PRV-143Oncology & Hematology
a2uHu000009v149IAAa2uHu000009v1490.030.030Infectious Disease1954-04-200Makana - HartfordVincent Horstadan.horst1@example.com0PaidAsthmaAspirin0.03HorstCigna001954-04-200.038Dr. Camille Nakamura0.0300.031996561233870.0300104-555-0100Spouse2027-04-261954-04-20Follow Up Visit0TC74ZZDr. Camille Halloran0.03Adan2027-04-260.030.9157862301099440.03001954-04-201954-04-20Male06103HartfordCTPRV-142PRV-135Diagnostics & Rehab
a2uHu000009v14AIAQa2uHu000009v14A9.859.850Primary Care1968-06-070Makana - HartfordVincent Macleangeorge.maclean1@example.com1OverdueAsthmaInsulin9.85MacleanCigna001968-06-079.859Dr. Camille Thibodeaux9.8509.850357067838079.8500263-555-0101Parent2025-03-301968-06-07Follow Up Visit0D9A70ZDr. Camille Thibodeaux9.85George2025-03-309.850.940785158016289.85001968-06-071968-06-07Male06105HartfordCTPRV-143PRV-143Primary Care
a2uHu000009v14BIAQa2uHu000009v14B5.925.921Otolaryngology (ENT)1969-06-081Makana - HartfordEvelyn Whitakerrafael.stevenson1@example.com0OverdueAsthmaInsulin5.92StevensonCigna111969-06-085.9210Dr. Camille Thibodeaux5.9215.921437393958775.9211229-555-0102Guardian2028-07-251969-06-08Follow Up Visit03QV4ZZDr. Camille Ferraro5.92Rafael2028-07-255.920.138675107414831Marijuana5.92111969-06-081969-06-08Male06112HartfordCTPRV-141PRV-143Sensory & Skin
a2uHu000009v14CIAQa2uHu000009v14C6.256.251Oncology1993-03-141Makana - DenverCarl Mcewanstacy.mcewan1@example.com0PendingHypertensionAntibiotics6.25McewanBlue Cross Blue Shield111993-03-146.2511Dr. Theo Ferraro6.2516.251871133165766.2511202-555-0100Spouse2027-04-041993-03-14Follow Up VisitB2151ZZDr. Theo Thibodeaux6.25Stacy2027-04-046.250.87950838911104716.25111993-03-141993-03-14Female80202DenverCOPRV-119PRV-117Oncology & Hematology
a2uHu000009v14DIAQa2uHu000009v14D5.695.690Allergy2005-10-160Makana - Los AngelesCarl Kriegarjeff.kriegar1@example.com0PaidHypertensionInsulin5.69KriegarMedicare Advantage002005-10-165.6912Dr. Marcus Thibodeaux5.6905.6908515429905135.6900581-555-0101Spouse2026-09-082005-10-16Initial Visit0RQBXZZDr. Marcus Ferraro5.69Jeff2026-09-085.690.062079561708620Drink5.69002005-10-162005-10-16Male90017Los AngelesCAPRV-033PRV-035Sensory & Skin
a2uHu000009v14EIAQa2uHu000009v14E4.264.261Family Medicine1957-11-121Makana - ChicagoCarl Kewogeorge.kewo1@example.com1PaidHypertensionAspirin4.26KewoUnited Healthcare111957-11-124.2613Dr. Amara Ferraro4.2614.260839030561944.2611515-555-0100Spouse2026-04-291957-11-12Annual Physical0P5D0ZZDr. Amara Ferraro4.26George2026-04-294.260.252393673614074.26111957-11-121957-11-12Male60603ChicagoILPRV-009PRV-009Primary Care
a2uHu000009v14FIAQa2uHu000009v14F7.887.881Anesthesiology1994-09-301Makana - Los AngelesCarl Rodmanjeramy.rodman1@example.com1PaidHypertensionInsulin7.88RodmanAetna111994-09-307.8814Dr. Marcus Thibodeaux7.8817.8815813779748137.8811493-555-0101Sibling2028-06-021994-09-30Initial Visit30250M0Dr. Marcus Delacroix7.88Jeramy2028-06-027.880.889753169119642Marijuana7.88111994-09-301994-09-30Male90064Los AngelesCAPRV-031PRV-035Surgical & Procedural
a2uHu000009v14GIAQa2uHu000009v14G5.785.780Oncology1970-08-230Makana - ChicagoCarl Slaydenkatherine.slayden1@example.com0PaidDiabetesAspirin5.78SlaydenMedicaid001970-08-235.7815Dr. Amara Ferraro5.7805.781159279801245.7800206-555-0138Sibling2027-04-081970-08-23Follow Up Visit0JN93ZZDr. Amara Thibodeaux5.78Katherine2027-04-085.780.04882267485092265.78001970-08-231970-08-23Female60601ChicagoILPRV-011PRV-009Oncology & Hematology
a2uHu000009v14HIAQa2uHu000009v14H7.727.721Hematology1989-03-201Makana - Dallas Medical CenterCarl Lawhonbradford.lawhon1@example.com0PaidHypertensionAspirin7.72LawhonAetna111989-03-207.7216Dr. Andre Castellanos7.7217.720536643123557.7211601-555-0102Sibling2029-12-131989-03-20Initial VisitF01L6ZZDr. Simone Thibodeaux7.72Bradford2029-12-137.720.05707258644147547.72111989-03-201989-03-20Male75204DallasTXPRV-083PRV-089Oncology & Hematology
a2uHu000009v14IIAQa2uHu000009v14I0.290.291Behavioral Medicine1947-07-221Makana - Main CampusCarl Steptoeshannon.steptoe1@example.com1PendingDiabetesAspirin0.29SteptoeUnited Healthcare111947-07-220.2917Dr. Elena Okonkwo0.2910.2913262321666180.2911604-555-0100Sibling2028-01-201947-07-22Initial Visit0TCB3ZZDr. Elena Castellanos0.29Shannon2028-01-200.290.09124366503161770.29111947-07-221947-07-22Female46224IndianapolisINPRV-041PRV-036Neuro & Behavioral
a2uHu000009v14JIAQa2uHu000009v14J7.927.920Gastroenterology1979-04-190Makana - Greater IndianapolisPriscilla Towlesbrennan.towles1@example.com0PaidDiabetesAspirin7.92TowlesMedicare Advantage001979-04-197.9218Dr. Amara Mbeki7.9207.921289743600997.9200539-555-0103Sibling2023-02-061979-04-19Follow Up Visit0P9V3ZZDr. Amara Abernathy7.92Brennan2023-02-067.920.4821277985061417.92001979-04-191979-04-19Male46205IndianapolisINPRV-004PRV-008Surgical & Procedural
a2uHu000009v14KIAQa2uHu000009v14K2.332.331Internal Medicine1995-02-081Makana - New MexicoPriscilla Larrylarry.larry1@example.com0OverdueAsthmaInsulin2.33LarryMedicaid111995-02-082.3319Dr. Rohan Nakamura2.3312.330329950856912.3311982-555-0100Parent2024-08-091995-02-08Follow Up Visit0RH00BZDr. Rohan Nakamura2.33Larry2024-08-092.330.212975920814203Smoke2.33111995-02-081995-02-08Male87102AlbuquerqueNMPRV-063PRV-063Primary Care
a2uHu000009v14LIAQa2uHu000009v14L3.253.250Pain Management1982-09-040Makana - TacomaVincent Dauphinrene.dauphin1@example.com0OverdueDiabetesAntibiotics3.25DauphinUnited Healthcare001982-09-043.2520Dr. Simone Okonkwo3.2503.2502910140737193.2500430-555-0100Sibling2029-10-251982-09-04Follow Up Visit0RWWX8ZDr. Simone Abernathy3.25Rene2029-10-253.250.75531363890483Smoke3.25001982-09-041982-09-04Male98406TacomaWAPRV-076PRV-072Surgical & Procedural
payer-enrichment.csv640 rows · 108 columns

Join keys: Email__c -> contacts.Email · MemberID__c -> patients.Patient_MemberID__c

ColumnType
Idsalesforce id
Nametext
Policy_Number__ctext
Coverage_Tier__ctext
Plan_Start_Date__cdate
Text_Attribute_9__cempty
Last_Portal_Login__cdate
Lifestyle_Indicators__ctext
Text_Attribute_5__cempty
Date_Attribute_5__cdate
Gender__ctext
Language_Preference__ctext
Address__ctext
Wellness_Program_Enrollment__cinteger
Completed_Annual_Wellness_Visit__cinteger
Optout__cinteger
Text_Attribute_14__cempty
Age__cinteger
Text_Attribute_10__cempty
MemberID__cinteger
Title__ctext
Text_Attribute_18__cempty
Date_Attribute_2__cdate
Chronic_Condition_Flags__ctext
Text_Attribute_2__cempty
Number_Attribute_4__cdecimal
Email__ctext
Plan_End_Date__cdate
Boolean_Attributes_7__cinteger
Boolean_Attributes_3__cinteger
Text_Attribute_8__cempty
Weight__cinteger
Number_Attribute_10__cdecimal
Text_Attribute_4__cempty
Number_Attribute_8__cdecimal
Race__ctext
Last_PCP_Visit_Date__cdate
Text_Attribute_13__cempty
Telehealth_Usage_Frequency__ctext
Social_Determinant_of_Health__ctext
Text_Attribute_17__cempty
Preventative_Care_Status__ctext
Medical_Condition__ctext
Text_Attribute_1__cempty
Number_Attribute_1__cdecimal
Number_Attribute_5__cdecimal
Last_Name__ctext
Insurance_Plan_Type__ctext
State__ctext
Boolean_Attributes_6__cinteger
Text_Attribute_20__cempty
Boolean_Attributes_2__cinteger
Network_Participation__ctext
First_Name__ctext
Text_Attribute_7__cempty
Salutation__ctext
Number_Attribute_9__cdecimal
Date_Attribute_3__cdate
Address_2__ctext
Text_Attribute_19__cempty
Preferred_Communication_Channel_Optin__ctext
Text_Attribute_12__cempty
Text_Attribute_16__cempty
Boolean_Attributes_9__cinteger
Children_Count__cinteger
Number_Attribute_6__cdecimal
Benefit_Utilization_Level__ctext
Number_Attribute_2__cdecimal
Deceased__cinteger
Contact_Number__cinteger
Boolean_Attributes_1__cinteger
Boolean_Attributes_5__cinteger
Plan_Renewal_Date__cdate
Member_Portal_Login_Frequency__ctext
Text_Attribute_6__cempty
Date_Attribute_4__cdate
Boolean_Attributes_10__cinteger
Text_Attribute_11__cempty
Marital_Status__ctext
Text_Attribute_15__cempty
Boolean_Attributes_8__cinteger
Date_Attribute_1__cdate
Zip__cinteger
Number_Attribute_7__cdecimal
Country__ctext
Text_Attribute_3__cempty
Number_Attribute_3__cdecimal
Boolean_Attributes_4__cinteger
City__ctext
Risk_Score__ctext
Member_Status__ctext
LOB__ctext
Renewal_Status__ctext
Risk_Tier__ctext
PMPM__ctext
Stars_Rating__ctext
RAF_Score__cdecimal
MLR__cdecimal
OON_Claims_Count__cinteger
OON_Claims_Pct__ctext
ER_Visits_12mo__cinteger
Inpatient_Admits_12mo__cinteger
Total_Care_Gaps__cinteger
Compliance_BP_Control__ctext
Compliance_A1C__ctext
Compliance_Flu_Vax__ctext
Compliance_Breast_Screen__ctext
cld_Audience__cempty

First 20 rows

IdNamePolicy_Number__cCoverage_Tier__cPlan_Start_Date__cText_Attribute_9__cLast_Portal_Login__cLifestyle_Indicators__cText_Attribute_5__cDate_Attribute_5__cGender__cLanguage_Preference__cAddress__cWellness_Program_Enrollment__cCompleted_Annual_Wellness_Visit__cOptout__cText_Attribute_14__cAge__cText_Attribute_10__cMemberID__cTitle__cText_Attribute_18__cDate_Attribute_2__cChronic_Condition_Flags__cText_Attribute_2__cNumber_Attribute_4__cEmail__cPlan_End_Date__cBoolean_Attributes_7__cBoolean_Attributes_3__cText_Attribute_8__cWeight__cNumber_Attribute_10__cText_Attribute_4__cNumber_Attribute_8__cRace__cLast_PCP_Visit_Date__cText_Attribute_13__cTelehealth_Usage_Frequency__cSocial_Determinant_of_Health__cText_Attribute_17__cPreventative_Care_Status__cMedical_Condition__cText_Attribute_1__cNumber_Attribute_1__cNumber_Attribute_5__cLast_Name__cInsurance_Plan_Type__cState__cBoolean_Attributes_6__cText_Attribute_20__cBoolean_Attributes_2__cNetwork_Participation__cFirst_Name__cText_Attribute_7__cSalutation__cNumber_Attribute_9__cDate_Attribute_3__cAddress_2__cText_Attribute_19__cPreferred_Communication_Channel_Optin__cText_Attribute_12__cText_Attribute_16__cBoolean_Attributes_9__cChildren_Count__cNumber_Attribute_6__cBenefit_Utilization_Level__cNumber_Attribute_2__cDeceased__cContact_Number__cBoolean_Attributes_1__cBoolean_Attributes_5__cPlan_Renewal_Date__cMember_Portal_Login_Frequency__cText_Attribute_6__cDate_Attribute_4__cBoolean_Attributes_10__cText_Attribute_11__cMarital_Status__cText_Attribute_15__cBoolean_Attributes_8__cDate_Attribute_1__cZip__cNumber_Attribute_7__cCountry__cText_Attribute_3__cNumber_Attribute_3__cBoolean_Attributes_4__cCity__cRisk_Score__cMember_Status__cLOB__cRenewal_Status__cRisk_Tier__cPMPM__cStars_Rating__cRAF_Score__cMLR__cOON_Claims_Count__cOON_Claims_Pct__cER_Visits_12mo__cInpatient_Admits_12mo__cTotal_Care_Gaps__cCompliance_BP_Control__cCompliance_A1C__cCompliance_Flu_Vax__cCompliance_Breast_Screen__ccld_Audience__c
a2wHu000007y0haIAADelia AshcombeBronze2026-02-28Female24801Nonedelia.ashcombe1@example.com2026-11-28AshcombeHMOINMixedDeliaEmail2026-10-2846201Indianapolis1ActiveExchangeIn ProgressLow262.450.820.711120.6667000Not ApplicableNot ApplicableCompliantNot Applicable
a2wHu000007y0hbIAADelia BrightwaterBronze2026-01-28Female31802Hypertensiondelia.brightwater1@example.com2026-12-28BrightwaterPPOILOut-of-NetworkDeliaEmail2026-11-2860601Chicago2.3ActiveCommercialIn ProgressLow465.9221.4560.775650.8333002Non-CompliantNot ApplicableNon-CompliantNot Applicable
a2wHu000007y0hcIAADelia CaldwellBronze2025-12-28Female38803Diabetesdelia.caldwell1@example.com2027-01-28CaldwellEPOMAOut-of-NetworkDeliaEmail2026-12-2802108Boston3.6ActiveCommercialRenewedLow557.4421.7420.7980.8889002Not ApplicableNon-CompliantNon-CompliantNot Applicable
a2wHu000007y0hdIAADelia DunmoreBronze2025-11-28Female45804Asthmadelia.dunmore1@example.com2027-02-28DunmorePOSCAOut-of-NetworkDeliaSMS2027-01-2890012Los Angeles4.9ActiveCommercialRenewedMedium648.9622.0280.8044110.9167002Not ApplicableNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0heIAADelia EllsworthSilver2025-10-28Female52805COPDdelia.ellsworth1@example.com2027-03-28EllsworthHMONYOut-of-NetworkDeliaSMS2027-02-2810001New York6.2ActiveExchangeRenewedMedium971.8822.3140.818940.8002Not ApplicableNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0hfIAADelia FairbourneSilver2025-09-28Female59806Nonedelia.fairbourne1@example.com2027-04-28FairbournePPOGAMixedDeliaSMS2027-03-2830303Atlanta7.5ActiveCommercialRenewedHigh94522.250.833370.875002Not ApplicableNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0hgIAADelia GatlinSilver2025-08-28Female66807Hypertensiondelia.gatlin1@example.com2027-05-28GatlinEPONMOut-of-NetworkDeliaMail2027-04-2887102Albuquerque8.8ActiveMedicare AdvantageRenewedHigh1212.1232.8860.8478100.9091002Non-CompliantNot ApplicableCompliantNon-Compliant
a2wHu000007y0hhIAADelia HarrowgateSilver2025-07-28Female73808Diabetesdelia.harrowgate1@example.com2027-06-28HarrowgatePOSWAOut-of-NetworkDeliaMail2027-05-2898402Tacoma2.1ActiveMedicare AdvantageRenewedLow593.0421.4120.798330.75003Not ApplicableNon-CompliantNon-CompliantNon-Compliant
a2wHu000007y0hiIAADelia InglewoodGold2025-06-28Female25809Asthmadelia.inglewood1@example.com2027-07-28InglewoodHMOTXOut-of-NetworkDeliaMail2027-06-2875201Dallas3.4ActiveExchangeRenewedLow916.9221.6980.762860.8571001Not ApplicableNot ApplicableNon-CompliantNot Applicable
a2wHu000007y0hjIAADelia JessupGold2025-05-28Female32810COPDdelia.jessup1@example.com2027-08-28JessupPPOTNOut-of-NetworkDeliaPhone Call2027-07-2837203Nashville4.7ActiveCommercialRenewedMedium1071.3621.9840.777290.9001Not ApplicableNot ApplicableNon-CompliantNot Applicable
a2wHu000007y0hkIAADelia KirkwallGold2025-04-28Female39811Nonedelia.kirkwall1@example.com2026-11-28KirkwallEPOTXMixedDeliaPhone Call2026-10-2877002Houston6ActiveCommercialIn ProgressMedium1036.821.920.791720.6667001Not ApplicableNot ApplicableNon-CompliantNot Applicable
a2wHu000007y0hlIAADelia LangtryGold2025-03-28Female46812Hypertensiondelia.langtry1@example.com2026-12-28LangtryPOSPAOut-of-NetworkDeliaPhone Call2026-11-2819102Philadelphia7.3ActiveCommercialIn ProgressHigh1380.2422.5560.856150.8333003Non-CompliantNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0hmIAADelia MerriwetherPlatinum2026-02-28Female53813Diabetesdelia.merriwether1@example.com2027-01-28MerriwetherHMOCOOut-of-NetworkDeliaEmail2026-12-2880202Denver8.6ActiveExchangeRenewedHigh1989.432.8420.845680.8889002Not ApplicableNon-CompliantCompliantNon-Compliant
a2wHu000007y0hnIAADelia NorthcotePlatinum2026-01-28Female60814Asthmadelia.northcote1@example.com2027-02-28NorthcotePPOMOOut-of-NetworkDeliaEmail2027-01-2864108Kansas City1.9ActiveCommercialRenewedLow957.621.3680.7711110.9167002Not ApplicableNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0hoIAADelia OakhurstPlatinum2025-12-28Female67815COPDdelia.oakhurst1@example.com2027-03-28OakhurstEPOCTOut-of-NetworkDeliaEmail2027-02-2806103Hartford3.2ActiveMedicare AdvantageRenewedLow1157.821.6540.785640.8002Not ApplicableNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0hpIAADelia PembertonPlatinum2025-11-28Female74816Nonedelia.pemberton1@example.com2027-04-28PembertonPOSNJMixedDeliaSMS2027-03-2807302Jersey City4.5ActiveMedicare AdvantageRenewedMedium111321.590.870.875002Not ApplicableNot ApplicableNon-CompliantNon-Compliant
a2wHu000007y0hqIAADelia QuillonBronze2025-10-28Female26817Hypertensiondelia.quillon1@example.com2027-05-28QuillonHMOFLOut-of-NetworkDeliaSMS2027-04-2832501Pensacola5.8ActiveExchangeRenewedMedium712.3222.2260.8144100.9091002Non-CompliantNot ApplicableNon-CompliantNot Applicable
a2wHu000007y0hrIAADelia RavenscroftBronze2025-09-28Female33818Diabetesdelia.ravenscroft1@example.com2027-06-28RavenscroftPPOINOut-of-NetworkDeliaSMS2027-05-2846208Indianapolis7.1ActiveCommercialRenewedHigh803.8422.5120.828930.75002Not ApplicableNon-CompliantNon-CompliantNot Applicable
a2wHu000007y0hsIAADelia StallworthBronze2025-08-28Female40819Asthmadelia.stallworth1@example.com2027-07-28StallworthEPOINOut-of-NetworkDeliaMail2027-06-2846201Indianapolis8.4ActiveCommercialRenewedHigh895.363.52.7980.818360.8571001Not ApplicableNot ApplicableCompliantNon-Compliant
a2wHu000007y0htIAADelia ThackeryBronze2025-07-28Female47820COPDdelia.thackery1@example.com2027-08-28ThackeryPOSILOut-of-NetworkDeliaMail2027-07-2860601Chicago1.7ActiveCommercialRenewedLow423.6821.3240.768990.9002Not ApplicableNot ApplicableNon-CompliantNon-Compliant

Every file scanned for credentials before packaging. Zero found. All data synthetic. MIT-licensed, provided as-is. Verified 3 September 2026.

What is in the asset pack

Asset pack folder layout
FolderContentsNote
00-dependencies/HLSMetadataSoap, HLSSiteGeocoderDeploy first. cld_ObjectFactory will not compile without the first
01-capability-layer/3 classesResolve object and field names at runtime so components degrade instead of throwing
02-controllers/17 classesThree of them hard-fail rather than degrade — see below
03-seed-generators/11 classesDeterministic. Run last: they write on top of records that must already exist
04-lwc/18 bundles, 72 filesEvery screen in the screenshots on this page
05-placement/15 FlexiPages, 11 tabs, 3 permission sets, 4 agent actionsDeploy tabs before permission sets
06-data/13 datasets, ~4.8 MB890 contacts, 640 payer, 640 patient, 2,989 appointments, 5,828 consent rows, 25 CMS pieces
07-config/91 filesSegments, dashboards, agents, Data Cloud. Reference material to read and adapt, not artifacts to import

Before you deploy

  1. Read SETUP.md. It carries a Replace before you deploy table: 71 hardcoded ids across the Apex, roughly 813 more across 07-config/, the org id in 33 config files, and the tenant-suffixed Data Cloud table ssotIndividualHls1_Unified_SMH_1768110__dlm whose numeric suffix is unique to this tenant and appears in four controllers.
  2. Deploy in folder order: 00 → 01 → 02 → 03.
  3. Run the seeds against synthetic data only. SEESpinePopulate infers gender from a name allowlist and is unsuitable for anything real.
  4. Load the data before running the seeds. 06-data/README.md gives the order. Every Id column is org-specific and must be re-keyed on import; contacts.IndividualId is the key the consent files join on, and an export that omits it produces 5,828 consent rows that join to nothing.

The mock data, on its own

890 contacts, 640 payer enrichment rows, 640 patient rows, 2,989 appointments, 1,189 campaign members, 5,828 consent rows and 25 CMS content pieces. Every email address is on the reserved example.com domain and every phone number sits in the NANP reserved fictional range – 8,198 addresses and 4,591 numbers, all replaced before packaging.

Twenty documented joins resolve at their original rates. Two of them previously resolved at zero: consent hangs off Individual.PartyId, and the first export omitted Contact.IndividualId, so 5,828 consent rows joined to nothing. That one column is the difference between a usable consent model and a pile of orphans.

Every Id column is org-specific and must be re-keyed on import. 06-data/README.md gives the load order.

The skills

Five Claude skills, written while building this and used to build it. sfdc-headless-discovery is the most portable – the enumerator rule, the three oracles, and a table of Salesforce errors that do not mean what they say. tableau-next-dashboard-craft turns a day of Can’t show visualization into ten minutes. sfdc-web-affinity covers anonymous-to-known web tracking including a guest-user with sharing bug worth knowing about. sfdc-mcnext-campaign-build is the densest of the set and only useful if you build Marketing Cloud Next demo orgs. salesforce-se-os is a triage router for SE work.

A sixth was withheld. It depends on unpublished documents, and without them an agent would improvise the missing rubric and present the result as authored – which is the opposite of what this document is for. PROVENANCE.md in the pack says what was reviewed, what was changed before publication and why, and what each skill needs to run.

The schema

The pack now carries the schema as deployable metadata. 306 files – five object definitions and 279 field definitions in sf source format, under 08-schema/.

sf project deploy start --source-dir 08-schema/force-app

That replaces the paragraph above telling you to build six objects by hand. Deploy it first, before anything else in the pack.

Then assign the included cld_AssetPack_Schema_Access permission set. A metadata deploy grants no field-level security, so without it cld_OrgCapability.hasField() reports every field missing even though they deployed correctly – the capability layer does exactly what it should and degrades the whole pack to empty.

Eighteen fields are quarantined in 08-schema/quarantine/, all for one reason: their parent object is Visit, an Industries standard object that does not exist in a plain Enterprise Edition org. They are correct metadata and deploy as a second command in an org that has it.

Honest caveat: this tree was validated structurally – well-formedness, Metadata API element ordering, per-type required elements, length and precision bounds, lookup reachability – and never actually deployed. The extraction was read-only.