Salesforce Module
Read and write Salesforce records from any flow: SOQL queries and SOSL searches, create, update, upsert and delete records, read an object's fields or the org's API limits, or call any REST resource of the org.
Typical uses: create or update a Lead for every booking, chat or form submission; look up an Account by email before answering a customer; push an Opportunity stage change from a timer; read a picklist's values to validate what a caller said.
The Salesforce Module adds four Tasks and no Start: Salesforce events do not start a flow yet (see Limits below).
Requirements
- A Salesforce org (Enterprise, Unlimited, Developer or Performance editions have API access; Professional needs the API add-on).
- One of two sign-ins (see Configuration):
- Connect Salesforce: the platform's connected app must be set up by a platform administrator (
SalesforceModule:OAuth:ClientId/ClientSecret, callbackhttps://engine(-dev).ew-flow.com/api/oauth/salesforce/callback, scopes api, refresh_token, offline_access, id, PKCE on). A user of your org then signs in once per environment. - Client credentials: your own connected app in your org with Enable Client Credentials Flow and a run-as user.
- Connect Salesforce: the platform's connected app must be set up by a platform administrator (
- Every call counts against the org's daily API allowance.
Configuration
The Salesforce Module is configured per Environment, so Development can point at a sandbox and Production at the live org.
| Field | Type | Required | Description |
|---|---|---|---|
| Sign in with | choice | Yes | Connect Salesforce (a user signs in; tasks act as that user) or Client credentials (your own connected app; tasks act as its run-as user). |
| Login address | string | No | https://login.salesforce.com (production, Developer Edition), https://test.salesforce.com (sandboxes) or the org's My Domain (https://acme.my.salesforce.com, https://acme--dev.sandbox.my.salesforce.com). Must be a salesforce.com address. Set it before connecting: Connect sends the user there. |
| Salesforce account | button | Connect mode | Connect Salesforce signs in with Salesforce (workspace owners and admins only). The sign-in is stored encrypted on the engine and renewed with its refresh token; it is never shown. The field shows the connected user, the org and its instance. Disconnect revokes the sign-in. |
| Consumer key | string | Client credentials | The connected app's consumer key (Setup → App Manager → your app → Manage Consumer Details). |
| Consumer secret | password | Client credentials | The connected app's consumer secret. Stored securely. |
| API version | string | No | Advanced. The REST API version, as v62.0. Empty: v62.0. |
Which sign-in?
| Connect Salesforce | Client credentials | |
|---|---|---|
| Who the tasks act as | the user who connected (their permissions, their name on records) | the connected app's run-as user |
| Set-up in Salesforce | none in your org (the platform's app is used) | create a connected app, enable the client credentials flow, pick a run-as user |
| Expiry | renewed automatically; a revoked or expired refresh token shows Reconnect on the field | a token is issued when needed; nothing to renew |
| Sandboxes | set the login address to https://test.salesforce.com first | set the login address to the sandbox's My Domain |
In both modes the sign-in is refused when the token or an instance address is not on salesforce.com.
Salesforce query
Reads records. The result is written to Save records as (default {records}).
| Field | Type | Required | Description |
|---|---|---|---|
| Operation | choice | Yes | Query (SOQL), Query all (with deleted) (includes deleted and archived records: queryAll), Search (SOSL). |
| SOQL | SQL | Query | A SELECT statement. Put {variables} inside single quotes: each value is escaped for a SOQL string (', \, line breaks), so data cannot change the query. Relationship fields (Account.Name) and subqueries ((SELECT Id FROM Contacts)) are returned nested. |
| SOSL | SQL | Search | A FIND {…} … RETURNING Object(fields) search. {variables} are escaped the same way. |
| Max records | number | No | How many records to read at most, following Salesforce's pages (2000 rows each). 1–50000. Empty: 2000. |
Output {records}:
| Field | Description |
|---|---|
count | Records in items. |
totalSize | Records that matched in Salesforce (may be more than count when Max records stopped the read). |
done | True when every matching record was read. |
items | The records with their Salesforce field names: {records.items.0.Name}, {records.items.0.Account.Name}, {records.items.0.Contacts.0.Email}. The attributes envelope is removed. |
SOQL only reads. A query that does not start with SELECT (or a search that does not start with FIND) is refused before Salesforce is called.
Salesforce record
Reads or writes one record.
| Field | Type | Required | Description |
|---|---|---|---|
| Operation | choice | Yes | Get, Create, Update, Upsert, Delete. |
| Object | string | Yes | The object's API name: Account, Contact, Lead, Opportunity, Case, Invoice__c… |
| Record id | string | Get, Update, Delete | The 15- or 18-character id. |
| External id field | string | Upsert | A field marked External ID on the object. |
| External id | string | Upsert | The value to match. The record holding it is updated; when none does, one is created. |
| Fields to read | string | No (Get) | Comma-separated fields, relationship paths allowed (Owner.Name). Empty: every field. |
| Fields | rows | Create, Update, Upsert | One row per field: the field's API name and its value. A value that is exactly one {variable} keeps the variable's type (number, boolean, list, object); any other text is sent as text, which Salesforce converts for numbers, dates (YYYY-MM-DD), date-times (ISO 8601) and checkboxes (true/false). An empty value clears the field. A relationship can be set by external id: Account.External_Id__c. |
Outputs:
- Get → Save record as (default
{record}): the record with its Salesforce field names,{record.Id},{record.Name},{record.Owner.Name}. - Create, Update, Upsert, Delete → Save result as (default
{result}):id,outcome(created,updated,deleted),created(true when an upsert created the record),object.
Salesforce metadata
| Operation | Output | Content |
|---|---|---|
| Describe object (needs Object) | {object} | name, label, labelPlural, keyPrefix, custom, queryable, createable, updateable, deletable, fieldCount, fields (list) and fieldsByName (by API name): each field's name, label, type, length, required (a create must give it a value), custom, createable, updateable, externalId, referenceTo, relationshipName, picklistValues (active values: value, label, default); childRelationships (childObject, field, relationshipName). |
| List objects | {objects} | count, names (API names), items (name, label, labelPlural, keyPrefix, custom, queryable, createable, updateable, deletable). |
| Limits | {limits} | dailyApiRequestsMax, dailyApiRequestsRemaining, dataStorageMbMax, dataStorageMbRemaining, fileStorageMbMax, fileStorageMbRemaining, and all with every limit Salesforce reports ({limits.all.DailyBulkApiBatches.remaining}). |
Salesforce API call
Any REST resource of the connected org, for what the other tasks do not cover: Apex REST, the composite API, Chatter, reports.
| Field | Type | Required | Description |
|---|---|---|---|
| Method | choice | Yes | GET, POST, PATCH, PUT, DELETE. |
| Path | string | Yes | Relative to /services/data/{version} (for example /composite/sobjects, /sobjects/Account/describe), or a full path starting with /services/ (Apex REST: /services/apexrest/Orders). A query string is allowed. Full addresses are refused: the call always goes to the connected org. |
| Body (JSON) | JSON | POST, PATCH, PUT | The JSON body. Each {variable} is escaped as the inside of a JSON string, so put it inside quotes unless it holds a number, true/false or JSON you trust. |
Output Save response as (default {response}): status and body (an object or list when Salesforce answered JSON, else the text; empty for 204).
Errors
Every Salesforce task takes its error flow when the call fails, and writes {salesforceError}:
| Field | Description |
|---|---|
code | Salesforce's own error code: MALFORMED_QUERY, INVALID_FIELD, REQUIRED_FIELD_MISSING, DUPLICATES_DETECTED, FIELD_CUSTOM_VALIDATION_EXCEPTION, NOT_FOUND, INVALID_SESSION_ID, REQUEST_LIMIT_EXCEEDED… or input (a field of the task is wrong), not_configured (no sign-in for the environment), unauthorized, forbidden, not_found, rate_limited, transient, invalid. |
message | What went wrong, in Salesforce's words when it gave them. |
fields | The fields Salesforce named, when it did (REQUIRED_FIELD_MISSING). |
status | The HTTP status. |
Route business conflicts with a Switch on {salesforceError.code}: a DUPLICATES_DETECTED on a create can go to an update branch; anything else to a support branch.
A 401 is handled before you see it: the sign-in is renewed once and the call repeated. When Salesforce refuses the renewed token too, the field shows Reconnect and the tasks fail with not_configured until someone reconnects.
Limits
- Tasks only. Platform events, Change Data Capture and outbound messages do not start a flow yet. To start a flow from Salesforce today, call a Form or Data start from a Salesforce Flow's HTTP callout.
- One record per write. For bulk loads use the Salesforce API call task with the composite API (
/composite/sobjects, up to 200 records), or the Bulk API 2.0. - A query reads at most 50000 records.
- Records are returned with Salesforce's field names, not camelCase:
{records.items.0.Name}, not{records.items.0.name}.