Contact post-upsert flow
Note
This flow is self-documenting and should be viewed within Salesforce (Setup > Process Automations > Flows). This document is to support working through a visual flow. Please note: the flow commentary is produced using AI.
Overview#
Flow name: MoveData_Donation_Contact_Post Label: [MoveData] General: Contact - Post Upsert Type: Auto-Launched Flow Template API version: 60.0 Status: Active
This flow handles post-processing operations after account records are created or updated, including platform key association and account-contact relationship establishment. The flow operates in the context of account processing but creates contact relationships and manages platform key associations.
Purpose#
The flow performs post-upsert operations that:
- Creates platform key associations linking accounts to external platform identifiers
- Establishes account-contact relationships with configurable roles
- Provides configurable platform key processing with disable options
- Supports business relationship management through AccountContactRelation objects
- Implements comprehensive error handling for platform key creation failures
Salesforce fields#
This flow interacts with the Salesforce Account, Contact, and AccountContactRelation objects. Below is a mapping of all fields utilised:
| Object | Field API name | Field type | Purpose in flow |
|---|---|---|---|
| Account | Id | ID | Primary account record identifier |
| Contact | Id | ID | Associated contact record identifier |
| AccountId | Lookup to Account | Links contact to the account | |
| AccountContactRelation | Id | ID | Relationship record identifier |
| AccountId | Lookup to Account | Account side of the relationship | |
| ContactId | Lookup to Contact | Contact side of the relationship | |
| Roles | Picklist | Business relationship role classification |
Input variables#
Core record data#
| Variable | Type | Required | Description |
|---|---|---|---|
Record |
Account SObject | Yes | The Account record that was created/updated |
ParentAccount |
Account SObject | No | Parent account for relationship establishment |
Platform |
String | Yes | External platform identifier |
PlatformKey |
String | Yes | External platform's account identifier |
Configuration variables#
| Variable | Type | Default | Description |
|---|---|---|---|
Config_ContactDisablePlatformKey |
Boolean | false | Completely disable platform key processing |
Config_ContactSetPlatformKey |
Boolean | true | Enable platform key creation |
Config_AccountRelationshipDefault |
String | "Business User" | Default role for account-contact relationships |
Config_AnonymousContactId |
String | null | The shared anonymous person account; no contact points are written for it |
Config_ContactPointWrite |
Boolean | false | The contact point writer's one switch |
Config_ContactPointAddressName |
String | null | Name pattern for ContactPointAddress, which requires a Name |
Config_ContactPointAddressType |
String | null | Default AddressType — Billing or Shipping |
Config_ContactPointPhoneType |
String | null | Default PhoneType — Home or Mobile |
Config_ContactPointUsageType |
String | null | Default UsageType, used only where the platform sent none |
Config_ContactPointSmsCapable |
Boolean | false | Sets IsSmsCapable on new phone contact points |
Config_ContactPointPhoneMinimumDigits |
Number | 8 | Phone numbers shorter than this are skipped; 0 writes every number |
Config_ContactAddressQualityIndex |
Number | null | Minimum address quality, 0.00 to 1.00; shared with the contact mapping flow |
Output variables#
| Variable | Type | Description |
|---|---|---|
Errors |
String Collection | Collection of errors from processing |
Logs |
Apex Collection | MoveDataLogEntry collection for logging |
LogsJSON |
String | JSON serialised version of logs |
RecordList |
String Collection | Contact point ids this donation created, matched or updated; merged into the notification's Records section |
Flow logic#
1. Parent account validation#
The flow begins by checking if a parent account is provided:
- Condition: Validates
ParentAccountis not null and has a valid ID - Path selection: Determines whether to proceed with relationship creation or skip to platform key processing
2. Contact record retrieval#
When a parent account exists:
- Query: Looks up contact records where
AccountIdequals the main record ID - Purpose: Finds existing contacts associated with the account for relationship establishment
- Result: Single contact record for relationship processing
3. Account-contact relationship management#
Existing relationship check#
- Query: Searches for existing
AccountContactRelationrecords - Filters:
AccountIdequals parent account IDContactIdequals found contact ID
- Purpose: Prevents duplicate relationship creation
Relationship creation#
When no existing relationship exists:
- Object: Creates new
AccountContactRelationrecord - Fields:
AccountId: Set to parent account IDContactId: Set to retrieved contact IDRoles: Set to configured default role value
- Business rule: Establishes formal business relationship between account and contact
4. Platform key association#
Configuration check#
- Condition: Verifies
Config_ContactDisablePlatformKeyis not true andConfig_ContactSetPlatformKeyis not false - Purpose: Allows complete bypassing of platform key processing when disabled
Platform key validation#
- Conditions:
Platformis not nullPlatformKeyis not null
- Purpose: Ensures required data exists before attempting platform key creation
Platform key creation#
- Component: Uses
movedata__PlatformKeyCreateComponentApex action - Parameters:
ObjectId: The account record IDPlatform: External platform identifierPlatformKey: Platform-specific account identifierErrorIfDifferentObjectId: Set to true for validation
- Error handling: Captures creation failures and adds to error collection
Processing summary#
- Parent account check: Validate parent account availability
- Contact retrieval: Find associated contact record
- Relationship assessment: Check for existing account-contact relationships
- Relationship creation: Create new relationships when needed
- Platform key processing: Create platform key associations (if enabled)
- Error collection: Capture and report any processing failures
Configuration options#
Platform key control#
- Complete disable:
Config_ContactDisablePlatformKey = trueskips all platform key processing - Suppress creation:
Config_ContactSetPlatformKey = falseskips platform key creation while leaving platform key matching in place - Relationship role:
Config_AccountRelationshipDefaultsets the business role for new relationships
Business relationship roles#
The default role "Business User" can be customised to reflect organisational relationship types:
- Standard business contact relationships
- Vendor/supplier relationships
- Partner/alliance relationships
- Customer/client relationships
Error handling#
Platform key error management#
- Error collection: Platform key creation failures are captured in
Errorscollection - Fault tolerance: Processing continues even if platform key creation fails
- Error attribution: Errors include specific details about platform key creation failures
Error handling#
Common error conditions handled:
- Duplicate platform keys: When platform key already exists for different record
- Invalid platform configuration: When platform settings are misconfigured
- Record access issues: When insufficient permissions exist for relationship creation
Customising contact point mapping#
The contact point settings cover the choices most organisations need. When a customer needs logic the settings cannot express — a usage type that depends on the campaign, say, or a contact point they want deleted under some condition — the route is their own flow running after this one, not a modified copy of it.
There is no _EXT extension slot on a post-upsert stage: the mapping stages have one (PIPELINE_DONATION_CONTACT_MAPPING_EXT) and post-upsert does not.
What a post stage does have is room for more than one handler. MoveData loads every enabled MoveData_Pipeline__mdt record whose label matches the stage and runs them in Order__c order, so a customer can register their own auto-launched flow against PIPELINE_DONATION_CONTACT_POST with an order after the package's.
Their flow then runs in the same transaction with the same inputs: Record is the Account, the payload values (Email, Phone, the MailingAddress_* fields) are all present, and so is every Config_ value.
A Get Records on ContactPointEmail, ContactPointPhone or ContactPointAddress sees what MoveData has just written. Their RecordList, Logs and Errors outputs are read back the same way the package's are, so they can add their records to the notification's Records section, write their own log lines, and raise an error that fails the notification.
A customer who wants the whole job their own way should instead turn Write Contact Points off and do all of it in their flow.
Three things to say before recommending this:
- A mapping extension flow is the wrong place for it. That runs before the upsert, and on a brand new supporter there is no Account id yet for a contact point to parent to.
- A second handler on a package stage is supported by the pipeline but is not a documented extension point, so it is not covered by the package's own upgrade testing.
Order__cis a single namespace across every stage, so pick a number clear of the package's.
Check Config_ContactPostUpsertAsync too: when it is set, the whole post-upsert stage moves to a future method, and the customer's flow goes with it.
Dependencies#
movedata__PlatformKeyCreateComponent(Apex action)movedata__NamePatternParserComponent(Apex action)ContactPointWriteComponent(Apex action) — see Write Contact Points flow componentmovedata__MoveDataLogEntry(Apex class)