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

# ETL: Salesforce Source

> Configure the Salesforce source to read standard and custom objects using the Bulk API. Supports SOQL queries and incremental data loading.

## Connection Setup: Salesforce

Integrate.io ETL can read your Salesforce data. This article details creating the [Salesforce connection in Integrate.io ETL.](https://www.integrate.io/blog/salesforce-to-salesforce/) Note that Integrate.io ETL can only be used with [Salesforce](https://www.integrate.io/blog/category/salesforce/) editions that have API access. Some plan types, including trial versions, do not have API access by default and cannot be used with Integrate.io ETL.

<Frame>
  <iframe className="w-full aspect-video rounded-xl" src="https://fast.wistia.com/embed/iframe/0im55tkm3k" title="Allowing Integrate.io ETL access to my data on Salesforce" allow="autoplay; fullscreen" allowFullScreen />
</Frame>

### To create a Salesforce connection in Integrate.io ETL

<Steps>
  <Step>
    Click the **Connections** icon (lightning bolt) on the top left menu.
  </Step>

  <Step>
    To create a connection, click **New connection.**

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-238.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=fbb6c965dd0f2c8ea4f0c7ad920c3d8c" alt="Connections page with New connection button" width="1200" height="828" data-path="images/connectivity-and-security/image-238.webp" />
    </Frame>
  </Step>

  <Step>
    Select Salesforce.

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-239.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=67f7959ec10bdf72c59ed67550679eb1" alt="Selecting Salesforce from the connection type list" width="1200" height="828" data-path="images/connectivity-and-security/image-239.webp" />
    </Frame>
  </Step>

  <Step>
    Select the Salesforce environment you'd like to connect to - production or sandbox - and click **authorize**.

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-240.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=6ab5139af6e61d5a6c6ed6ffdceefbc4" alt="Salesforce environment selection with authorize button" width="1200" height="828" data-path="images/connectivity-and-security/image-240.webp" />
    </Frame>
  </Step>

  <Step>
    In the Salesforce login window, sign in with your Salesforce account. (Note: The user name for a sandbox account is your user name with a dot sandbox account name suffix. For example, If your user name is [danielle@ilovemycompany.com](mailto:danielle@ilovemycompany.com) and your sandbox account name is test, your user name for it is [danielle@ilovemycompany.com.test](mailto:danielle@ilovemycompany.com.test))
  </Step>

  <Step>
    In the next page, click "Allow" to allow Integrate.io ETL access on your behalf to Salesforce.
  </Step>

  <Step>
    In the new Salesforce connection window, name the connection and click **create salesforce connection.**

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-241.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=5ef252ba04b4d4559345c4cefbbecdee" alt="Naming the new Salesforce connection" width="1200" height="828" data-path="images/connectivity-and-security/image-241.webp" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-242.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=cf6b8775db8852ed04aceac254bc19d2" alt="Salesforce connection created successfully" width="1200" height="828" data-path="images/connectivity-and-security/image-242.webp" />
    </Frame>
  </Step>
</Steps>

### To modify Salesforce connections in Integrate.io ETL

<Steps>
  <Step>
    Click the **Connections** icon (lightning bolt) on the top left menu.
  </Step>

  <Step>
    Click a connection to open and modify it. Make any necessary changes, then click **Reconnect**, and **Save changes**. To exit the Salesforce connection window without changes, click **Back to connections** (grey tab on the left side) on the Salesforce connection window.
  </Step>

  <Step>
    To delete a Salesforce connection, click on the three vertical dots on the far right of the connection listing and select the **Delete connection** option.

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-243.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=9fb79fdcf58688d492d7814c3ebc3c0e" alt="Delete connection option in the three-dot menu" width="1200" height="828" data-path="images/connectivity-and-security/image-243.webp" />
    </Frame>
  </Step>
</Steps>

## Salesforce Apps Installation Restrictions (Oct 2025)

Salesforce recently introduced controls for **uninstalled connected apps**, which affect how users can approve third-party integrations like our ETL Salesforce connector. If a connected app isn't explicitly installed in a customer's Salesforce org, users without the proper permissions will encounter OAuth errors (such as `OAUTH_APPROVAL_ERROR_GENERIC`) during authentication. To fix this, customers must either install the connected app within their org or grant users the **"Approve Uninstalled Connected Apps"** permission through a profile or permission set. This permission allows users to authorize and connect to apps that aren't officially installed in their org.

For orgs that have **API Access Control** enabled, Salesforce replaces this with the **"Use Any API Client"** permission, which serves the same purpose. Support teams should advise customers to check their **Connected Apps OAuth Usage** page to confirm whether our ETL app appears as "uninstalled." If so, the Salesforce admin should either install it or assign one of the above permissions to affected users. This change ensures users can continue authenticating successfully with third-party apps like ours.

For more info, please check Salesforce article [here](https://help.salesforce.com/s/articleView?id=005132365\&type=1).

## Connection Setup: Salesforce (SOAP)

Integrate.io ETL can read your Salesforce SOAP data. This article details creating the Salesforce SOAP connection in Integrate.io ETL. Note that Integrate.io ETL can only be used with [Salesforce](https://www.integrate.io/blog/category/salesforce/) editions that have API access. Some plan types, including trial versions, do not have API access by default and cannot be used with Integrate.io ETL.

<Frame>
  <iframe className="w-full aspect-video rounded-xl" src="https://fast.wistia.com/embed/iframe/0im55tkm3k" title="Allowing Integrate.io ETL access to my data on Salesforce (SOAP)" allow="autoplay; fullscreen" allowFullScreen />
</Frame>

### To create a Salesforce SOAP connection in Integrate.io ETL

<Steps>
  <Step>
    Click the **Connections** icon (lightning bolt) on the top left menu.
  </Step>

  <Step>
    To create a connection, click **New connection.**

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-244.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=99db7e840cda5dabf29c31807eeac40c" alt="Connections page with New connection button for SOAP" width="1200" height="828" data-path="images/connectivity-and-security/image-244.webp" />
    </Frame>
  </Step>

  <Step>
    Select Salesforce (SOAP).

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-245.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=f6cdceea25a34d77610b944bf1a1b1a0" alt="Selecting Salesforce SOAP from the connection type list" width="1200" height="828" data-path="images/connectivity-and-security/image-245.webp" />
    </Frame>
  </Step>

  <Step>
    In the new Salesforce (SOAP) window, name the connection and enter the connection information.

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-246.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=4d5dac6fed811a24d9cc63e5ea9c7463" alt="Salesforce SOAP connection form with credential fields" width="1200" height="828" data-path="images/connectivity-and-security/image-246.webp" />
    </Frame>

    * **Name** - Name of the new connection
    * **Instance URL** - Your Salesforce SOAP Instance URL (Login Server URL)
    * **Username** - Your Salesforce SOAP Account Username
    * **Password** - Your Salesforce SOAP Account Password
    * **Security Token** - Your Salesforce SOAP Security Token. Obtain your security token by changing your password or resetting or security via Salesforce user interface. For more information, please refer to the [documentation](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_concepts_security.htm)
  </Step>

  <Step>
    Test the Salesforce SOAP connection by clicking Test connection. Once the connection tests successful, click Create connection.

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-247.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=d5132c70a57e841b16097194428ef52c" alt="Successful connection test with Create connection button" width="1200" height="828" data-path="images/connectivity-and-security/image-247.webp" />
    </Frame>
  </Step>
</Steps>

### To modify Salesforce SOAP connections in Integrate.io ETL

<Steps>
  <Step>
    Click the **Connections** icon (lightning bolt) on the top left menu.
  </Step>

  <Step>
    Click a connection to open and modify it. Make any necessary changes, then click **Reconnect**, and **Save changes**. To exit the Salesforce SOAP connection window without changes, click **Back to connections** (grey tab on the left side) on the Salesforce SOAP connection window.
  </Step>

  <Step>
    To delete a Salesforce SOAP connection, click on the three vertical dots on the far right of the connection listing and select the **Delete connection** option.

    <Frame>
      <img src="https://mintcdn.com/integrateio/V1Ns1A4dfxUcZVN3/images/connectivity-and-security/image-248.webp?fit=max&auto=format&n=V1Ns1A4dfxUcZVN3&q=85&s=2606f72cbfd570545ded461f597aa15a" alt="Delete connection option for Salesforce SOAP" width="1200" height="828" data-path="images/connectivity-and-security/image-248.webp" />
    </Frame>
  </Step>
</Steps>

## Connection Setup: Salesforce (Customer OAuth)

This guide explains how to retrieve the **Client ID**, **Client Secret**, **Authorization Code**, **Access Token**, **Refresh Token**, and **Instance URL** for OAuth 2.0 integration with Salesforce. We'll use **Postman** and curl to demonstrate the flow.

### Step 1: Get `Client ID` and `Client Secret` from Salesforce Dashboard

<Steps>
  <Step>
    Log into Salesforce with an admin account.
  </Step>

  <Step>
    In the top-right, click the **gear icon → Setup**.
  </Step>

  <Step>
    In the left sidebar, search for **App Manager** and click it.
  </Step>

  <Step>
    Click **New External Client App** (or find an existing one and click **View**).
  </Step>

  <Step>
    Fill in:

    * **Connected App Name**: `My OAuth App`
    * **API Name**: auto-generated
    * **Contact Email**: your email.
  </Step>

  <Step>
    Scroll down to **API (Enable OAuth Settings)** and:

    * Check **Enable OAuth Settings**
    * **Callback URL**: use `https://oauth.pstmn.io/v1/callback` for Postman testing
    * **Selected OAuth Scopes**:
      * Perform requests at any time (refresh\_token, offline\_access)
      * Manage user data via APIs (api)
      * Full access (full)
    * Uncheck **Require Proof Key for Code Exchange (PKCE)** option
    * Check **Require secret for Web Server Flow** and **Require secret for Refresh Token Flow** options.
  </Step>

  <Step>
    Click **Save**. You may need to wait a few minutes for the app to become active.
  </Step>

  <Step>
    Go back to **App Manager**, find your app, and click **View**.
  </Step>
</Steps>

You'll now see:

* **Consumer Key** → this is your `client_id`
* **Consumer Secret** → this is your `client_secret` (click "Reveal")

### Step 2: Generate Authorization Code (using Postman)

<Steps>
  <Step>
    Open Postman.
  </Step>

  <Step>
    Create a new **OAuth 2.0** authorization under the **Authorization tab**.
  </Step>

  <Step>
    Fill in:

    * **Grant Type**: Authorization Code
    * **Callback URL**: `https://oauth.pstmn.io/v1/callback`
    * **Auth URL**: `https://login.salesforce.com/services/oauth2/authorize`
    * **Access Token URL**: `https://login.salesforce.com/services/oauth2/token`
    * **Client ID**: *(from Salesforce Dashboard)*
    * **Client Secret**: *(from Salesforce Dashboard)*
    * **Scope**: `full refresh_token api`
  </Step>

  <Step>
    Click **Get New Access Token**.
  </Step>

  <Step>
    You will be redirected to Salesforce → login and allow access.
  </Step>

  <Step>
    Postman will receive a redirect like: `https://oauth.pstmn.io/v1/callback?code=YOUR_AUTH_CODE`

    Copy the value of `code=...` – this is your **Authorization Code**.
  </Step>
</Steps>

### Step 3: Exchange Authorization Code for Tokens

Use the following `curl` command to exchange the authorization code for:

* `access_token`
* `refresh_token`
* `instance_url`

### CURL example:

```bash theme={null}
curl -X POST https://login.salesforce.com/services/oauth2/token \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=https://oauth.pstmn.io/v1/callback" \
  -d "code=YOUR_AUTHORIZATION_CODE"
```

### Example Response:

```json theme={null}
{
  "access_token": "00Dxx000000S1on!...",
  "refresh_token": "5Aep86...etc",
  "instance_url": "https://na123.salesforce.com",
  "id": "https://login.salesforce.com/id/...",
  "issued_at": "1711734351000",
  "signature": "abcdef123456="
}
```

***

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-1.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=90541d6dac16f05510e54a7dfdd0c20b" alt="Salesforce source component in the pipeline designer" width="1200" height="828" data-path="images/creating-packages/using-components-salesforce-source/image-1.png" />
</Frame>

## Connection

Connections are part of configuring a no-code Salesforce integration, allowing secure API-based access without writing custom code.

Select an existing Salesforce connection or create a new one (for more information, see [Allowing Integrate.io ETL access to my data on Salesforce](/etl/allowing-integrateio-etl-access-to-my-data-on-salesforce).)

## Source Properties

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-2.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=048ad42df4feeb14569ad5676d23f54d" alt="Salesforce source properties with API version, access mode, and object fields" width="1200" height="1121" data-path="images/creating-packages/using-components-salesforce-source/image-2.png" />
</Frame>

* **API Version -** list of Salesforce Bulk API versions we support. Read more about Bulk API 2.0 [here](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/asynch_api_intro.htm)
* **Access mode** - select object to extract an entire object or query to execute a SOQL query.
* **Source object** - the table name from which the data will be imported.
* **where clause** - optional. You can add predicates clauses to the WHERE clause as part of the SQL query that is built in order to get the data from the database. Make sure to skip the keyword WHERE.
  | Good | `prod_category = 1 AND prod_color = 'red'`       |
  | :--- | :----------------------------------------------- |
  | Bad  | `WHERE prod_category = 1 AND prod_color = 'red'` |
* **Source action** - Use `bulk query` (default) to read available records or `bulk query all` to read available and deleted records.
* **Query** - type in a SOQL query. Read more about SOQL syntax [here](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm).
* **Max records** - Specify the number of records to retrieve per page/API call to prevent timeouts. If left empty, all records will be retrieved in a single API call. Only available in Bulk API 2.0

## Source Schema

After defining the source object, select the fields to use in the source.

The fields you select are used to build the SOQL query that will be executed to read the data. Careful field selection helps reduce unnecessary API usage and improves performance in no-code Salesforce integrations.

## Loading data incrementally from Salesforce

Incremental loading is a common pattern in ETL products that support pulling data from systems like Marketing Cloud, transforming it, and writing updates back into Salesforce while minimizing API consumption

In order to load data incrementally (changes and additions) to objects, the object to synchronize should have the *systemmodstamp* column. This column is automatically updated whenever a user or an automated process updates a record. Use the following condition in the **where clause** field with a variable:

SystemModstamp > \$lastsysmod

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-3.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=f9bef29cd5fb2ea103b12a1feda15f5d" alt="Where clause using SystemModstamp for incremental loading" width="1200" height="1121" data-path="images/creating-packages/using-components-salesforce-source/image-3.png" />
</Frame>

You can use the last successful submission timestamp for the package as you can see in the example below as a value for the variable, or use ExecuteSqlDatetime function to get the last SystemModstamp in your destination database table.

```sql theme={null}
lastsysmod = CASE
WHEN (COALESCE($_PACKAGE_LAST_SUCCESSFUL_JOB_SUBMISSION_TIMESTAMP,'')=='') THEN '1900-01-01T00:00:00Z' 
ELSE $_PACKAGE_LAST_SUCCESSFUL_JOB_SUBMISSION_TIMESTAMP END
```

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-4.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=a0c127b042a05087fbb6e9652a413d0b" alt="Package variable using last successful job submission timestamp" width="1096" height="365" data-path="images/creating-packages/using-components-salesforce-source/image-4.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-5.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=b3f64866f7fcb360781b3bc63fa8c666" alt="Variable expression with CASE and COALESCE for incremental load" width="1200" height="1123" data-path="images/creating-packages/using-components-salesforce-source/image-5.png" />
</Frame>

Merge operations are typically used when synchronizing transformed data back into Salesforce to avoid duplicate records. In order to store additions or changes in your database destination, make sure to mark the id column as key and change the operation type to "merge":

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-6.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=069a64d02faca89ab08acdb0a6789905" alt="Destination schema with id column marked as merge key" width="1200" height="1120" data-path="images/creating-packages/using-components-salesforce-source/image-6.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/integrateio/OwEKdS5aIKsEcmhX/images/creating-packages/using-components-salesforce-source/image-7.png?fit=max&auto=format&n=OwEKdS5aIKsEcmhX&q=85&s=d0ecf601d169682c20d62cb4e52a72da" alt="Merge operation type selected in the destination component" width="1200" height="1123" data-path="images/creating-packages/using-components-salesforce-source/image-7.png" />
</Frame>

## Enabling PK Chunking

You can enable **PK Chunking** for large datasets such as initial bulk load. By enabling this feature, Salesforce automatically splits the Bulk API Query job into multiple batches. Integrate.io ETL then polls for the progress of each of the batch then process them in parallel once all are done. The parallelism depends on the cluster node count (higher node count can pull more batches in parallel). Note that PK Chunking is disabled in Bulk API 2.0

<Frame>
  <img src="https://mintcdn.com/integrateio/HSGmKiO3soPLENmi/images/creating-packages/using-components-salesforce-source/image-8.png?fit=max&auto=format&n=HSGmKiO3soPLENmi&q=85&s=ea8083b47e57677b61a8f0ecb8a95798" alt="PK Chunking option enabled in Salesforce source settings" width="1200" height="1123" data-path="images/creating-packages/using-components-salesforce-source/image-8.png" />
</Frame>

## Limitations

It is currently not possible to join a Salesforce Sandbox environment source connection with a Salesforce Production environment source connection.

This limitation applies to Join, Union and Cross-join components to join Sandbox with Production source data.

## Querying Parent Fields

It is possible to execute query containing parent fields, for example following query:

```sql theme={null}
SELECT CreatedDate, Id, Sales_User__r.Id, Sales_User__r.Name 
FROM Account
```

`Sales_User__r.Id` and `Sales_User__r.Name` are fields from `Account`'s parent object: `Sales__User__c` (`Sales_User__r` is the relationship name prefix for the `Account` object, for more details about the difference on `__c` and `__r` is [here](https://developer.salesforce.com/forums/?id=906F00000008llXIAQ))

Please note that when doing the query, the schema column might not pop up if the data returned is empty.

## Related

<CardGroup cols={2}>
  <Card title="Salesforce Destination" icon="arrow-right" href="/etl/using-components-salesforce-destination" horizontal />

  <Card title="Salesforce Objects Reference" icon="arrow-right" href="/etl/list-of-salesforce-objects" horizontal />

  <Card title="Salesforce PK Chunking" icon="arrow-right" href="/etl/salesforce-pk-chunking" horizontal />

  <Card title="Moving Data Incrementally Between Databases" icon="arrow-right" href="/etl/how-do-i-move-data-incrementally-between-databases" horizontal />
</CardGroup>
