---
title: Salesforce integration API
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

> **Info:** **Enterprise license required**
>
> Features described on this page require the **Kentico Xperience Enterprise** license.

In addition to the built-in [replication process](https://docs.kentico.com/13/integrating-3rd-party-systems/salesforce-integration.md) that automatically converts Xperience [contacts](https://docs.kentico.com/13/on-line-marketing-features/managing-your-on-line-marketing-features/contact-management/working-with-contacts.md) into Salesforce leads, Xperience also provides integration with the Salesforce API. The integration allows you to develop custom logic for manipulating data inside your Salesforce organization (query, create, update and delete).

This page introduces the Salesforce integration API and presents basic examples to get you started.

The following content assumes you already have knowledge of the Salesforce SOAP API and Salesforce Object Query Language (SOQL). SOQL is the object language developed for querying data on the Salesforce platform. Refer to the official Salesforce documentation for more information:

- [Introduction to SOAP API](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_quickstart_intro.htm)
- [Salesforce Object Query Language (SOQL)](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm)

Xperience integrates the API using the Partner version of the web service, which is weakly typed. This means that the integration API does not use classes such as Lead or Company. Only general classes are available: _Object_ and _Field_. For example, to create a new contact in your Salesforce organization, you need to create a new Object and set its properties so that it represents a contact. The flexibility of this form of integration reduces the reliance on the Salesforce data model.

**Note**: There are several basic naming differences between the default Salesforce API and the integration API in Xperience:

| Salesforce        | Xperience              |
| ----------------- | ---------------------- |
| Object            | Entity                 |
| Object Type       | Model                  |
| Object Field      | Entity Attribute       |
| Object Field Type | Entity Attribute Model |

## Salesforce API requirements and limitations

You can only use the integration API if your Salesforce organization has the API feature enabled. This feature is enabled by default for the following editions:

- Unlimited
- Enterprise
- Developer
- Some Professional Edition organizations may have the API enabled

Salesforce also enforces a limit on the number of API calls your organization can make during a 24 hour window. If your organization exceeds the limit, all calls result in an error until the number of calls over the last 24 hours drops below the limit. The [maximum number](https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_api.htm) of allowed calls for your organization is determined by the edition you are using.

> **Note:** **Xperience API namespace**
>
> The Salesforce integration API is available in the **CMS.SalesForce** namespace.
>
> Add the following _using_ directive to all files that access the integration API:
>
> ```csharp
>
> using CMS.SalesForce;
>
> ```

## Establishing a session with the Salesforce organization

Before you can start working with the data, you need to establish a session with your Salesforce organization.

1. Use the following code to create a session for your Salesforce organization based on your [Salesforce integration settings](https://docs.kentico.com/13/integrating-3rd-party-systems/salesforce-integration/configuring-salesforce-integration.md).

   ```csharp

   // Provides a Salesforce organization session
   ISessionProvider sessionProvider = new ConfigurationSessionProvider();
   Session session = sessionProvider.CreateSession();

   ```
2. Create a client to access the organization's data using the session.

   ```csharp

   // Creates a client to access Salesforce organization's data
   SalesForceClient client = new SalesForceClient(session);


   ```

You can then use the client to perform specific operations.

> **Note:** All examples in the sections below use the **client** variable for this purpose.

## Querying data

1. Describe the entity you will be working with.

   - The following examples work with Salesforce _Contact_ entities, but you can use the same approach for other Salesforce objects such as Leads or Accounts.

   ```csharp

   // Describes the Salesforce Contact entity
   EntityModel model = client.DescribeEntity("Contact");

   // Displays basic information about the entity's attributes
   foreach (EntityAttributeModel attributeModel in model.AttributeModels)
   {   
       Console.WriteLine("{0} is an attribute labeled {1} of type {2}", attributeModel.Name, attributeModel.Label, attributeModel.Type);
   }

   ```
2. Load the attributes of the entity using SOQL.

   ```csharp

   // Executes a query using SOQL
   SelectEntitiesResult result = client.SelectEntities("SELECT Id, Name, MobilePhone FROM Contact", model);

   // Displays how many contacts were found
   Console.WriteLine("{0} contacts were found", result.TotalEntityCount);

   // Displays basic information about each of the contacts
   foreach (Entity contact in result.Entities)
   {
       Console.WriteLine("Contact {0} with name {1} and phone number {2}", contact.Id, contact["Name"], contact["MobilePhone"]);
   }

   ```

## Creating objects

1. Create a new contact.

   ```csharp

   // Describes the Contact entity
   EntityModel model = client.DescribeEntity("Contact");

   // Creates a new contact entity
   Entity customContact = model.CreateEntity();

   customContact["LastName"] = "Jones";
   customContact["Description"] = "Always has his wallet on him";

   Entity[] customContacts = new Entity[] { customContact };
   CreateEntityResult[] results = client.CreateEntities(customContacts);

   ```
2. Use the following code to check whether the creation was successful or not.

   ```csharp

   // Checks if the contact was successfully created in Salesforce
   foreach (CreateEntityResult createResult in results)
   {
       if (createResult.IsSuccess)
       {
           Console.WriteLine("A contact with id {0} was inserted.", createResult.EntityId);
       }
       else
       {
           Console.WriteLine("A contact could not be inserted.");
           foreach (Error error in createResult.Errors)
           {
               Console.WriteLine("An error {0} has occurred: {1}", error.StatusCode, error.Message);
           }
       }
   }

   ```

## Updating existing objects

To update an object, you first need to either prepare a new entity, or load an existing one using SOQL.

> **Info:** **Custom Salesforce identifier field required**
>
> The following examples use a custom external ID attribute for Salesforce contacts, so you first need to define the custom field in Salesforce.
>
> 1. Log in to [Salesforce.com](http://www.salesforce.com/)
> 2. Navigate to **App Setup → Customize → Contacts → Fields**..
> 3. Click **New** in the **Contact Custom Fields & Relationships** section.
> 4. Choose **Text** as the field type and click **Next**.
> 5. In the **Enter the details** step, fill in the following values:
>    - **Field Label**: Xperience contact ID
>    - **Length**: 32
>    - **Field Name**: XperienceContactID
>    - **Unique**: enabled
>      - Select _Treat "ABC" and "abc" as duplicate values (case insensitive)_
>    - **External ID**: enabled
>
> Custom fields in Salesforce always use the **\_\_c** suffix in their API name. You need to add this suffix to the field name when identifying fields in your code.

1. Update a contact and assign an external ID value.

   ```csharp

   // Describes the Contact entity
   EntityModel model = client.DescribeEntity("Contact");

   // Loads an existing Salesforce contact using SOQL
   SelectEntitiesResult result = client.SelectEntities("SELECT Id, LastName FROM Contact WHERE LastName = 'Jones'", model);

   if (result.TotalEntityCount > 0)
   {                
       Entity updateContact = result.Entities.FirstOrDefault();

       // Sets values for the contact's fields
       updateContact["Description"] = "Always has his satchel on him";
       updateContact["XperienceContactID__c"] = "D900172AABCE11E1BC6924C56188709B";

       // Updates the contact
       Entity[] updateContacts = new Entity[] { updateContact };
       UpdateEntityResult[] updateResults = client.UpdateEntities(updateContacts);
   }

   ```
2. Use the following code to check whether the update was successful.

   ```csharp

   // Checks if the contact was successfully updated
   foreach (UpdateEntityResult updateResult in updateResults)
   {
       if (updateResult.IsSuccess)
       {
           Console.WriteLine("The contact with id {0} was updated.", updateResult.EntityId);
       }
       else
       {
           Console.WriteLine("The contact could not be updated.");
           foreach (Error error in updateResult.Errors)
           {
               Console.WriteLine("An error {0} has occurred: {1}", error.StatusCode, error.Message);
           }
       }
   }

   ```

## Upserting objects

The _Upsert_ operation uses an external ID to identify already existing objects and then decides whether to _update_ the object or _create_ a new one:

- If the external ID does not exist, a new record is _created_.
- When the external ID matches an existing record, the given record is _updated_.
- If multiple external ID matches are found, the upsert operation reports an error.

**Note**: It is generally recommended to use upsert instead of directly creating entities if you plan on specifying an External ID attribute. This allows you to avoid creating duplicate records.

1. Create a new entity using the _upsert_ call.

   - If you leave the value of _XperienceContactID_ the same as in the previous example, the existing contact will be _updated_.

   ```csharp

   // Describes the Contact entity
   EntityModel model = client.DescribeEntity("Contact");

   // Creates a new contact or updates an existing one
   Entity upsertContact = model.CreateEntity();

   upsertContact["Description"] = "Is a professor";
   upsertContact["XperienceContactID__c"] = "D900172AABCE11E1BC6924C56188709B";

   Entity[] upsertContacts = new Entity[] { upsertContact };
   UpsertEntityResult[] upsertResults = client.UpsertEntities(upsertContacts, "XperienceContactID__c");

   ```
2. Use the following code to check for the results of the upsert call.

   ```csharp

   // Checks the results of the upsert call
   foreach (UpsertEntityResult upsertResult in upsertResults)
   {
       if (upsertResult.IsSuccess)
       {
           if (upsertResult.IsUpdate)
           {
               Console.WriteLine("The contact with id {0} was updated.", upsertResult.EntityId);
           }
           else
           {
               Console.WriteLine("A new contact with id {0} was inserted.", upsertResult.EntityId);
           }
       }
       else
       {
           Console.WriteLine("The contact could not be created nor updated.");
           foreach (Error error in upsertResult.Errors)
           {
               Console.WriteLine("An error {0} has occurred: {1}", error.StatusCode, error.Message);
           }
       }
   }

   ```

## Deleting objects

The delete call takes an array of entity IDs as a parameter. The ID is generated by Salesforce and is unique for each object.

1. Use an upsert call to create several new contacts that you will later delete.

   ```csharp

   // Describes the Contact entity
   EntityModel model = client.DescribeEntity("Contact");

   // Creates new contacts
   Entity customContact1 = model.CreateEntity();
   Entity customContact2 = model.CreateEntity();
   Entity customContact3 = model.CreateEntity();

   customContact1["LastName"] = "Drake";
   customContact1["Email"] = "Drake@acme.com";
   customContact1["XperienceContactID__c"] = "6C2L16B8W0ZXSU5SYPYRVE08QSKOR7F6";
   customContact2["LastName"] = "Croft";
   customContact2["Email"] = "Croft@acme.com";
   customContact2["XperienceContactID__c"] = "N5XX8Z42ISTVYGPC98AH81T1RHVOSESR";
   customContact3["LastName"] = "Solo";
   customContact3["Email"] = "Solo@acme.com";
   customContact3["XperienceContactID__c"] = "N34VY7D5K677GKG8JOGDIA9UHVBHHVSL";

   Entity[] newCustomContacts = new Entity[] { customContact1, customContact2, customContact3 };
   UpsertEntityResult[] createResults = client.UpsertEntities(newCustomContacts, "XperienceContactID__c");

   ```
2. Use the following example to check whether the creation was successful or not.

   ```csharp

   // Checks the results of the upsert call
   foreach (UpsertEntityResult upsertResult in createResults)
   {
       if (upsertResult.IsSuccess)
       {
           if (upsertResult.IsUpdate)
           {
               Console.WriteLine("The contact with id {0} was updated.", upsertResult.EntityId);
           }
           else
           {
               Console.WriteLine("A new contact with id {0} was inserted.", upsertResult.EntityId);
           }
       }
       else
       {
           Console.WriteLine("The contact could not be created nor updated.");
           foreach (Error error in upsertResult.Errors)
           {
               Console.WriteLine("An error {0} has occurred: {1}", error.StatusCode, error.Message);
           }
       }
   }

   ```
3. Select the contacts using a SOQL query and list their IDs. **Note**: Salesforce returns an 18 character version of object IDs in API calls.

   ```csharp

   // Executes a query using SOQL
   SelectEntitiesResult queryResult = client.SelectEntities("SELECT Id, Name FROM Contact WHERE Email LIKE '%acme.com'", model);

   // Displays how many contacts were found
   Console.WriteLine("{0} contacts were found", queryResult.TotalEntityCount);

   // Displays basic information about each of the contacts
   foreach (Entity contact in queryResult.Entities)
   {
       Console.WriteLine("Contact {0} with name {1}", contact.Id, contact["Name"]);
   }

   ```
4. Delete all of the contacts returned by the query.

   - Identify the contacts using an array or _IEnumerable_ collection of ID values.

   ```csharp

   using System.Collections.Generic;
   using System.Linq;

   ...

   // Gets the IDs of the contacts to be deleted
   List<string> contactIDs = queryResult.Entities.Select(c => c.Id).ToList();

   // Deletes the contacts           
   DeleteEntityResult[] deleteResults = client.DeleteEntities(contactIDs);

   ```
5. Check whether the deletion was successful.

   ```csharp

   // Checks if the contact was successfully deleted
   foreach (DeleteEntityResult deleteResult in deleteResults)
   {
       if (deleteResult.IsSuccess)
       {
           Console.WriteLine("A contact with id {0} was deleted.", deleteResult.EntityId);
       }
       else
       {
           Console.WriteLine("A contact could not be deleted.");
           foreach (Error error in deleteResult.Errors)
           {
               Console.WriteLine("An error {0} has occurred: {1}", error.StatusCode, error.Message);
           }
       }
   }

   ```

## Loading deleted objects

After you delete an object in Salesforce, its _IsDeleted_ attribute is set to _True_. You can't select deleted objects unless you enable the [IncludeDeleted](#call-options) option for the query.

1. Change the client options so that queries include deleted objects **.**

   ```csharp

   // Changes the client settings
   client.Options.IncludeDeleted = true;

   ```
2. Select the deleted contacts using a SOQL query.

   ```csharp

   // Describes the Contact entity
   EntityModel model = client.DescribeEntity("Contact");

   // Executes a query using SOQL
   SelectEntitiesResult queryResult = client.SelectEntities("SELECT Id, Name FROM Contact WHERE Email LIKE '%acme.com'", model);

   // Displays how many contacts were found
   Console.WriteLine("{0} contacts were found", includeDeletedQueryResult.TotalEntityCount);

   // Displays the basic information of each contact
   foreach (Entity contact in includeDeletedQueryResult.Entities)
   {
       Console.WriteLine("Contact {0} with name {1}", contact.Id, contact["Name"]);
   }

   // Reverts the client settings to ignore deleted contacts again
   client.Options.IncludeDeleted = false;

   ```

## Call options

You can adjust Salesforce client calls through additional options. The options are similar to the [SOAP headers](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/soap_headers.htm) available in the Salesforce API.

| Call option                                                                                                                             | Type   | Description                                                                            |
| --------------------------------------------------------------------------------------------------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| [TransactionEnabled](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_header_allornoneheader.htm)              | Bool   | Specifies whether the command operations run in a transaction.                         |
| [AttributeTruncationEnabled](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_header_allowfieldtruncation.htm) | Bool   | Specifies whether truncation is allowed for string values.                             |
| [FeedTrackingEnabled](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_header_disablefeedtracking.htm)         | Bool   | Specifies whether the changes made by the call are tracked in feeds.                   |
| [MruUpdateEnabled](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_header_mruheader.htm)                      | Bool   | Specifies whether the call updates the list of most recently used items in Salesforce. |
| IncludeDeleted                                                                                                                          | Bool   | Specifies whether SOQL queries include deleted entries.                                |
| ClientName                                                                                                                              | String | String identifier for the client.                                                      |
| DefaultNamespace                                                                                                                        | String | String that identifies a developer namespace prefix.                                   |
| [CultureName](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_header_localeheader.htm)                        | String | Specifies the language of the returned labels.                                         |
| [BatchSize](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_header_queryoptions.htm)                          | Int    | Specifies the maximum number of entities returned by one query call.                   |
