What are platform integrations?
This feature allows institutions to connect their Mainstay data to a third-party platform, such as Salesforce. This enables a 2-way sync of contact record data, including default fields (name, phone, email, etc.) and custom fields created by the partner. To learn more, visit Platform Integrations.
OVERVIEW
Mainstay Sync for Salesforce is an unlocked package available for Salesforce admins. This integration provides a number of features:
- One-time Import and Export commands, to generate new Salesforce records for Mainstay Contacts and to generate new Mainstay Contacts from Salesforce records.
- One- or two-direction syncing, to update Mainstay Contacts automatically when a Salesforce record is changed and/or update Salesforce records automatically when an Mainstay Contact is changed; this also includes field mapping customizations and robust error logging.
- Viewing Mainstay Conversations within the Salesforce Contact record page.
- Viewing Mainstay Campaign history within the Salesforce Contact record page.
INSTALLATION
- Salesforce
- Log into your Salesforce account at https://login.salesforce.com/.
- Ensure "My Domain" is enabled. (See https://help.salesforce.com/articleView?id=sf.domain_name_overview.htm&type=5)
- Access the installation manager at https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FMnUFUA1
-
To use this package in a Salesforce sandbox, instead of login (https://login.salesforce.com/packaging/installPackage...) use test (https://test.salesforce.com/packaging/installPackage...)
-
To use this package in a custom "My Domain" URL, go to Setup > Company Settings > My Domain and check the value of the current My Domain URL. Then instead of login.salesforce.com (https://login.salesforce.com/packaging/installPackage...) use your custom My Domain URL (https://schoolname-sandbox.my.salesforce.com/packaging/installPackage...)
-
- Grant permissions as necessary and select "Install."
- Note that this may take up to 5 minutes; Salesforce will notify you by email when the package has been installed.
- Log into your Salesforce account at https://login.salesforce.com/.
- Mainstay
- Log into your Mainstay account at https://app.mainstay.com.
- In the sidebar, navigate to Settings > Mainstay API.
- If this option is not available, contact your Partner Success Manager.
- In the top-right corner, select "Generate a new token." Enter a name, such as "Salesforce," and then copy the randomly generated integration token.
- Mainstay Sync for Salesforce integration
- When the package has installed, return to Salesforce.
- Use the app selector to search for "Mainstay Sync" and open this app. Note that in some older versions, this may say "AdmitHub Sync".
- Note that if you installed this "for Admins Only", you may need to ensure the tab visibility is set to "Default On" (https://help.salesforce.com/articleView?id=users_tab_visibility.htm&type=5).
- Paste the Mainstay API token into the "API token" field. Click "Connect." This is necessary to send information from Salesforce to Mainstay.
- Use the gear icon to access Setup. Navigate to Apps > App Manager > Mainstay Sync (Connected) > rightmost dropdown > View. Again, note that in some older versions, this may be labeled "AdmitHub Sync".
- Copy the values from "Consumer Key" and "Consumer Secret" into the respective fields on the Mainstay "Salesforce" page. This is necessary to send information from Mainstay to Salesforce.
- Return to the Mainstay Sync for Salesforce page click "Authorize Salesforce for Mainstay".
- If you're upgrading from a previous package, toggle the Sync Salesforce → Mainstay and Sync Mainstay → Salesforce off and on again to reset them.
VERSION 1.0 - 1.42
Mainstay Sync Settings
SYNC STATUS
In this section, you can independently control the direction of data:
- Sync Salesforce → Mainstay: if enabled, any changes you make to Salesforce records will be immediately forwarded to the corresponding Mainstay Contacts, including creating new Contacts.
- Sync Mainstay → Salesforce: if enabled, any changes you make to Mainstay Contacts will be immediately forwarded to the corresponding Salesforce records, including creating new records.
Review the Installation section to ensure the necessary authentication keys have been shared between the two platforms.
FIELD MAPPINGS
In this section, you can customize which Salesforce objects are synced, and for each one, which fields and Mainstay Contact Attributes will be mapped. By default, only a few basic fields will be mapped.
-
To add a new Salesforce Object Mapping, click New SObject Mapping and select a standard or custom Salesforce Object.
-
The Record Sync Criteria indicates which Boolean (true/false) field is used to determine whether a Contact will sync with this Salesforce Object. Note that this can also be a Formula Field that outputs true or false. If this is left blank, then all contact records will be eligible for syncing.
-
Use the Create Unmatched Records checkbox to determine how to handle incoming contact records from Mainstay who do not already have a corresponding match in Salesforce. (See below for customizing the matching logic.) If this is checked, unmatched records will be created as new records in Salesforce. If this is not checked, then unmatched records will be ignored.
-
To add a field mapping for this Salesforce object, click New Field Mapping.
- Select the Salesforce field from the left column.
- Select the Mainstay field from the right column. Any custom fields you have created on Mainstay will appear in this list. (See Contact Fields Manager.)
- Use the Matching checkbox to determine if this field should be considered when looking for existing Salesforce records whenever a new Contact record is sent from Mainstay to Salesforce. At least one field must be set for Matching.
- Note that some Mainstay fields cannot be overwritten by data from Salesforce, such as the Mainstay ID or the contact's Created At date.
- Similarly, Salesforce formula fields cannot be overwritten by data from Mainstay, since they are computed from a formula. This allows you to configure read-only fields to send data from Salesforce to Mainstay.
- Note that the Salesforce ID is automatically mapped to Mainstay's "CRM ID" field.
- To edit or delete a field mapping, click the dropdown arrow on the right side.
INITIAL SYNC
In this section, you have the option to batch import and export records. It is recommended that you run this after creating the field mapping. Note that each batch import may take several minutes.
-
Import all Contacts from Mainstay: this will match existing Mainstay Contacts to existing Salesforce records based on your matching criteria.
- If a match is found, the Mainstay Contact will acquire the Salesforce CRM ID.
- Otherwise, you have the option (in Fields Mapping) to create new Salesforce records. The Mainstay Contact would then acquire the new Salesforce record's CRM ID.
-
Export all Contacts to Mainstay: this will match existing Salesforce records to existing Mainstay Contacts based on the individual's Salesforce CRM ID and mobile phone.
- If a match is found using CRM ID, the Mainstay Contact will be updated.
- If a match is found using phone, the Mainstay Contact will acquire the Salesforce CRM ID.
- If no match is found, a new Mainstay Contact will be created, with the Salesforce CRM ID.
- See Error Dictionary below for other common situations.
Logging
SYNC STATUS
"Latest Sync": This field will indicate the date, time, status, and Salesforce record that was last updated with changes sent to Mainstay.
SYNC RESULTS
Visit this tab to view a history of all Sync Results, including:
- a link to a more detailed view for the individual Sync Result
- a link to the Salesforce record
- a status (Success / Fail)
- if the status is Fail, an explanation
If you encounter data validation errors while importing contact records, visit Error Dictionary below to better understand next steps.
Pro tip: You can delete all Sync Logs in the Salesforce Developer Console with the following command:
delete [select id from admithubsync__SyncResult__c];
Conversations & Campaigns
It is also possible to view Mainstay Conversations for any given Contact by viewing the corresponding Salesforce record, as well as a list of all Campaigns the Contact received.
- On Salesforce, click "Setup" in the top menu.
- In the Quick Find box, search "Lightning App Builder".
- If you already have a Lightning Page for viewing Contact records, select that. Otherwise, click "New" above the Lightning Pages table and follow the creation wizard:
- Select "Record page" from the left sidebar of the "Create a new Lightning page" pop-up.
- In the Label field, enter a name, such as "Contact".
- In the Object field, enter "Contact".
- Select the desired layout.
- Recommended: CLONE SALESFORCE DEFAULT PAGE > "Contact Grouped View Default"
- Once in the Lightning App Builder, select the section of the page where you would like to add Mainstay Conversations.
- Recommended: add a new tab in the Activity / Chatter widget, named "Mainstay Conversations" or "Mainstay Campaigns"
- On the left side bar of Components, scroll to the bottom and drag the "Mainstay Contact Messages" into your desired section / tab, which should read: "Add component here."
- Click "Activate" in the top-right corner.
-
Recommended: Assign as Org Default.
-
Recommended: Assign as Org Default.
-
Navigate to an individual Contact page in any app (such as Sales) and you will now see the Mainstay Conversations and/or Mainstay Campaigns for this record.
- Conversations: Incoming (student) messages will appear left-aligned.
- Conversations: Outgoing (bot / campaign) messages will appear right-aligned.
- Campaigns: Displayed information includes the Script Name, Type, Status, and Time Sent.
Troubleshooting
If you are experiencing permissions errors, such as
System.QueryException: Insufficient permissions: secure query included inaccessible field
when using TargetX or similar add-ons, try granting the following permissions:
-
SyncResult__c - read, create; edit for all fields
-
SyncMapping__c - read; read for all fields
-
AppLogs__c - read, create; edit for all fields
-
AppLogEvent__e - read, create
Version 2.0+ (July 2023)
As of July 2023, Mainstay Sync for Salesforce v2 introduces an overhauled UX and many new features. (The installation process has not changed; please see above.)
Mainstay Sync Settings
This tool's main tab, Mainstay Sync Settings, includes several collapsible sections.
CONNECT TO MAINSTAY
Use this section to connect to Mainstay using an API token. Refer to the "Installation" section at the top of this article.
MAINSTAY FIELDS TYPES
After you first install this package, and any time you edit custom fields, click Refresh from Mainstay to load in all of your contact fields.
The table below shows the name and data-type of each field, as well as an indicator for custom fields and an indicator for deprecated fields. The standard fields include all information accessible via the Mainstay API.
This table also includes all custom fields you've configured in the Contact Fields Manager.
SYNC STATUS
In this section, you can independently control the direction of data:
- Sync Salesforce → Mainstay: if enabled, any changes you make to Salesforce records will be immediately forwarded to the corresponding Mainstay Contacts, including creating new Contacts.
- Sync Mainstay → Salesforce: if enabled, any changes you make to Mainstay Contacts will be immediately forwarded to the corresponding Salesforce records, including creating new records.
If you upgrade from a previous package version, please turn toggle these off and on again to reset the state.
Below these toggles, you'll see the last sync's timestamp, status, and details (as a link to the Sync Result).
The Clear All Sync Results button will delete all Sync Results. USE WITH CAUTION. This is only advised if Sync Results are becoming a storage concern.
FIELDS MAPPING
This section is used to configure the core integration, which is in effect for both the ongoing real-time syncing and the manual bulk syncing.
Use New SObject Mapping to map to any SObject. The first time you select this object, you will need to Deploy Mainstay sync trigger for it, effectively making that object "known" to this integration.
Within each SObject mapping, you can configure a mapping for each direction.
Salesforce to Mainstay
- Record Sync Criteria: select any Boolean field (including a formula field) on this SObject. If the value is true, the record is eligible to sync to Mainstay, when triggered by an update or manual export.
- Include Field Deletions in Sync to Mainstay: control whether clearing a field on Salesforce sends a signal to Mainstay to clear out the corresponding field's value.
- Include all Fields in Sync to Mainstay: for syncs triggered by an update, control whether to include all fields in the mapping, or only the fields that have updated ("delta").
- Required Mapping indicates that this field must be included in your mapping.
Mainstay to Salesforce
- Record Sync Criteria: select any Boolean field (including a formula field) on this SObject. When a contact comes in from Mainstay, this field value will be computed. If the value is true, the changes will be taken (ie, fields updated); if not, the changes will be rejected.
- Create Unmatched Records: when a match is not found (based on your selected Matching criteria), control whether the integration will create a new Salesforce record.
- Matching Mapping indicates whether this field is used to find a match. Note that this is case-insensitive (so, if you were matching on first name, "james" would match to "James").
Add / Edit / Delete Field Mapping
Click the [v] button to Edit or Delete an existing mapping.
Click the Add Field Mapping button at the bottom of the table to add a new field mapping.
The mapping editor allows you to select both the Salesforce and Mainstay fields, and indicates the direction of the mapping. This uses the fields' data-types to indicate whether the mapping is valid or not. (A mapping will also be marked invalid if a field no longer exists.)
For a Mainstay → Salesforce mapping, this is also how you indicate if the field is used for matching.
Lookup Fields
When selecting a Salesforce SObject field, note that you can also select a "lookup" or "parent" field. For example, a Contact record might have a lookup field to an Account SObject, which might have a lookup field to another Account SObject.
- These lookup fields cannot be used as matching criteria in the Mainstay → Salesforce direction.
- In the Salesforce → Mainstay direction, if your mapping includes a lookup field, then when that parent object's field is updated, this will trigger a sync to Mainstay for all records that are referencing that parent object.
- If this is also mapped in the Mainstay → Salesforce direction, then child record A could update parent record X, which would cause child records B, C, D, etc. to update and therefore sync back to Mainstay. Use with caution!
- The first time you map to a field on a secondary object, you may have to Deploy Mainstay sync trigger for it, making that object "known" to this integration.
INITIAL SYNC
In this section, you have the option to batch import and export records. It is recommended that you run this after creating the field mapping. Note that each batch import may take several minutes.
-
Import all Contacts from Mainstay: this will match existing Mainstay Contacts to existing Salesforce records based on your matching criteria.
- If a match is found, the Mainstay Contact will acquire the Salesforce CRM ID.
- Otherwise, you have the option (in Fields Mapping) to create new Salesforce records. The Mainstay Contact would then acquire the new Salesforce record's CRM ID.
-
Export all Contacts to Mainstay: this will match existing Salesforce records to existing Mainstay Contacts based on the individual's Salesforce CRM ID and mobile phone.
- If a match is found using CRM ID, the Mainstay Contact will be updated.
- If a match is found using phone, the Mainstay Contact will acquire the Salesforce CRM ID.
- If no match is found, a new Mainstay Contact will be created, with the Salesforce CRM ID.
- See Error Dictionary below for other common situations.
Sync Results
The Sync Results tab includes logging and data validation results for both successful and failed syncs (triggered by data updates). This tab does not include logging for manually triggered bulk imports or exports.
Note: If you experience technical issues with the integration itself - not just data validation - try the App Logs tab, or contact Support.
Each Sync Result includes:
- Sync Result Name: an incrementing numerical id
- Direction: SF to Mainstay | Mainstay to SF
- Status: Success | Fail
-
Fail Message: the direct response from the Mainstay API and/or Salesforce integration
- Note that even an overall Success may have a Fail Message, such as an individual field with invalid data.
- See Error Dictionary below for more information.
- Request Endpoint: the HTTP method (GET, POST, PUT) and full URL used for this request
- Request Body: the full JSON sent to or received from Mainstay
- SObject Name & ID: the Salesforce record being synced
When troubleshooting, you can use the Resend Payload tool to send the exact same data to Mainstay to recreate the issue. You can even adjust the request without needing to change the actual Salesforce records.
Empty Fields
- Empty fields sending from Salesforce → Mainstay may appear as "UNSET" (this keyword triggers a field deletion on Mainstay).
- Empty fields sending from Mainstay → Salesforce (such as "UNSET" in a CSV import / contact panel, or clicking the (-) button for a custom field) will appear as null.
- See the "Tips" section of Importing Contacts for more details.
Conversations & Campaigns
You can view Mainstay Conversations and Campaigns for a Mainstay Contact by viewing the corresponding Salesforce SObject record.
SETUP
- On Salesforce, click Setup in the top menu.
- In the Quick Find box, search Lightning App Builder.
- If you already have a Lightning Page for viewing the SObject record, select that. Otherwise, click New above the Lightning Pages table and follow the creation wizard.
- Once in the Lightning App Builder, select the section of the page where you would like to add Mainstay Conversations.
- On the left side bar of Components, search for "Mainstay" and select either Mainstay Contact Campaigns or Mainstay Contact Messages. Drag it into your desired section / tab.
- Optionally change the Id Field API Name to a different SObject, ie, a "parent"/"lookup" object.
- Click Activate in the top-right corner.
- Recommended: Assign as Org Default.
- Navigate to an individual record and you will now see the Mainstay Conversations and/or Mainstay Campaigns for this record.
CONVERSATIONS
- Count, Incoming, Outgoing: the number of messages exchanged with this contact
-
message types: each outgoing message (on the right) displays information explaining why the message was sent:
- Live Chat: {user info}
- AI: {topic}
- Campaign: {campaign name}
- Other (such as default messages)
- timestamp: hover over any message to see when it was sent
CAMPAIGNS
At the top of the component is an overall Count of Campaigns received.
Displayed information includes each Campaign's Script Name, Type, Status, and Time.
Advanced Settings
The integration also allows for a few additional configurations, which are available in "Custom Settings".
The Sync Method custom setting field allows you to choose how sync operations to Mainstay are initiated from the sObject trigger. You can set this field to one of two values:
-
PLATFORM_EVENT:
- The main logic for syncing to Mainstay is triggered by publishing a platform event from the sObject trigger.
- This option is suitable when there are asynchronous updates for sObjects configured in the mapping.
- It leverages the limits allocated to the publishing and delivery of platform events.
-
QUEUEABLE:
- The main logic for syncing to Mainstay is initiated by enqueuing a Queueable job from the sObject trigger.
- This option is appropriate when there are no asynchronous updates for the sObjects configured in the mapping.
CHANGE LOG
- 2.207 (February 11, 2024)
- standardize enable/disable toggle
- 2.300 (February 18, 2024)
- use FIFO sync queue for Salesforce --> Mainstay updates
- 2.301 (July 10, 2024)
- allow mapping for last_modified_at
- fix Campaign widget for contacts with 20+ Campaigns
- 2.302 (October 5, 2024)
- fix "too many queueable jobs" error
- fix "attempt to de-reference a null object" error
- allow sync triggers to publish Platform Event for processing records
- allow disconnecting the package from Mainstay
- 2.303 (November 20, 2024)
- if mapping to a parent object's formula field, when that value updates, trigger a sync
- 2.304 (May 20, 2024)
- fix for hitting the Salesforce Apex CPU Limit for contacts with many fields
Error Dictionary
For import errors encountered in manual CSV uploads, see Import Error Dictionary.
"Request would update contact's phone and create a duplicate record w/ this unique ID. This update failed to prevent contact duplication."
- Code: "duplicate-contact"
- Failure type: complete
- Explanation: A PUT request was issued to update a contact who was identified by CRM ID in Mainstay, but the phone in the payload matches to a different existing contact in Mainstay.
"Not found."
- Code: "not-found"
- Failure type: complete
- Explanation: A PUT request was issued to update a contact with a CRM ID or a phone number, but that contact does not exist.
- Note: This error will happen often, and it isn't really an issue. The integration first tries a PUT request matching on CRM ID, then a PUT request matching on phone, and then a POST request to create a new contact. So if the corresponding record doesn't exist in Mainstay at all, you may see this twice, and then a successful create (POST).
"Contact w/ provided phone already exists. Use PUT method to update contacts instead of POST to create."
- Code: "duplicate-contact"
- Failure type: complete
- Explanation: A POST request has been issued to create a contact, but the phone in the payload matches to an existing contact in Mainstay.
- Note: This error should be very rare due to the integration's order of operations. Specifically, it first tries a PUT request matching on CRM ID, then a PUT request matching on phone, and then this POST request to create a new contact.
"Contact w/ provided CRM ID already exists. Use PUT method to update contacts instead of POST to create."
- Code: "duplicate-contact"
- Failure type: complete
- Explanation: A POST request was issued to create a contact, but a contact with the same CRM ID already exists in Mainstay.
- Note: This error should be very rare due to the integration's order of operations. Specifically, it first tries a PUT request matching on CRM ID, then a PUT request matching on phone, and then this POST request to create a new contact.
"Request would update contact's CRM ID and create a duplicate record w/ this unique ID. This update failed to prevent contact duplication."
- Code: "duplicate-contact"
- Failure type: complete
- Explanation: A PUT request was issued to update the contact's CRM ID to a CRM ID already taken by another contact.
- Note: This error should not be possible because it necessitates that a contact exists in Mainstay with a CRM ID that matches the ID from the Salesforce payload. If that is the case, the PUT request would match to that existing contact and not update the CRM ID.
"Contact-to-update's previousPhone matches provided phone number. This update failed in order to prevent reverting a previous phone number update."
- Code: "contact-out-of-sync"
- Failure type: partial
- Explanation: A PUT request was issued to update a contact, and the matching contact’s _previousPhone in the Mainstay DB matches the phone in the payload. In this case, the phone is removed from the payload and we still attempt to update the matching contact per all other data in the payload.
"Request would match to an existing contact on phone and update the CRM ID. This update failed in order to prevent errant CRM ID update."
- Code: "phone-match-found-but-crmId-mismatch"
- Failure type: complete
- Explanation: A PUT request was issued to update a contact who is identified by phone but has a CRM ID in Mainstay that differs from that in the request payload. We prevent the update entirely in order to prevent updating this unique identifier.
"Invalid phone provided."
- Code: "invalid-phone"
- Failure type: complete if from POST request to create contact, partial if from PUT request to update contact
- Explanation: phone in request payload is not valid (too short, too long, invalid area code, etc…)
"Invalid attribute value type"
- Code: "invalid-attribute-data: [field name here]"
- Failure type: partial
- Explanation: At least one value in the "custom" section of the payload cannot be cast to the data_type of the corresponding Contact Attribute.
"Invalid messaging_status"
- Code: "invalid-messaging-status"
- Failure type: partial
- Explanation: This error pertains to the "messaging_status_sms" and "messaging_status_web_bot" fields. The only valid values are (case insensitive): 'opted-in', 'opted-out', 'opted in', 'opted out', and 'paused'.
- Note: This could be due to the request containing a messaging status field for a channel the contact does not have (ie, setting SMS status but the contact has no phone number). Or it could be an attempt to set a status for a channel the institution does have enabled (ie, no bot phone number).
- Note: It is also not possible to opt a contact back in who has opted out. The learner must message in "START".
- Note: It is also not possible to set a contact to be paused. The learner must message "#pause".
"Values too long in the following custom fields: [custom fields listed here]
- Code: "custom-values-too-long"
- Failure type: partial
- Explanation: Custom field values cannot exceed 1000 characters in length.
"Row # [row number here]: invalid email"
- Code: "invalid-email"
- Failure type: partial
- Explanation: The email value is not a valid email address.
"Row # [row number here]: invalid preferred name"
- Code: “invalid-preferred-name”
- Failure type: partial
- Explanation: A PUT request is issued which would change the contact’s Preferred Name value. This is only permitted if the value was blank; otherwise, the learner can change it via #changename.
"Row # [row number here]: invalid language"
- Code: "invalid-language"
- Failure type: partial
- Explanation: The language value is not a valid two-letter language code.
Comments
0 comments
Article is closed for comments.