Python code samples for Salesforce REST API

python, api
Published on 2017-12-26 | Jérémy Grèze

The Salesforce.com REST API can be tricky to use. I share here a list of snippets that I hope will be useful. You should read first the snippet about the authentication with Salesforce REST API. The Object Reference for Salesforce describes the objects available via the API.

Helper function

import requests
import base64

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))

Searching leads, contacts, opportunities and acconts containing a specific text

search = 'air france'
call = sf_api_call('/services/data/v40.0/search/', parameters={
        'q': "FIND {%s} IN ALL FIELDS RETURNING Account (Id, Name), Contact (Id, Name), Opportunity (Id, Name), Lead (Id, Name) WITH METADATA='LABELS' " % search
    })
print json.dumps(call, indent=2)

Creating an opportunity

call = sf_api_call('/services/data/v40.0/sobjects/Opportunity/', method="post", data={
    'CloseDate': '2018-03-01',
    'Name': 'My big deal',
    'StageName': 'Sales Accepted Lead',
    'Type': 'Initial Subscription',
    'AccountId': '0019E000009WTBVQA4',
})
opportunity_id = call.get('id')

Attaching a Google Doc to an opportunity

# 1) Create a ContentVersion
ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data={
    'Title': 'Important attached document',
    'ContentUrl': 'https://drive.google.com/drive/folders/0B60dm9TFrvQrTDVVYnp3QldvWFE'
})
ContentVersion_id = ContentVersion.get('id')

# 2) Get the ContentDocument id
ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion/%s' % ContentVersion_id)
ContentDocument_id = ContentVersion.get('ContentDocumentId')


# 3) Create a ContentDocumentLink
Opportunity_id = "0069E000003o92TQAQ"
ContentDocumentLink = sf_api_call('/services/data/v40.0/sobjects/ContentDocumentLink', method = 'post', data={
        'ContentDocumentId': ContentDocument_id,
        'LinkedEntityId': Opportunity_id,
        'ShareType': 'V'
    })

Uploading a document to an opportunity

This is very similar to the code just above. Only part 1 is modified.

# 1) Create a ContentVersion
path = "test.png"
with open(path, "rb") as f:
    encoded_string = base64.b64encode(f.read())

ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data={
    'Title': 'An image',
    'PathOnClient': path,
    'VersionData': encoded_string,
})
ContentVersion_id = ContentVersion.get('id')

# 2) Get the ContentDocument id (see above)

# 3) Create a ContentDocumentLink (see above)

Adding an event to an opportunity

AddEvent = sf_api_call('/services/data/v40.0/sobjects/Event', method = 'post', data={
    #'Type': 'Meeting', # seems not required
    'Subject': 'Qualification meeting',
    'OwnerId': "0050Y000000PIONQA4",
    'ActivityDate': '2017-07-24T00:00:00.000Z',
    'IsAllDayEvent': True,
    'WhoId': "0030Y00000KAABsQAP", #from doc: "represents a human such as a lead or a contact"
    'WhatId': "0060Y0000077iDGQAY", #from doc: "represents nonhuman objects such as accounts, opportunities, campaigns, cases, or custom objects"
    'Description': 'blablabla'
})

Adding a member to the OpportunityTeam of an opportunity

sf_api_call('/services/data/v40.0/sobjects/OpportunityTeamMember', method = 'post', {
    'UserId': user_id,
    'OpportunityId': opportunity_id,
    'OpportunityAccessLevel': 'Edit',
    'TeamMemberRole': 'SDR'
})

Exporting all the records of an object with all fields

For example, exporting all opportunities with all fields. You will get a list of dictionaries. You can then easily export this list to a CSV file or to a Pandas dataframe.

object_to_export = "Opportunity"
limit = 10000

describe = sf_api_call('/services/data/v40.0/sobjects/%s/describe' % object_to_export)

if not describe.get('queryable', False):
    raise Exception("This object is not queryable")

fields = [f['name'] for f in describe.get('fields')]

query = "SELECT %s FROM %s LIMIT %i" % (
    ", ".join(fields),
    object_to_export,
    limit
)

call = sf_api_call('/services/data/v40.0/queryAll/', {'q': query})

rows = call.get('records', [])
# for obj in call.get('records', []):
#     print(obj)

next = call.get('nextRecordsUrl', None)

while next:
    call = sf_api_call(next)
    rows.extend(call.get('records', []))
    # for obj in call.get('records', []):
    #     print(obj)
    next = call.get('nextRecordsUrl', None)

# print(rows)