The Salesforce REST API from Python
Connected apps, credentials, cloud connections and the self.salesforce API.
Overview
Zato connects to Salesforce through a cloud connection. You create the connection once in the Dashboard - address, API version, username, password, consumer key and consumer secret - and every Python service can then talk to Salesforce with self.salesforce. The connection obtains OAuth access tokens and attaches them to every request, so no HTTP code and no token handling appear in your services.
The connection speaks the Salesforce REST API - the same API behind Salesforce's own tooling. You call sObject and query paths such as /sobjects/Campaign/ or /query/ and Zato prefixes them with the address and API version of your connection.
Getting the credentials
Four credentials are needed and all of them come from your Salesforce org. Obtaining them is usually coordinated with an administrator of your organization.
The username and password are the same credentials that can be used to log in to Salesforce:

The consumer key and consumer secret are properties of a connected app - the term Salesforce uses for API clients that invoke its services. If you already use the Salesforce REST API directly, you may know the two under their aliases of client_id and client_secret - these are the same objects. Find the app in Setup under App Manager:

When a connected app already exists, the key and secret are available under the app's "View" menu option, not under "Edit" or "Manage":

Creating the connection
In the Dashboard, go to Cloud -> Salesforce and create a new connection:

| Field | Value |
|---|---|
| Name | My Salesforce Connection |
| API version | 54.0 |
| Address | https://yourcompany.my.salesforce.com |
| Username | The integration user's username |
| Password | The integration user's password |
| Consumer key | From the connected app |
| Consumer secret | From the connected app |
The API version pins your integration to one Salesforce release. Upgrading is a one-field change in the connection, with no code redeployment.
Calling the API
Look the connection up by name and call any of its methods - each one maps directly to an HTTP verb of the REST API:
| Method | What it does |
|---|---|
| conn.get | Reads records or runs SOQL queries |
| conn.post | Creates records |
| conn.patch | Updates records or upserts them by external ID |
| conn.delete | Deletes records |
| conn.ping | Confirms the credentials work by listing the API's resources |
The smallest possible service:
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class PingSalesforce(Service):
name = 'crm.ping-salesforce'
def handle(self):
# Get a connection to Salesforce ..
conn = self.salesforce['My Salesforce Connection']
# .. and confirm the credentials work.
response = conn.ping()
self.logger.info('Salesforce resources: %s', response)
Paths are relative to the API version of your connection - conn.get('/sobjects/Campaign/701...') really requests /services/data/v54.0/sobjects/Campaign/701... against the connection's address. Paths that already carry the full prefix, such as the nextRecordsUrl values that paginated queries return, are used as they are.
One environment can talk to any number of Salesforce orgs - create one connection definition per org and pick the right one by name in your services.
Coming from MuleSoft
If your Salesforce integrations run on MuleSoft's Salesforce Connector today, each of its operations is one REST call here:
| MuleSoft operation | The equivalent call |
|---|---|
| Create | conn.post('/sobjects/Campaign/', record) |
| Update | conn.patch(f'/sobjects/Campaign/{record_id}', changes) |
| Upsert | conn.patch(f'/sobjects/Campaign/Campaign_Code__c/{code}', record) |
| Delete | conn.delete(f'/sobjects/Campaign/{record_id}') |
| Query | conn.get('/query/?q=' + quote(soql)) |
| Query result list | Not needed - follow nextRecordsUrl from the query response |
There are no DataWeave transformations in between - your input and output are plain Python dicts, and mapping between formats is ordinary Python code. The create and query guide shows a complete flow of the kind the connector's examples build.
Configuration as YAML
The connection can be defined in YAML with enmasse and imported per environment, with secrets supplied through environment variables:
salesforce:
- name: My Salesforce Connection
address: https://yourcompany.my.salesforce.com
username: api.services@example.com
password: Zato_Enmasse_Env.Salesforce_Password
consumer_key: Zato_Enmasse_Env.Salesforce_Consumer_Key
consumer_secret: Zato_Enmasse_Env.Salesforce_Consumer_Secret
api_version: '54.0'