Introduction
As an alternative to viewing Sendoso spend one record at a time, you can roll Sendoso writeback spend up the Salesforce data model — from Lead to Contact to Account — so AEs and CSMs see total Sendoso program investment per account in reports, list views, and dashboards.
This setup uses standard Salesforce Currency fields, a Contact-level formula field, a Lead → Contact conversion mapping, and one record-triggered flow.
You will need Salesforce admin permissions to complete this setup, including Customize Application and Manage Flows.
This article assumes the Sendoso ↔ Salesforce integration is already connected and writing back send data, and that the Sendoso writeback fields have been mapped per Setting Up: Additional Salesforce Tracking Fields and Activity Mapping.
Lead-Level Field Setup
To get started, go to 'Setup' and find Object Manager → Lead → Fields & Relationships.
Create a new Currency field on the Lead object using the values below.
| Setting | Value |
| Type | Currency |
| Field Label | Total $ Spent on Lead |
| Field Name | Total_Spent_On_Lead |
| Length | 16 |
| Decimal Places | 2 |
| Description | Total $ spent via Sendoso while this person was a Lead. Populated by the Sendoso ↔ Salesforce writeback. |
Grant the Sendoso integration user Edit access via the permission set or profile that controls integration access (typically named something like Sendoso_Fields_Access):
- Setup → Permission Sets (or Profiles)
- Open the permission set assigned to the Sendoso integration user
- Object Settings → Lead → click Edit
- Set Read and Edit on Total $ Spent on Lead
- Save
End-user profiles can be Read-Only.
Add the field to the 'Sendoso' section of any Lead page layouts that should display it.
This field is populated by Sendoso, not by Salesforce. Do not put a formula or default value on it.
Contact-Level Field Setup
You will create three custom fields on the Contact object. Two are populated by Sendoso, the third is a formula that adds them together.
Go to 'Setup' and find Object Manager → Contact → Fields & Relationships.
Step 1 – Create Total $ Spent on Contact
Create a new Currency field using the values below.
| Setting | Value |
| Type | Currency |
| Field Label | Total $ Spent on Contact |
| Field Name | Total_Spent_On_Contact |
| Length | 16 |
| Decimal Places | 2 |
| Description | Total $ spent via Sendoso on this Contact since they became a Contact. Populated by the Sendoso ↔ Salesforce writeback. |
Step 2 – Create Total $ Spent on Lead
Create a second Currency field using the values below.
| Setting | Value |
| Type | Currency |
| Field Label | Total $ Spent on Lead |
| Field Name | Total_Spent_On_Lead |
| Length | 16 |
| Decimal Places | 2 |
| Description | Total $ spent on this recipient while they were a Lead. Populated via Lead conversion mapping so Sendoso spend history is preserved after Lead-to-Contact conversion. |
Step 3 – Create Total $ Sendoso Spend (formula)
Create a Formula field with return type Currency.
| Setting | Value |
| Type | Formula → Currency |
| Field Label | Total $ Sendoso Spend |
| Field Name | Total_Overall_Sendoso_Spend |
| Decimal Places | 2 |
| Treat blank fields as | Zero |
| Description | Total overall Sendoso spend on this Contact across their lifetime, including spend accumulated while they were a Lead. |
Paste the formula below into the formula editor:
Total_Spent_On_Contact__c + Total_Spent_On_Lead__c
If your org has multi-currency enabled, wrap each field in convertCurrency(...) to keep totals in a consistent currency.
After all three fields are created, grant the Sendoso integration user the right access on each:
- Setup → Permission Sets (or Profiles)
- Open the permission set assigned to the Sendoso integration user
- Object Settings → Contact → click Edit
- Set Read and Edit on Total $ Spent on Contact and Total $ Spent on Lead
- Set Read on Total $ Sendoso Spend (formula fields are read-only by design)
- Save
End users typically need Read access on all three fields.
Configure Sendoso Writeback to the New Fields
After creating the Lead and Contact fields, the Sendoso platform must be told to write to these specific Salesforce field API names. Without this step, Sendoso continues writing to its default fields and the new fields stay empty — even though the SFDC setup is complete.
Confirm with your Sendoso admin or Sendoso Customer Success Manager that the writeback configuration in Sendoso is mapped to:
| Salesforce Object | Sendoso writeback field | New API name to map to |
| Lead | Total $ Spent on Lead | Total_Spent_On_Lead__c |
| Contact | Total $ Spent on Contact | Total_Spent_On_Contact__c |
Refer to Setting Up: Additional Salesforce Tracking Fields and Activity Mapping for the field-mapping UI inside the Sendoso platform.
Until the Sendoso side is mapped, sending a gift will not populate the new fields. The Account rollup will stay at $0 even after the flow is deployed and active.
Lead → Contact Conversion Mapping
Without this step, Sendoso spend that accumulates on a Lead is lost the moment that Lead converts. The Account-level total will undercount lifetime spend for any Contact who entered as a Lead.
Go to Setup → Object Manager → Lead → Fields & Relationships → Map Lead Fields.
Find Total_Spent_On_Lead__c (Lead) and map it to Total_Spent_On_Lead__c (Contact).
Save.
After mapping, convert a test Lead with a non-zero Total $ Spent on Lead. Open the resulting Contact and confirm the value carried over and that Total $ Sendoso Spend reflects it.
Account-Level Field Setup
Go to Setup → Object Manager → Account → Fields & Relationships.
Create a new Currency field using the values below.
| Setting | Value |
| Type | Currency |
| Field Label | Total Sendoso Spend |
| Field Name | Total_Sendoso_Spend |
| Length | 16 |
| Decimal Places | 2 |
| Description | Total Sendoso spend across all Contacts on this Account. Populated by the Account Sendoso Rollup flow whenever a Contact on this Account is created or updated. |
Set field-level security:
- End users: Read-Only
- Sendoso integration user: Read-Only
- Automated Process User and any user profile that triggers the flow (typically by saving Contact records): Edit
The flow runs in system context but writes the Account update on behalf of the user who triggered the save. If that user does not have Edit FLS on Account → Total Sendoso Spend, the flow will fail.
Add the field to the 'Sendoso' section of Account page layouts.
Account Rollup Flow Setup
The rollup is implemented as a record-triggered flow on the Contact object that fires after save (Create and Update). It pulls every Contact on the Account, sums Total $ Sendoso Spend, and writes the total back to Account → Total Sendoso Spend.
There are two ways to build this flow. Deloy the flow XML or Build the flow in Flow Builder.
Option A – Deploy the flow XML
If you are comfortable deploying metadata, save the XML below as Account_Sendoso_Rollup.flow-meta.xml in your force-app/main/default/flows/ directory and deploy with sf project deploy start.
Code Block for Account Sendoso Rollup Flow:
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<label>Account Sendoso Rollup</label>
<description>Recalculates Account.Total_Sendoso_Spend__c as the sum of Total_Overall_Sendoso_Spend__c across all Contacts on the Account. Fires after save on Contact create or update.</description>
<interviewLabel>Account Sendoso Rollup {!$Flow.CurrentDateTime}</interviewLabel>
<processType>AutoLaunchedFlow</processType>
<status>Active</status>
<environments>Default</environments>
<start>
<object>Contact</object>
<recordTriggerType>CreateAndUpdate</recordTriggerType>
<triggerType>RecordAfterSave</triggerType>
<connector>
<targetReference>Has_Account</targetReference>
</connector>
</start>
<decisions>
<name>Has_Account</name>
<label>Has Account</label>
<defaultConnectorLabel>No Account</defaultConnectorLabel>
<rules>
<name>Yes_Has_Account</name>
<label>Yes</label>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>$Record.AccountId</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Get_All_Contacts</targetReference>
</connector>
</rules>
</decisions>
<recordLookups>
<name>Get_All_Contacts</name>
<label>Get All Contacts On Account</label>
<object>Contact</object>
<getFirstRecordOnly>false</getFirstRecordOnly>
<storeOutputAutomatically>true</storeOutputAutomatically>
<queriedFields>Id</queriedFields>
<queriedFields>Total_Overall_Sendoso_Spend__c</queriedFields>
<filterLogic>and</filterLogic>
<filters>
<field>AccountId</field>
<operator>EqualTo</operator>
<value>
<elementReference>$Record.AccountId</elementReference>
</value>
</filters>
<connector>
<targetReference>Init_Sum</targetReference>
</connector>
</recordLookups>
<variables>
<name>totalSum</name>
<dataType>Number</dataType>
<scale>2</scale>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<assignments>
<name>Init_Sum</name>
<label>Initialize Sum</label>
<assignmentItems>
<assignToReference>totalSum</assignToReference>
<operator>Assign</operator>
<value>
<numberValue>0.0</numberValue>
</value>
</assignmentItems>
<connector>
<targetReference>Loop_Contacts</targetReference>
</connector>
</assignments>
<loops>
<name>Loop_Contacts</name>
<label>Loop Contacts</label>
<collectionReference>Get_All_Contacts</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Add_To_Sum</targetReference>
</nextValueConnector>
<noMoreValuesConnector>
<targetReference>Update_Account</targetReference>
</noMoreValuesConnector>
</loops>
<assignments>
<name>Add_To_Sum</name>
<label>Add Contact Spend To Sum</label>
<assignmentItems>
<assignToReference>totalSum</assignToReference>
<operator>Add</operator>
<value>
<elementReference>Loop_Contacts.Total_Overall_Sendoso_Spend__c</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Loop_Contacts</targetReference>
</connector>
</assignments>
<recordUpdates>
<name>Update_Account</name>
<label>Update Account Total</label>
<object>Account</object>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>$Record.AccountId</elementReference>
</value>
</filters>
<inputAssignments>
<field>Total_Sendoso_Spend__c</field>
<value>
<elementReference>totalSum</elementReference>
</value>
</inputAssignments>
</recordUpdates>
</Flow>
After deploying, activate the flow:
- Setup → Process Automation → Flows
- Find Account Sendoso Rollup
- Click the dropdown arrow on the right → View Details and Versions
- Click Activate on the most recent version
The XML above is stripped of canvas coordinates. The flow will deploy and run identically — Flow Builder will auto-layout the elements the first time you open it.
Option B – Build the flow in Flow Builder
If you would rather click-build, navigate to Setup → Process Automation → Flows → New Flow → Record-Triggered Flow.
Configure the trigger:
| Setting | Value |
| Object | Contact |
| Trigger | A record is created or updated |
| Optimize the Flow for | Actions and Related Records |
| Set conditions | None |
This flow has no entry criteria by design. It fires on every Contact create or update. For high-volume orgs, add an entry condition like ISCHANGED(Total_Overall_Sendoso_Spend__c) OR ISNEW() to reduce flow runs. For bulk loads (Data Loader, API, or background sync) of 200+ Contacts on the same Account, consider deactivating the flow during the load and running the backfill in the next section once the load completes.
Build the flow with six elements wired in this order.
Step 1 – Decision element: Has Account
| Setting | Value |
| Label | Has Account |
| Outcome | Yes |
| Condition | $Record → AccountId Is Null False |
| Default outcome | No Account (end the flow) |
Step 2 – Get Records: Get All Contacts On Account
| Setting | Value |
| Object | Contact |
| Filter | AccountId Equals $Record → AccountId |
| Number of records to store | All records |
| How to store record data | Choose fields and let Salesforce do the rest (Id, Total_Overall_Sendoso_Spend__c) |
Step 3 – Variable: totalSum
Create a flow Resource → Variable.
| Setting | Value |
| API Name | totalSum |
| Data Type | Number |
| Scale | 2 |
| Available for input | No |
| Available for output | No |
Step 4 – Assignment: Initialize Sum
| Setting | Value |
| Variable | {!totalSum} |
| Operator | Equals |
| Value | 0 |
Step 5 – Loop: Loop Contacts
| Setting | Value |
| Collection variable | {!Get_All_Contacts} |
| Direction | First item to last item |
Inside the loop, add an Assignment element Add Contact Spend To Sum:
| Setting | Value |
| Variable | {!totalSum} |
| Operator | Add |
| Value | {!Loop_Contacts.Total_Overall_Sendoso_Spend__c} |
Step 6 – Update Records: Update Account Total
| Setting | Value |
| How to find records | Specify conditions |
| Object | Account |
| Filter | Id Equals $Record → AccountId |
| Field to update | Total_Sendoso_Spend__c → {!totalSum} |
Save the flow as Account Sendoso Rollup and Activate.
Backfilling Existing Records
The flow only fires when a Contact is created or updated. If the org already has Sendoso spend on Contacts that have not been edited since the flow was activated, run a one-time backfill to populate the Account totals.
Open the Salesforce Developer Console → Debug → Open Execute Anonymous Window. Paste and run:
List<Contact> contactsToTouch = [ SELECT Id FROM Contact WHERE AccountId != null ]; update contactsToTouch;
For orgs with more than ~10,000 Contacts, run the backfill in batches with Data Loader instead of Execute Anonymous to avoid governor limits.
Verify Everything Works
Before waiting on real Sendoso send data, run a manual test to confirm the flow is wired correctly.
- Open any Contact record on an Account that has multiple Contacts
- Edit the Contact and set Total $ Spent on Contact to 100
- Save
- Open the parent Account
- Confirm Total Sendoso Spend increased by exactly $100
Once the manual test passes, your end-state should look like this once Sendoso writeback is flowing:
| Object | Field | Expected Value |
| Lead (pre-conversion) | Total $ Spent on Lead | Sendoso writeback amount |
| Contact (post-conversion) | Total $ Spent on Lead | Same value carried over from the Lead |
| Contact | Total $ Spent on Contact | Sendoso writeback amount accumulated as a Contact |
| Contact | Total $ Sendoso Spend | Sum of the two fields above |
| Account | Total Sendoso Spend | Sum of Total $ Sendoso Spend across every Contact on the Account |
To confirm the flow is firing on real saves, go to Setup → Process Automation → Flows → Account Sendoso Rollup → View Details and Versions and check the recent Interview history.
Troubleshooting
| Problem | Solution |
| Account → Total Sendoso Spend stays at $0 | Confirm the Contact records on that Account have non-zero Total $ Sendoso Spend. If Contact fields are also $0, confirm the Sendoso side has been mapped to the new field API names (see Configure Sendoso Writeback to the New Fields). |
| Lead spend is lost after conversion | Confirm the Lead → Contact field mapping is wired (Setup → Object Manager → Lead → Map Lead Fields). |
| Sendoso spend on an unconverted Lead is not on any Account | Expected. Account totals only include spend on Contacts. Spend on Leads that never convert is visible only on the Lead record itself. |
| Account total is stale after a Contact is deleted | The base flow does not fire on Contact delete. Touch any other Contact on the Account, or extend the flow to also trigger on Before Delete. |
| Account total is stale after a Contact is reparented | The flow updates the new Account but not the old one. Touch a Contact on the prior Account, or extend the flow to recalculate the prior AccountId. |
| Flow throws "Insufficient Privileges" on the Account update | Grant Edit FLS on Account → Total Sendoso Spend to the user profiles that trigger the flow (anyone whose actions cause Contact saves). |
| New Sendoso sends do not populate Lead or Contact spend fields | The Sendoso platform writeback is still pointing at default fields. Map the Sendoso side to Total_Spent_On_Lead__c and Total_Spent_On_Contact__c per the Configure Sendoso Writeback to the New Fields section. |
| Roll-Up Summary Field option is greyed out on Account | Account → Contact is a lookup, not master-detail. Roll-Up Summary is not available — that is why this article uses a flow. |
| Custom field references break after rename | The flow references Contact.Total_Overall_Sendoso_Spend__c and Account.Total_Sendoso_Spend__c. Keep those API names stable. The underlying writeback fields can be renamed if you also update the Contact formula. |