Skip to main content

Salesforce-Python Integration: Simple-Salesforce Library Overview

About Us
Published by JET BI
28 January 2024

Benefits of Integrating Salesforce with Python

Python is now one of the most popular programming languages ​​in the world. It was ranked for its powerful and versatile features, flexibility and beginner friendliness. It is utilized in a wide array of industries, from Web Development and Task Automation to cutting-edge fields like Machine Learning and Data Science.

And there are several reasons to utilize Python for Salesforce development.

  • Ease of use. Python is often simpler to learn than other programming languages, which makes creating custom solutions using it faster and easier.
  • Community. With a large and active community, Python opens doors for developers to tap into its robust ecosystem of libraries and frameworks. These resources enable developers to create advanced and sophisticated applications, going beyond the capabilities of the Salesforce CRM. One such example is the pandas package, designed to streamline data manipulation by providing flexible data structures for processing "relational" or "labeled" data. Serving as the fundamental and top-level component, pandas can empower deep Salesforce data analysis.
  • Integration. Python can make Salesforce CRM integration with other programs and systems easier.
  • Scalability. By leveraging Python's scalability, it’s possible to develop custom solutions that have the ability to grow and evolve alongside any business’ needs, ensuring their continued relevance in the long run.

Why Use Simple-Salesforce Library?

Simple-Salesforce library is a basic REST API client built for Python 3.6, 3.7, 3.8, 3.9, 3.10, and 3.11. Its main purpose is to provide a simple interface to access the REST Resource and APEX API, returning the API JSON response in the form of a dictionary.

The library can perform tasks such as Salesforce data management, SOQL and SOSL queries, CRUD and file based calls to the Metadata API, access Bulk and Bulk 2.0 API functions, and, as icing on the cake, can call Apex methods and provide easy authentication methods.

What Simple-Salesforce Library Has To Offer?


To use the vast majority of the library's features, simply use the following import statement:

from simple_salesforce import Salesforce

There are also some helper classes that are used internally:

from simple_salesforce import Salesforce, SFType, SalesforceLogin, format_soql, format_external_id

To find out more about them, check the Queries and Additional Features section.


To gain access and connect Python to Salesforce, there are two options available. The first option is to provide the domain of your Salesforce instance and a session ID:

sf = Salesforce(instance='', session_id='session_id') 

Alternatively, if you have the complete URL of your instance (which may include the schema used in the OAuth2 request process), you can use instance_url argument instead:

sf = Salesforce(instance_url='>', session_id='session_id')

There are four different methods of authentication available.

The first method uses a combination of username, password, and security token:

sf = Salesforce(username='', password='password', security_token='token')

The second method utilizes IP filtering along with username, password, and organization ID:

sf = Salesforce(password='password', username='', organizationId='org_id')

The third method involves the use of a private key to sign a JWT (JSON Web Token):

sf = Salesforce(username='', consumer_key='consumer_key', privatekey_file='filename.key')

Lastly, there is a method specifically designed for connected apps, which requires the use of username, password, consumer key, and consumer secret:

sf = Salesforce(username='', password='password', consumer_key='consumer_key', consumer_secret='consumer_secret')


Record Management

To create an Account record, use the following syntax:

sf.Account.create({'Name':'Account Name'})

The result will be an ordered dictionary that contains ID, status, and errors.

To get a dictionary with all the information regarding the particular record, use:

account = sf.Account.get(account_id)

To get a dictionary with all the information regarding the particular record, using a Custom Field that was defined as External ID, use:

account = sf.Account.get_by_custom_id('External_Id__c', external_id)

To update an Account record, use:

sf.Account.update(account_id, {'Name': 'New Account Name'})

To delete an Account record, use:


To get a list of Account records updated or deleted over a specific time period, use:

sf.Account.updated(start, end)
sf.Account.deleted(start, end)

The methods presented above work with both standard and custom objects.


All SOQL queries that developers are used to are supported and can be run via the search() method:

sf.query("SELECT Id, Name, Parent.Name FROM Account")
sf.query("SELECT Id, Name, Status__c FROM Custom_Object__c WHERE Status__c='Active'")
sf.query("SELECT Id, Field, NewValue, OldValue FROM Custom_Object__History")
sf.query("SELECT Id, Amount, Name, (SELECT Quantity, ListPrice FROM OpportunityLineItems) FROM Opportunity")
sf.query("SELECT LeadSource, COUNT(Name) FROM Lead GROUP BY LeadSource HAVING COUNT(Name) > 100")
sf.query("SELECT Id, AccessLevel, RowCause FROM Custom_Object__Share")
sf.query("SELECT Id, Label FROM Custom_Metadata__mdt")

If the initial query returns only part of the results, the response contains:

"nextRecordsUrl" : "/services/data/v59.0/query/01gD0000002HU6KIAW-2000”

In this case, the query_more() method comes into play, taking either the ID or the full URL (then the second argument should be True) and returning the next batch of records until all records have been retrieved:

sf.query_more("/services/data/v26.0/query/01gD0000002HU6KIAW-2000", True)

To retrieve all records, use the query_all() method, which returns a list, or query_all_iter(), which returns an iterator:

sf.query_all("SELECT Id, Name, Parent.Name FROM Account")
sf.query_all_iter("SELECT Id, Name, Parent.Name FROM Account")

Values used in SOQL queries can be quoted and escaped using the format_soql() method:

sf.query(format_soql("SELECT Id, Type FROM Account WHERE Type = {}", "Channel Partner / Reseller"))
sf.query(format_soql("SELECT Id, Type FROM Account WHERE Type = {type}", type="Prospect"))
sf.query(format_soql("SELECT Id, Type FROM Account WHERE Type IN {types}", types=["Installation Partner", "Technology Partner"]))

To escape a substring used in a LIKE expression while being able to use % around it, use :like:

sf.query(format_soql("SELECT Id, Email FROM Contact WHERE Name LIKE '{:like}%'", "Jones"))

A SOSL request can be run using the search() and quick_search() methods. The first one allows you to write the entire query, while the second one simply inserts the search term into the {} part of the SOSL syntax:"FIND {Wingo} IN ALL FIELDS RETURNING Account(Name), Contact(FirstName,LastName,Department)")


CRUD Metadata API Calls

By employing Simple-Salesforce library, you can easily make API calls to the Metadata API in order to carry out CRUD (Create, Read, Update, and Delete) operations.

To create a new metadata component in Salesforce, retrieve the Metadata API object, specify the metadata component, and perform the create API call, use:

mdapi = sf.mdapi
custom_object = mdapi.CustomObject(
    fullName = "Custom_Object__c",
    label = "Custom Object",
    pluralLabel = "Custom Objects",
    nameField = mdapi.CustomField(
        label = "Name",
        type = mdapi.FieldType("Text")
    deploymentStatus = mdapi.DeploymentStatus("Deployed"),
    sharingModel = mdapi.SharingModel("Read")

By using mdapi.MetadataType.create(), any metadata type can be created in Salesforce. Additionally, mdapi.MetadataType.create() can be leveraged to create multiple metadata components by passing a list of metadata definitions.

The read, update, delete, rename, and describe (returns a DescribeValueTypeResult object) API calls are also supported.

describe_response = mdapi.CustomObject.describe()
custom_object ="Custom_Object__c")
custom_object.sharingModel = mdapi.SharingModel("ReadWrite")
mdapi.CustomObject.rename("Custom_Object__c", "My_Custom_Object__c")

The describe_metadata() and list_metadata() API calls will give you the DescribeMetadataResult and FileProperties objects as their output.

describe_metadata = mdapi.describe_metadata()
query = mdapi.ListMetadataQuery(type='CustomObject')
query_response = mdapi.list_metadata(query)


File-Based Metadata API Calls

Simple-Salesforce library can also be utilized to initiate file-based calls to the Metadata API, enabling the deployment of a zip file to an org. Both functions receive keyword arguments. And you have the option to keep track of the deployment progress as well.

result = sf.deploy("path/zip", sandbox=False, **kwargs)


BULK and BULK 2.0 API Calls

This library provides access to Bulk API functions. The data element can be a list of records of any size and by default batch sizes are 10,000 records and run in parallel concurrency mode. To specify the batch size for insert, update, upsert, delete, and hard delete operations, you can use the batch_size argument. Additionally, use the use_serial argument to set the concurrency mode for the Salesforce job.

To perform insert, update, upsert, delete (soft and hard) operations, use the following methods:

sf.bulk.Account.upsert(data, 'Id', batch_size=10000, use_serial=True)

To query records, use the query() and query_all() (retrieves deleted records resulting from merges or deletions and also provides information about archived Task and Event records) methods:

query = 'SELECT Id, Name FROM Account LIMIT 10'

To retrieve large amounts of Salesforce data, use the lazy_operation argument set to True and iterate over the results:

query = 'SELECT Id, Name FROM Account'
results = sf.bulk.Account.query(query, lazy_operation=True)
results = sf.bulk.Account.query_all(query, lazy_operation=True)

all_results = []
for results_portion in results:

Simple-Salesforce library also allows you to utilize functions of Bulk 2.0 API.

To perform insert, update, upsert, delete (soft and hard) operations, use the following methods:

sf.bulk2.Account.insert("path/sample.csv", batch_size=10000)
sf.bulk2.Account.upsert("path/sample.csv", 'Custom_Id__c')

Use the concurrency argument to create records concurrently:

sf.bulk2.Account.insert("path/sample.csv", batch_size=10000, concurrency=10)

To query records, use the query() method:

query = 'SELECT Id, Name FROM Account LIMIT 100000'
results = sf.bulk2.Account.query(query, max_records=50000, column_delimiter="COMM", line_ending="LF")

To download records, use the download()method:

query = 'SELECT Id, Name FROM Account LIMIT 100000', path="path/", max_records=100000)


Apex Calls

Simple-Salesforce library can be used to invoke custom Apex REST methods. The endpoint https://<instance>* will be called, passing the body content as the data argument.

sf.apexecute('Account/', method='GET')
sf.apexecute('Account/', method='POST', data=payload)
sf.apexecute('Account/', method='PUT', data=payload)
sf.apexecute('Account/AccountId', method='DELETE')
sf.apexecute('Account/AccountId', method='PATCH')


Additional Features

SalesforceLogin accepts a username, password, security token, optional version, and optional domain as input parameters. It then provides a tuple consisting of session_id and sf_instance as output. The session_id represents the authentication session ID for accessing Salesforce, while sf_instance denotes the domain of the Salesforce instance to be used during the session.

from simple_salesforce import SalesforceLogin
session_id, instance = SalesforceLogin(

Within the Salesforce() class, the __getattr__() method utilizes SFType internally to represent a particular SObject type. SFType requires object_name, session_id (an authentication ID), sf_instance (the hostname of your Salesforce instance), and an optional sf_version.

For example, to create an Account, use the following syntax:

from simple_salesforce import SFType
account = SFType('Account', sesssion_id, sf_instance)
account.create({'Name':'Account Name'})

Use the format_external_id() method to format an external ID that may have characters not suitable for URLs:

from simple_salesforce import format_external_id
external_id = format_external_id('External_Id__c', '[]')



As you can see, integrating Python and Salesforce has many undeniable benefits for any business, including ease of use, broad integration capabilities with all kinds of services and systems, scalability, and unrivaled flexibility. Python along with Salesforce CRM can do everything!

Given the capabilities of the Simple-Salesforce library, which allow you to do the same things you're used to doing on the Salesforce platform: manage data, make database calls, use Metadata API and BULK API, and execute Apex code. And by utilizing the vast array of libraries and packages in the Python community, it is possible to do even more and go beyond the capabilities and limitations of Salesforce CRM!

Want to go beyond Salesforce capabilities too? Integrating Salesforce CRM with any other system or service? Salesforce data processing of any complexity? We can do that and even more. JET BI is your trusted partner you can rely on. Мake a request now! Our consultant will prepare valuable insights, estimates, questions about your request and contact you back in 1 business day or less.

Gleb Zemskov
Salesforce Developer

We have available resources to start working on your project within 5 business days

1 UX Designer


1 Admin


2 QA engineers


1 Consultant


Steps following request submission



After receiving your request, we analyze it and we offer free online meeting slots (via email) so that we can discuss your needs in as much detail as possible


We begin gathering all necessary requirements to create comprehensive estimates, including timelines, resource allocations, risk assessments, and underlying assumptions.


Once all preparations are in place, we will initiate the project and move forward with the planned tasks