← Salesforce integration

Querying Salesforce with SOQL

Nearly every Salesforce read is one salesforce_soql_query call. SOQL looks like SQL but is narrower in ways that bite if you assume otherwise.

What SOQL does not have

  • No SELECT *. You must name every field. Describe the object first if you don't know the field API names.
  • No arbitrary joins. You traverse relationships instead: - Child → parent, with dots: SELECT Id, Account.Name, Account.Industry FROM Contact - Parent → children, with a subquery: SELECT Name, (SELECT LastName FROM Contacts) FROM Account
  • Custom objects and fields end in __c (Branch__c, Project__c.Region__c), and custom relationship traversals use __r (Project__r.Name).
  • LIKE works, but there is no ILIKE — text comparisons are already case-insensitive.

The describe-then-query loop

For any object you haven't queried before — and always for custom objects:

  1. salesforce_list_objects with a filter to find the API name.
  2. salesforce_describe_object to get field API names, types, picklist values, and which fields are required.
  3. Compose the SOQL against those exact names.

Field labels shown in the Salesforce UI are frequently not the API names, so guessing from a screenshot or a user's description tends to fail on the first try. One describe call removes the guessing.

Pagination

A query returns roughly the first 2000 records with done: false and a nextRecordsUrl. Pass that URL back as next_records_url to get the next batch, and keep going until done is true. Aggregates (COUNT(), GROUP BY) avoid the problem entirely when you only need totals.

Date literals make period reporting easy

SOQL has built-in relative date literals — no date arithmetic needed:

SELECT StageName, COUNT(Id), SUM(Amount)
FROM Opportunity
WHERE CloseDate = THIS_QUARTER
GROUP BY StageName

Useful ones: TODAY, YESTERDAY, THIS_WEEK, THIS_MONTH, LAST_MONTH, THIS_QUARTER, THIS_YEAR, LAST_N_DAYS:30, NEXT_N_DAYS:7.

Writing records

salesforce_create_record and salesforce_update_record take field API names mapped to values, and both require approval before they run. Describe the object first: required fields are not guessable, picklist fields reject values outside their active set, and lookup fields expect a record ID rather than a name.

Multiple orgs

One connected org = one account asset, each with its own instance URL. When more than one is connected, pass accountId to pick the org — production and sandbox orgs are separate connections.