Skip to main content

Upgrading your Salesforce connection to use the External Client App and support BYOC

Step-by-step guide to upgrade your Salesforce connection with Fin to use the External Client App and move from Enhanced Chat to BYOC.

Bring Your Own Channel (BYOC) is a new way for Fin customers to enable Fin Messenger as their live-chat AI Agent. Connecting via BYOC rather than Enhanced Chat brings improvements in the way that the messenger handles certain user behaviours, such as concurrent conversations across multiple tabs, so that you can continue to enjoy Fin's best-in-class service. Migration is simple, making use of test environments before rolling out to production without causing any downtime. Follow the guide below to implement on your workspace.

Use this article to upgrade your existing Fin for Salesforce connection to use the new External Client App (ECA). This guide is for Salesforce admins migrating an existing Fin for Salesforce deployment — you'll need Salesforce admin access and an active Fin for Salesforce subscription. By the end, you'll have installed the required managed packages, connected via the new ECA, configured permissions, and — if you use Fin Messenger — established a live-chat connection between Fin and Salesforce via Bring Your Own Channel (BYOC), Salesforce's standard channel integration framework for connecting third-party messaging providers.

There are 6 steps involved:

  1. Connect to Salesforce via the External Client App

  2. Set up permissions

  3. Switch to using External Client App credentials

  4. Run the Apex migration script

  5. Uninstall the deprecated package and disconnect the Connected App

  6. Update your Fin Messenger deployment [optional]

Note: If you're setting up Fin to handle Salesforce cases only (no messaging), you can skip the Updates to Fin Messenger section below.


Step 1: Connect to Salesforce via the External Client App

Go to Connect in your Fin workspace, then click on the Bring Your Own Channel tab.

This serves as the migration tab for moving to the new External Client App (ECA) — an OAuth 2.0 client credentials-based authentication method that replaces the legacy Connected App (an older OAuth-based integration that required storing user credentials).

You will see your existing connections listed as Not Connected in this tab. The connection status is with respect to the External Client App.

Follow the steps below to install a managed package in Salesforce. The managed package installs the External Client App, plus all the permissions and fields Fin needs to run.

  1. Click the Connect button, on any existing connection you want to connect (test or live), then click Install Package.

  2. Select Install for all users. This means the permission set can be assigned to any user in your Salesforce org if you choose.

  3. Wait for the installation to finish. No errors should be shown.

  4. Once installation is complete, return to the Connect page and click the Connect to Salesforce button in Step 2, then allow the connection to establish.


Step 2: Set up permissions

Go to Connect > External Client App (Tab) > Assign permissions in Salesforce from your Fin workspace and follow the steps there to create a new permission set and assign all the permissions Fin needs to run.

Create a new permission set

  1. In Salesforce, create a new permission set. The label and API name can be anything — this permission set will only be assigned to the integration user.

  2. When selecting a license, make sure to choose one that includes the Set Audit Fields upon Record Creation permission, for example, the Salesforce license. Some licenses don't include this permission.

  3. Save the new permission set.

The Salesforce New Permission Set screen, showing the License dropdown set to 'Salesforce' — the license type that includes the required 'Set Audit Fields upon Record Creation' permission.

Note: Not all Salesforce license types include the Set Audit Fields upon Record Creation permission. If this option isn't available for a license you're considering, select a different license type (such as the standard Salesforce license) that does include it.

Assign permission sets to the integration user

Both the existing Fin for Salesforce permissions permission set and the newly created permission set must be assigned to the integration user.

  1. In Salesforce, navigate to the integration user's profile.

  2. Go to Permission Set Assignments and click Edit Assignments.

  3. Add both the Fin for Salesforce permissions permission set and the newly created permission set to the Enabled Permission Sets column, then click Save.

The Salesforce Permission Set Assignments screen for the integration user, showing both 'Fin for Salesforce permissions' and the newly created permission set moved into the Enabled Permission Sets column.


Step 3: Switch to using External Client App credentials

You can switch to using the External Client App credentials for a Salesforce connection by toggling the Use External Client App credentials when managing a connection under Connect > External Client App (Tab).

Once switched on, Fin uses the External Client App credentials for all its requests to Salesforce, including:

  • Queries to get the status of the connection.

  • Creating a Salesforce case via the workflow step.

  • Creating a Salesforce case on Fin resolution or user inactivity.

  • Responding to case created via the Salesforce cases channel

  • Importing Knowledge articles

  • Importing historical Salesforce cases

Once switched on, you can switch it back off if you believe something is amiss. This lets you test in each environment — sandbox, UAT (user acceptance testing), and production — and gain confidence with the new ECA credentials, without disrupting the legacy Connected App credentials.

Once all connections have Use External Client App credentials switched on, the migration is complete. The connection status for each entry updates to Connected in the External Client App tab. Follow the steps below to migrate your data and clean up the deprecated package once you're satisfied that all systems are working as intended.


Step 4: Run the Apex migration script

When you install the Fin for Salesforce base managed package, it installs new Fin Case fields that are namespaced with finai. Namespacing means each field name is prefixed with finai__ (for example, finai__FinConversationId__c) to prevent naming conflicts with other packages or custom fields in your org.

As part of the migration, use the Apex migration script to move your existing case data from the older unnamespaced fields to the new namespaced fields. The Fin for Salesforce package includes a pre-built Apex class called FinCaseFieldMigrator.cls that handles the migration logic.

Apex inside a managed package resolves unqualified custom field names against its own namespace. A query for FinConversationId__c executed inside the finai package returns finai__FinConversationId__c instead, so packaged code cannot read the legacy fields at all, and naming both in one query fails outright with a duplicate field selected error. The migration fetch must therefore be executed from outside the package — that is why you need to add the classes below manually in your org. The classes themeselves hold no migration logic; it calls the migration class installed by the managed package and runs it in batches of 200 records at a time.

You'll add two Apex classes to your org, run the migration once, then delete both classes once no longer necessary:

  • FinCaseFieldMigration runs the migration.

  • FinCaseFieldMigrationTest is its test. Salesforce won't deploy Apex to production without a test, and this one also checks that your org is set up correctly before anything runs.

4a. Copy the two classes

FinCaseFieldMigration

public without sharing class FinCaseFieldMigration implements Database.Batchable<SObject>, Database.Stateful {

private final finai.FinCaseFieldMigrator migrator;

public FinCaseFieldMigration() {
this.migrator = new finai.FinCaseFieldMigrator();
}

public static Id run() {
return run(200);
}

public static Id run(Integer scopeSize) {
if (scopeSize == null || scopeSize < 1 || scopeSize > 2000) {
throw new IllegalArgumentException('scopeSize must be between 1 and 2000, got: ' + scopeSize);
}
return Database.executeBatch(new FinCaseFieldMigration(), scopeSize);
}

public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(migrator.queryString());
}

public void execute(Database.BatchableContext bc, List<SObject> scope) {
migrator.migrate(scope);
}

public void finish(Database.BatchableContext bc) {
migrator.report(bc.getJobId());
}
}

FinCaseFieldMigrationTest

@IsTest
private class FinCaseFieldMigrationTest {

private static final String LEGACY_FIELD = 'FinConversationId__c';
private static final String TARGET_FIELD = 'finai__FinConversationId__c';

// Absent legacy field means the old unlocked package was never installed here, so there is
// genuinely nothing to migrate and the test below has nothing to prove. Every other
// precondition is a misconfiguration and is asserted, so it fails the deploy rather than
// passing green on a migration that would silently copy nothing.
private static Boolean orgHasLegacyField() {
return Schema.SObjectType.Case.fields.getMap().containsKey(LEGACY_FIELD);
}

@IsTest
static void copiesLegacyDataOntoTheNamespacedField() {
if (!orgHasLegacyField()) {
return;
}
Map<String, Schema.SObjectField> fields = Schema.SObjectType.Case.fields.getMap();
System.assert(
fields.containsKey(TARGET_FIELD),
TARGET_FIELD + ' does not exist — install the finai managed package before this class'
);
System.assert(
fields.get(LEGACY_FIELD).getDescribe().isAccessible(),
'cannot read ' + LEGACY_FIELD + ' — the legacy permission set must stay assigned'
);
System.assert(
fields.get(TARGET_FIELD).getDescribe().isUpdateable(),
'cannot write ' + TARGET_FIELD + ' — assign finai__Fin_for_Salesforce_permissions'
);

Case seeded = new Case(Subject = 'fin case field migration test', Status = 'New');
seeded.put(LEGACY_FIELD, 'conv-under-test');
insert seeded;
Id seededId = seeded.Id;

Test.startTest();
FinCaseFieldMigration.run();
Test.stopTest();

SObject migrated = Database.query(
'SELECT Id, ' + TARGET_FIELD + ' FROM Case WHERE Id = :seededId LIMIT 1'
)[0];
System.assertEquals(
'conv-under-test',
migrated.get(TARGET_FIELD),
'the legacy value should have been copied onto the namespaced field'
);
}

@IsTest
static void runReturnsAJobId() {
Test.startTest();
Id jobId = FinCaseFieldMigration.run(50);
Test.stopTest();
System.assertNotEquals(null, jobId, 'run() should return the id of the batch job it queued');
}

@IsTest
static void runRejectsAScopeSizeOutsideTheBatchLimits() {
for (Integer scopeSize : new List<Integer>{ null, 0, 2001 }) {
try {
FinCaseFieldMigration.run(scopeSize);
System.assert(false, 'expected IllegalArgumentException for scopeSize ' + scopeSize);
} catch (IllegalArgumentException e) {
System.assert(
e.getMessage().contains('scopeSize must be between 1 and 2000'),
'unexpected message: ' + e.getMessage()
);
}
}
}
}

4b. Add the classes to your Salesforce organization

How you do this depends on which organization you're migrating.

Migrating a sandbox

  1. Go to Setup > Apex Classes and click New.

  2. Paste the FinCaseFieldMigration code and click Save.

  3. Click New again, paste the FinCaseFieldMigrationTest code, and click Save.

  4. Click Run All Tests, or open FinCaseFieldMigrationTest and click Run Test, and confirm it passes.

Migrating production with a change set (no command line needed)

Production orgs don't let you create Apex classes in Setup, so build them in a sandbox and deploy from there.

  1. In a sandbox connected to production, with the new package installed, create both classes as described above.

  2. In the sandbox, go to Setup > Outbound Change Sets and click New. Add both Apex classes and click Upload, choosing your production org as the target.

  3. In production, go to Setup > Deployment Settings and make sure your sandbox is allowed to send inbound changes.

  4. In production, go to Setup > Inbound Change Sets, open the change set, and click Deploy.

  5. Under Choose a Test Option, select Run specified tests, enter FinCaseFieldMigrationTest, and click Deploy.

Migrating production with the Salesforce CLI

Save each class as a .cls file in a case-field-migration/classes/ folder. Next to each one, add a .cls-meta.xml file with the same name (for example FinCaseFieldMigration.cls-meta.xml) containing:
​

<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<status>Active</status>
</ApexClass>

Then run:

sf project deploy start \
--source-dir case-field-migration \
--target-org <your-org-alias> \
--test-level RunSpecifiedTests \
--tests FinCaseFieldMigrationTest

What a successful deploy tells you: during the deploy, the test creates a temporary test Case, migrates it, and checks that the value arrived on the new field. Salesforce rolls the test data back afterwards. So a successful deploy means the migration already works in your org. If the deploy fails, the error message says why, for example a missing package or a missing permission set.

4c. Run the migration

  1. Go to Salesforce setup > Developer Console

  2. Click on Debug > Open Execute Anonymous Window

  3. Paste in the code below, Click Execute

    Id jobId = FinCaseFieldMigration.run();
    System.debug('Fin Case field migration job: ' + jobId);


    The migration processes 200 Cases per batch by default. If your org has Case triggers, flows or other automation that hit governor limits at that size, use a smaller batch size instead:

    FinCaseFieldMigration.run(50);

4d. Check the result

  • Setup > Apex Jobs shows the progress of the FinCaseFieldMigration job.

  • When the job finishes, the admin who started it gets a report email. It lists every Case that was skipped or failed, with the field and the reason.

Read the report rather than assuming the run worked. If a permission set was missing when you ran it, the job can finish "successfully" having copied nothing. The report will tell you which fields it skipped.

You can safely run the migration again. It only fills in new fields that are still empty, so a second run updates zero records.

What the migration doesn't do:

  • It doesn't delete or change anything on the old fields.

  • It can't be reversed.

  • The two checkboxes, Fin Involved and Fin Marked As Spam, are only copied when the old value is checked. An unchecked box can't be told apart from one that was never set, so it isn't copied. Either way, the new field ends up unchecked.

4e. Remove the classes

Once the report shows a clean run, delete both FinCaseFieldMigration and FinCaseFieldMigrationTest. Don't skip this: while these classes are in your org, Salesforce won't let you uninstall the Fin for Salesforce package.

  • Sandbox: go to Setup > Apex Classes and click Del next to each class.

  • Production: Apex can't be deleted through Setup in production, so use the Salesforce CLI.

    • In an empty folder, create destructiveChanges.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      <Package xmlns="http://soap.sforce.com/2006/04/metadata">
      <types>
      <members>FinCaseFieldMigration</members>
      <members>FinCaseFieldMigrationTest</members>
      <name>ApexClass</name>
      </types>
      </Package>

    • Then create a package.xml file in the same folder:

      <?xml version="1.0" encoding="UTF-8"?>
      <Package xmlns="http://soap.sforce.com/2006/04/metadata">
      <version>62.0</version>
      </Package>

    • From that folder, run:

      sf project deploy start \
      --manifest package.xml \
      --post-destructive-changes destructiveChanges.xml \
      --target-org <your-org-alias> \
      --test-level RunLocalTests

      This runs your org's existing tests, as any production deployment does. If it fails on a test that isn't FinCaseFieldMigrationTest, the problem is with that test, not the migration. Fix it the way you would for any other deployment.


Step 5: Uninstall the deprecated package and disconnect the Connected App

Once the new managed package is installed, all connections are switched to the ECA credentials, and the Fin Case field data has been migrated to the new namespaced fields, uninstall the previous unlocked or unmanaged package and revoke the legacy Connected App connection.

Unassign legacy PermissionSet

The legacy PermissionSet (a Salesforce object that grants users access to specific features and fields) must be unassigned before the package can be uninstalled.

  1. Go to Salesforce setup > Installed Packages

  2. Click on the Fin for Salesforce unlocked package

  3. Click on View Components

  4. Click on the Fin_for_Salesforce_permissions PermissionSet, this should take you to the PermissionSet page.

  5. Click on Manage Assignments

  6. Select all assigned Salesforce Users

  7. Click the Remove Assignment button

Uninstall package and save data

  1. Go to Salesforce setup > Installed Packages

  2. Click on Uninstall beside the Fin for Salesforce unlocked package

    The Salesforce Installed Packages page with the Fin for Salesforce unlocked package listed and an 'Uninstall' button visible to its right.
  3. Select Save a copy of this package's data for 48 hours after uninstall this will save all the case field data as a csv with a column for the Salesforce Case ID.

    Important: Salesforce retains the saved data export for 48 hours only after uninstallation. Download the CSV before that window closes. If you've already run the Apex migration script successfully, you won't need to restore from this file — but it's a useful safety net.

  4. Wait to get notified that the package uninstallation has been complete successfully.

  5. Revisit Salesforce setup > Installed Packages, you should see the uninstalled package listed under Uninstalled Packages.

  6. Click Data, this will download all the Case data as a csv stored within a zip file. Store this zip file safely as you could use it to restore data if required. But if you've run the Apex migration script you should be good to go.

    The Salesforce Uninstalled Packages list showing the Fin for Salesforce package with a 'Data' download link, used to download the saved CSV export of case field data within the 48-hour window.

Revoke Connected App connection

  1. Go to Salesforce setup > Connected Apps OAuth Usage

  2. Click on number link listed below the User Count column for the Fin for Salesforce Connected App. It will redirect you to Connected App User's Usage.

    The Salesforce Connected Apps OAuth Usage page showing the Fin for Salesforce Connected App with a numeric user count link in the User Count column, which opens the Connected App User's Usage screen.
  3. Click Revoke next to each user listed. This removes the OAuth access tokens stored as part of the legacy Connected App connection. Once revoked, those users no longer appear in the list.

    The Salesforce Connected App User's Usage screen showing individual user entries with a 'Revoke' action link next to each, used to remove the legacy OAuth access tokens.


Step 6: Update your Fin Messenger deployment

Follow these steps only if you intend on using Fin for Salesforce with Messaging.

This section explains how to connect Fin as a Bring Your Own Channel (BYOC) partner in Salesforce, and how to migrate existing Enhanced Chat handoff workflows to use BYOC instead.

Connect Fin to Bring Your Own Channel

To establish the BYOC connection between Fin and Salesforce, follow Step 1 of the Fin Messenger: Setting up with Salesforce article. That step walks you through creating a Messaging Channel, configuring the Event Relay, and activating the channel in Salesforce.

Once complete, you should have an active Messaging Channel with a running Event Relay — a Salesforce feature that streams real-time platform events, used here to pass messages between Fin and Salesforce — between Fin and Salesforce.

Hand-off to Salesforce agent

The Hand-off to Salesforce agent step in Fin Messenger workflows now supports toggling between BYOC and Enhanced Chat. This lets you control which channel the handoff uses while testing, so you can switch gradually without downtime.

The Fin Messenger workflow editor showing the 'Hand-off to Salesforce agent' step, with a toggle to switch between BYOC and Enhanced Chat handoff modes.

You can create multiple workflows with different audience & environment targeting to control what traffic goes through BYOC
​


Or you could leverage the Branches step in workflows with the Environment variable to direct it to a Hand-off to Salesforce agent step with BYOC turned on vs one with BYOC turned off (i.e Enhanced Chat)
​


FAQs

How long does the migration take?

The technical steps themselves typically take 1–2 hours. However, if you run the full testing cycle — sandbox first, then UAT (user acceptance testing), then production — allow 1–2 business days end to end. The main variable is how many Salesforce environments you validate in before going live.

Is there any downtime?

Downtime is not expected. The Use External Client App credentials toggle can be switched back off at any time if something looks wrong, and both Enhanced Chat and BYOC can run simultaneously during the transition.

Is there any additional Salesforce licences / add ons required?

For BYOC to work you need the Digital Engagement SKU with the Partner Messaging add-on license. One way to check if you have the relevant license in place is,

  1. Go to Salesforce setup > Company Information

  2. Check if you Partner Messaging User listed under Permission Set Licenses and the total licenses available.

Reach out to your Salesforce Account Executive (AE) if you are missing either the license or add-on to get them enabled for your Salesforce Organization.

Is there any risk of overwriting existing Salesforce data?

  • There is a risk around loss of data (specifically the Fin custom Case fields) when uninstalling the previous unlocked/unmanaged package.

  • However, that's mitigated by Running the Apex migration script and/or by downloading the Case data as part of uninstallation.

  • There's no risk associated with overwriting existing salesforce data with this migration specifically.


💡Tip

Need more help? Get support from our Community Forum
Find answers and get help from Intercom Support and Community Experts


Did this answer your question?