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). LIKEworks, but there is noILIKE— text comparisons are already case-insensitive.
The describe-then-query loop
For any object you haven't queried before — and always for custom objects:
salesforce_list_objectswith a filter to find the API name.salesforce_describe_objectto get field API names, types, picklist values, and which fields are required.- 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.