> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getomni.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Salesforce

> Connect Salesforce CRM to Omni for search, permissions, actions, and MCP tools

The Salesforce connector indexes CRM records into Omni with Salesforce's sharing model mirrored into document permissions. It also exposes native CRM actions and the official Salesforce MCP server, so the assistant can both search indexed records and act on Salesforce live with the signed-in user's own Salesforce identity.

## Overview

### What We Sync

| Object        | Content                                                                           |
| ------------- | --------------------------------------------------------------------------------- |
| Accounts      | Company profile, industry, billing location, revenue, and owner                   |
| Contacts      | Name, email, phone, title, department, and parent account                         |
| Opportunities | Amount, stage, close date, probability, type, lead source, and parent account     |
| Leads         | Name, company, status, industry, lead source, and owner                           |
| Cases         | Case number, subject, status, priority, type, origin, related account and contact |
| Tasks         | Subject, status, priority, activity date, and related records                     |

Alongside those records the connector syncs the directory data needed to resolve permissions — `User`, `Group`, `GroupMember`, and `UserRole` — and the per-object share tables (`AccountShare`, `ContactShare`, `OpportunityShare`, `LeadShare`, `CaseShare`). Deletions are reconciled from Salesforce's deleted-records API.

<Note>
  Accounts, contacts, and the other CRM records are indexed as documents, not as people-directory entries. Salesforce users are synced into the people directory, so to look someone up by name, email, or title, ask the assistant in chat — it queries the directory with its `search_people` tool.
</Note>

### How It Works

1. The native connector authenticates to your org with an **External Client App JWT bearer flow** using a dedicated integration user. It mints and refreshes its own short-lived access tokens — no password or security token is required.
2. Records and their share metadata are synced, and Salesforce's ownership, role-hierarchy, sharing-rule, and public-read semantics are translated into Omni permissions.
3. The companion **MCP OAuth client** is what lets users **act on Salesforce through Omni** rather than only search it. It is configured once per Salesforce source, and each Omni user then authorizes their own Salesforce account so the assistant can make live MCP/API calls against the org with that user's own Salesforce identity and permissions — for example running an ad-hoc SOQL query that the synced records can't answer, or invoking the write-capable tools enabled for the source. MCP never falls back to the org JWT credential, so a user who hasn't authorized Salesforce has no MCP access.

## Permissions

Omni mirrors four Salesforce visibility mechanisms:

| Mechanism                           | Behavior in Omni                                                                                                                                                       |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Record ownership**                | The owner is granted. When a record is owned by a queue, the queue's members are granted                                                                               |
| **Role hierarchy**                  | When *Grant Access Using Hierarchies* is enabled, users in **ancestor** roles of the owner's role are granted. Peers in the owner's role and subordinate roles are not |
| **Sharing rules and manual shares** | Rows in the per-object `*Share` tables grant access to a user, a public group, or a role (role shares include descendants)                                             |
| **Org-wide defaults**               | Only objects listed as public-read grant everyone; everything else is private by default                                                                               |

Only Salesforce users that are active and have an email address receive grants. Group and role membership is expanded through nested groups with cycle protection, and records owned by a role group no longer grant stale memberships.

The connector ships with four settings enabled by default that affect permission resolution: `sync_users`, `sync_groups`, `sync_shares`, and `grant_access_using_hierarchies`. Groups and share resolution require user data, so disabling `sync_users` also disables sharing and hierarchy resolution. These are stored on the source configuration.

<Warning>
  If the integration user cannot read `User.UserRoleId`, role hierarchy and role-based sharing cannot be resolved and sync fails with `Required User fields are not queryable: UserRoleId`. See [Troubleshooting](#troubleshooting).
</Warning>

## Prerequisites

Before setting up the Salesforce connector:

* **Omni version** with the Salesforce connector service running (Compose profile or connector name: `salesforce`)
* **Salesforce administrator access** to create a user, generate a certificate, and create an External Client App
* **A reachable Omni callback URL** for the per-user OAuth flow (HTTPS for non-local deployments)
* **A secure location for the RSA private key** — never commit it or paste it into tickets or chat

## Setup

### Step 1: Create a dedicated Salesforce integration user

The native connector should not depend on an individual employee's password or OAuth session.

1. In Salesforce, open **Setup → Users → Users** and select **New User**.
2. Create a dedicated user, for example `Omni Salesforce Integration`.
3. Use a **full Salesforce user license** for the sync user. The **Salesforce Integration** user license cannot be granted role-hierarchy or user-visibility permissions, which breaks native sync.
4. Keep the user active and note its username — you'll enter it in Omni.

<Warning>
  A sync user on the Salesforce Integration license cannot resolve `UserRoleId`/`UserRole`, so sync fails by default. Use a full Salesforce user license and grant access with the permission set below.
</Warning>

### Step 2: Grant the connector read access

Grant the missing object and system permissions with a permission set:

1. **Setup → Users → Permission Sets → New**. Label it e.g. `Omni Connector Read`. Leave **License** empty and save.
2. **Object Settings → Edit** for each of `Account`, `Contact`, `Opportunity`, `Lead`, `Case`, and `Task`, and enable **Read** and **View All Records**.
3. **System Permissions → Edit** and enable `API Enabled`, `View All Data`, `View Roles and Role Hierarchy`, and `View All Users`.
4. **Users → the integration user → Permission Set Assignments** and add the permission set.

The `...Share` objects (`AccountShare`, `ContactShare`, `OpportunityShare`, `LeadShare`, `CaseShare`) do not appear in Object Settings and cannot be granted individually. The connector reads them for per-document ACLs, so access must come from the parent object's **View All Records** plus the **View All Data** system permission.

<Accordion title="If you must stay on the Salesforce Integration license">
  The Salesforce Integration user license rejects several permissions the connector's default configuration needs (`View Roles and Role Hierarchy`, `View All Users`, and `View All Data`), and cannot read `UserRoleId`. In that case, configure the source to skip role and share resolution (`grant_access_using_hierarchies: false`, and `sync_shares: false` when the org uses role-based groups). Document permissions then fall back to record ownership and public grants, so share-based access is lost.
</Accordion>

### Step 3: Generate the JWT key pair

Generate an RSA private key and a matching self-signed public certificate outside the repository:

```bash theme={null}
umask 077
openssl genrsa -out privatekey.pem 2048
openssl req -new -x509 \
  -key privatekey.pem \
  -out server.crt \
  -days 3650 \
  -subj "/CN=Omni Salesforce Integration"
chmod 600 privatekey.pem
```

Keep `privatekey.pem` secret. Only the public certificate (`server.crt`) is uploaded to Salesforce.

### Step 4: Create the Salesforce External Client App

#### 4a. Create the app

1. In Salesforce, open **Apps → External Client Apps → External Client App Manager** and select **New External Client App**.
2. Set the app name to `Omni`, set the contact email, and keep the distribution state **Local** for an org-local app.

<Frame caption="Basic Information for the Omni External Client App">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-settings-basic.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=f8bef6eb5181c8b0fb2a782ebb8ff0fd" alt="External Client App Basic Information" width="1325" height="950" data-path="images/salesforce/salesforce-external-client-app-settings-basic.png" />
</Frame>

#### 4b. Set the callback URL and OAuth scopes

1. Enable OAuth and set the callback URL to your Omni OAuth callback, e.g. `https://your-omni-domain/api/oauth/callback`.
2. Add the OAuth scopes required for the integration:
   * **Access the identity URL service** (`id`, `profile`, `email`, `address`, `phone`)
   * **Manage user data via APIs** (`api`)
   * **Manage user data via Web browsers** (`web`)
   * **Perform requests at any time** (`refresh_token`, `offline_access`)
   * **Access unique user identifiers** (`openid`)
   * **Access Salesforce hosted MCP servers** (`mcp_api`)

<Frame caption="Consumer Key and Secret, callback URL, and selected OAuth scopes">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-settings-oauth.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=91fb31e8e749cf9bb7486cf60772b1bd" alt="External Client App OAuth settings and scopes" width="1325" height="690" data-path="images/salesforce/salesforce-external-client-app-settings-oauth.png" />
</Frame>

#### 4c. Enable the flows and upload the certificate

In **OAuth settings → Flow Enablement**, enable **Authorization Code and Credentials Flow** for per-user OAuth and **JWT Bearer Flow** for the native connector, then upload the public certificate generated in step 3.

<Frame caption="Flow Enablement with the JWT bearer certificate uploaded">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-settings-flows.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=2c7b6bfd66e62024fbec7e192a9abbbc" alt="External Client App flow enablement and certificate" width="1325" height="320" data-path="images/salesforce/salesforce-external-client-app-settings-flows.png" />
</Frame>

Under **Security**, keep **Require Proof Key for Code Exchange (PKCE)**, refresh-token rotation, JWT-based access tokens for named users, and Salesforce's enforced idle refresh-token limit enabled.

<Frame caption="Security settings for the External Client App">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-settings-security.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=e35bd2f630ab07e876662368ed40e641" alt="External Client App security settings" width="1325" height="595" data-path="images/salesforce/salesforce-external-client-app-settings-security.png" />
</Frame>

#### 4d. Configure the authorization policy

Open the **Policies** tab and configure the permitted profiles. **Admin approved users are pre-authorized** is recommended; add the profiles that may authorize the app, including the sync user's profile.

<Frame caption="App Policies with pre-authorized profiles">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-policies-profiles.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=59c7548b9b7eae8ca3cbc341f0208515" alt="External Client App profiles policy" width="1255" height="955" data-path="images/salesforce/salesforce-external-client-app-policies-profiles.png" />
</Frame>

#### 4e. Set the permitted-user OAuth policy

In **OAuth Policies → Plugin Policies**, keep the **Permitted Users** policy aligned with your organization's security requirements and leave the **OAuth Start URL** empty unless the org has a specific start page.

<Frame caption="OAuth Policies with the permitted-user policy">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-policies-oauth.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=00527a7727a03956c558d9af932648d5" alt="External Client App OAuth policies" width="1255" height="315" data-path="images/salesforce/salesforce-external-client-app-policies-oauth.png" />
</Frame>

#### 4f. Review app authorization

Under **App Authorization**, confirm the refresh-token policy and validity, IP relaxation, and named-user JWT settings match your organization's requirements.

<Frame caption="App Authorization settings">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/salesforce-external-client-app-policies-authorization.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=88f3b83e65b3bdbb21705baca7b85f84" alt="External Client App authorization settings" width="1255" height="570" data-path="images/salesforce/salesforce-external-client-app-policies-authorization.png" />
</Frame>

After saving, open **Consumer Key and Secret** and copy the values into a secure password manager or deployment secret store. Do not commit them or include them in screenshots.

### Step 5: Connect the Salesforce source in Omni

1. Open **Settings → Integrations** and select **Connect** for Salesforce.
2. Choose **External Client App (JWT)** and enter:
   * **Consumer Key**: the External Client App's client ID
   * **Private Key (PEM)**: the RSA private key from step 3
   * **Username**: the dedicated integration user
   * **Login URL**: `https://login.salesforce.com` for production or `https://test.salesforce.com` for a sandbox
   * **Instance URL**: the exact Salesforce instance URL, used to bind the source to the intended organization
3. Select **Connect**, leave the source enabled, and choose a sync interval.

<Frame caption="Salesforce source settings">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/omni-salesforce-source-settings.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=710e21e994277f0e2a2701d66bde2d80" alt="Omni Salesforce source settings" width="1270" height="803" data-path="images/salesforce/omni-salesforce-source-settings.png" />
</Frame>

Once connected, Salesforce appears under **Organization Integrations** as an enabled source with **Sync** and **Settings** controls:

<Frame caption="Salesforce listed as an enabled source in the integrations list">
  <img src="https://mintcdn.com/omni-32b875be/K0DyB4CZIl4XMOwj/images/salesforce/omni-integrations-salesforce.png?fit=max&auto=format&n=K0DyB4CZIl4XMOwj&q=85&s=7c2d2f1ef3066002f1bc02c53d493b40" alt="Omni integrations list with Salesforce" width="1280" height="298" data-path="images/salesforce/omni-integrations-salesforce.png" />
</Frame>

<Tip>
  An **Access Token** mode is also available for quick trials. It accepts a static session or OAuth access token, expires within hours, and cannot be used for MCP — MCP requires an External Client App.
</Tip>

### Step 6: Configure the source-scoped MCP OAuth client

MCP OAuth is configured separately from the native JWT source credentials:

1. From the Salesforce source settings page, select **Configure MCP OAuth client**.
2. Enter the External Client App's **Client ID** and **Client Secret**.
3. Leave the **DCR initial access token** blank when using a pre-created External Client App. Salesforce Dynamic Client Registration is an alternative that requires an administrator-issued initial access token.
4. Save the configuration.

The MCP client is stored for this Salesforce source only. It is not an org-wide credential and is not shared with other Salesforce sources. Until it is configured, Salesforce MCP tools do not appear in chat.

### Step 7: Authorize each user's Salesforce MCP access

Every Omni user who uses Salesforce MCP tools authorizes Salesforce separately:

1. Start an MCP action from an Omni chat, or use the Salesforce authorization action when Omni presents it.
2. Follow the Salesforce OAuth redirect and sign in as the intended Salesforce user.
3. Complete any identity verification or MFA Salesforce requests, approve the scopes, and return to Omni through the callback.

The resulting credential is stored for the combination of Omni user and Salesforce source. If it is missing, revoked, expired, or belongs to another Salesforce org, MCP access fails closed and asks for authorization again.

## Managing the Integration

Changing the synced objects, fields, or permission-affecting settings forces a full reconciliation on the next run, which removes stale permissions and attributes.

### Search Operators

Once the source is running, these operators work in Search and Chat:

| Operator       | Meaning                              |
| -------------- | ------------------------------------ |
| `owner:`       | Filter by the record owner           |
| `status:`      | Filter by case, lead, or task status |
| `priority:`    | Filter by case or task priority      |
| `stage:`       | Filter by opportunity stage          |
| `account:`     | Filter by related account name       |
| `industry:`    | Filter by industry                   |
| `lead_source:` | Filter by lead source                |

### Native Actions

These actions use the org JWT credential and are available to the assistant:

| Action               | Mode  | Purpose                                                                             |
| -------------------- | ----- | ----------------------------------------------------------------------------------- |
| `find_records`       | Read  | Search accounts, contacts, opportunities, leads, cases, or tasks by name or subject |
| `get_case`           | Read  | Fetch a case by ID, including status, priority, and description                     |
| `create_case`        | Write | Create a case with optional status, priority, type, origin, and related records     |
| `update_case_status` | Write | Update a case's status and optionally its priority                                  |
| `create_task`        | Write | Create a task with optional due date and related records                            |
| `update_task_status` | Write | Update a task's status                                                              |

Write actions require confirmation in interactive chat and respect the source's read-only policy and any action authorization configured for the deployment.

### MCP Tools

Salesforce MCP tools run through Salesforce's official MCP server using each user's own OAuth credential, so results respect that user's Salesforce permissions. The connector exposes the read-only catalog it enables — `get_username`, `list_all_orgs`, and `run_soql_query`. Any other discovered tool is classified as write and is withheld unless write authorization is granted for the source.

A typical request asks for a specific tool and SOQL explicitly:

```text theme={null}
Use the Salesforce MCP run_soql_query tool, not indexed search, to run
SELECT Id, Name FROM Account LIMIT 5 and list the accounts.
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Native sync fails with sObject type 'Account' is not supported">
    The integration user's profile or permission set does not expose the CRM objects. Grant **Read** and **View All Records** on `Account`, `Contact`, `Opportunity`, `Lead`, `Case`, and `Task` as described in [Step 2](#step-2-grant-the-connector-read-access). MCP success does not prove native sync works — they use separate credentials.
  </Accordion>

  <Accordion title="Sync fails with Required User fields are not queryable: UserRoleId">
    The sync user cannot read role data. `View Roles and Role Hierarchy` is required whenever `grant_access_using_hierarchies` is enabled (the default) or role-based sharing is in effect. The Salesforce Integration user license rejects this permission — authenticate native sync as a user with a full Salesforce license, or disable hierarchy and share resolution.
  </Accordion>

  <Accordion title="MCP tools do not appear in chat">
    Confirm the source-scoped MCP OAuth client is configured (client ID and secret) and that the signed-in user has authorized Salesforce. A missing, revoked, or expired per-user credential fails closed and must be re-authorized.
  </Accordion>

  <Accordion title="MCP authorization fails or binds the wrong org">
    The source's **Instance URL** and login URL must match the org the user is authorizing. The connector validates that the OAuth credential's instance belongs to the same Salesforce organization as the source.
  </Accordion>

  <Accordion title="Records are missing after a permission change">
    Permission and share changes are reconciled on sync. Trigger a manual sync after changing profiles, permission sets, roles, or sharing rules, and confirm the run completes without errors.
  </Accordion>
</AccordionGroup>

## Security Considerations

* **Separate identities**: native sync and native actions use the org JWT credential; MCP tools use each user's own OAuth credential. The org JWT is never an MCP fallback.
* **Least privilege**: limit the integration user's object and system permissions to what Omni must sync.
* **Secret handling**: never commit the private key, consumer secret, access tokens, refresh tokens, or MFA codes, and never capture the Consumer Key and Secret page.
* **Credential storage**: source credentials and per-user OAuth credentials are encrypted at rest in Omni.
* **Read-only option**: the source can be set read-only, which removes write-capable actions including write-classified MCP tools.
* **Rotation**: revoke and recreate credentials in both Salesforce and Omni if a secret is exposed.

## What's Next

<CardGroup cols={3}>
  <Card title="Search Your Data" icon="magnifying-glass" href="/user-guide/search">
    Search CRM records alongside your other sources
  </Card>

  <Card title="Access Control" icon="shield" href="/user-guide/access-control">
    Understand how Salesforce sharing becomes Omni permissions
  </Card>

  <Card title="Connector Management" icon="gear" href="/admin/connector-management">
    Monitor syncs and manage the source
  </Card>
</CardGroup>
