Salesforce REST API: authentication in Python

python, api
Published on 11/05/2017 | Jérémy Grèze

The Salesforce.com REST API let one interact with the entire data of the CRM (accounts, contacts, opportunities...). An authentication is required beforehand, an access token must be obtained.

The documentation indicates 3 distinct OAuth flows to authenticate: Web Server OAuth, User-Agent OAuth and Username-Password OAuth.

The first two flows can offer the advantage to also return a refresh token that can be used to extend the validity of the access token. But the third flow, Username-Password OAuth, is the easiest solution for data analysis purposes. I will use this one in this snippet.

Create an App

In any case, create a new "Connected App" in your Salesforce portal (prod or sandbox).

Go in "Setup", open the "App Manager". Then, create a "New Connected App". Name your application. Tick the box "Enable OAuth Settings". In "Selected OAuth Scopes", make all scopes available. Type "http://localhost/" in "Callback URL". Save.

At the end, you should get and note down the "Consumer Key" and the "Consumer Secret".

Use the Username-Password OAuth Flow to authenticate

With the user’s credentials and the the security token, use this Python script to get an access token.

import requests
params = {
    "grant_type": "password",
    "client_id": "XXX.YYY", # Consumer Key
    "client_secret": "0000000000000000", # Consumer Secret
    "username": "my@email.com", # The email you use to login
    "password": "MyPasswordMySecurityToken" # Concat your password and your security token
}
r = requests.post("https://login.salesforce.com/services/oauth2/token", params=params)
access_token = r.json().get("access_token")
instance_url = r.json().get("instance_url")
print("Access Token:", access_token)
print("Instance URL", instance_url)

Make calls to the Salesforce REST API

After successfully getting an access token, one can make calls the Salesforce REST API to extract data (leads, opportunities, etc.) or to modify and create new records.

import requests

def sf_api_call(action, parameters = {}, method = 'get', data = {}):
    """
    Helper function to make calls to Salesforce REST API.
    Parameters: action (the URL), URL params, method (get, post or patch), data for POST/PATCH.
    """
    headers = {
        'Content-type': 'application/json',
        'Accept-Encoding': 'gzip',
        'Authorization': 'Bearer %s' % access_token
    }
    if method == 'get':
        r = requests.request(method, instance_url+action, headers=headers, params=parameters, timeout=30)
    elif method in ['post', 'patch']:
        r = requests.request(method, instance_url+action, headers=headers, json=data, params=parameters, timeout=10)
    else:
        # other methods not implemented in this example
        raise ValueError('Method should be get or post or patch.')
    print('Debug: API %s call: %s' % (method, r.url) )
    if r.status_code < 300:
        if method=='patch':
            return None
        else:
            return r.json()
    else:
        raise Exception('API error when calling %s : %s' % (r.url, r.content))

Very simple example: let's extract the next closing opportunities thanks to a SOQL request (Salesforce Object Query Language).

print(json.dumps(sf_api_call('/services/data/v39.0/query/', {
    'q': 'SELECT Account.Name, Name, CloseDate from Opportunity where IsClosed = False order by CloseDate ASC LIMIT 10'
}), indent=2))

The result is a JSON easy to exploit.

Voila!