Install
$ agentstack add skill-workato-devs-recipe-skills-salesforce-recipes ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Salesforce Recipes Skill - Agent Instructions
> ⚠️ DEPENDENCY: Load /workato-recipes first if not already loaded. > This skill requires the base Workato knowledge for triggers, control flow, datapills, formulas, and recipe structure.
This skill provides Salesforce-specific knowledge for generating Workato recipes. It extends the workato-recipes base skill and focuses on Salesforce-specific patterns.
CRITICAL: Pre-Generation Checklist
For EXISTING projects:
- Read existing Salesforce
.recipe.jsonfiles to understand local patterns
For GREENFIELD projects:
- Use skill templates - see
templates/upsert-contact.jsonas reference - Use descriptive UUIDs - e.g.,
upsert-contact-001,search-account-002
ALWAYS:
- Ask for connection name - exact name of Salesforce connection in Workato
- Confirm object type - standard (Contact, Account) vs custom (ends in
__c) - Verify external ID field - for upsert operations, which field is the external ID?
- Use API endpoint trigger for testability via curl
- Use descriptive UUIDs - never copy random hex UUIDs from existing recipes
- Remember datapill paths - Salesforce does NOT use
["body"]wrapper
> WARNING: Never assume custom objects/fields exist. Always ask if uncertain whether an object or field is custom. Custom objects are org-specific and NOT portable.
Table of Contents
- [When to Use This Skill](#when-to-use-this-skill)
- [Salesforce Config Requirements](#salesforce-config-requirements)
- [Standard vs Custom Objects and Fields](#standard-vs-custom-objects-and-fields)
- [Native Connector Guidance](#native-connector-guidance)
- [Salesforce Datapill Paths](#salesforce-datapill-paths)
- [Salesforce Patterns](#salesforce-patterns)
- [Pre-Push Checklist (Salesforce)](#pre-push-checklist-salesforce)
When to Use This Skill
Use this skill when building Workato recipes that:
- Search Salesforce records (Contacts, Accounts, Opportunities, Cases, Leads, custom objects)
- Create new records in Salesforce
- Upsert records using external IDs
- Update existing records by Salesforce ID
- Work with standard or custom SObjects
Prerequisites:
workato-recipesbase skill loaded- Workato workspace with Salesforce connection configured
- Understanding of the target Salesforce org's object schema
Salesforce Config Requirements
Every Salesforce recipe requires the salesforce provider in the config section:
{
"keyword": "application",
"provider": "salesforce",
"skip_validation": false,
"account_id": {
"zip_name": "Workspace Connections/salesforce_connection.connection.json",
"name": "Salesforce Connection Name",
"folder": "Workspace Connections"
}
}
Combined with trigger provider:
For callable recipe trigger:
"config": [
{ "provider": "workato_recipe_function", "account_id": null, ... },
{ "provider": "salesforce", "account_id": { ... }, ... },
{ "provider": "logger", "account_id": null, ... }
]
Standard vs Custom Objects and Fields
CRITICAL: Custom Objects Are Implementation-Specific
Standard SObjects (available in ALL Salesforce orgs):
Contact,Account,Lead,Opportunity,Case,Task,Event- Standard fields:
Id,Name,Email,Phone,AccountId, etc.
Custom Objects and Fields (specific to each Salesforce implementation):
- Custom objects:
Booking__c,Room__c,Property__c - Custom fields:
Contact_Type__c,Unique_Email__c,Status__c - Custom metadata types:
Config__mdt,Settings__mdt
Object and Field Suffixes
| Suffix | Type | Example | Notes | |--------|------|---------|-------| | __c | Custom Object/Field | Booking__c, Status__c | NOT standard across orgs | | __mdt | Custom Metadata Type | Config__mdt | NOT standard across orgs | | __e | Platform Event | Order_Event__e | NOT standard across orgs | | __x | External Object | SAP_Account__x | NOT standard across orgs | | (none) | Standard Object/Field | Contact, Email | Standard across all orgs |
Agent Requirements for Custom Objects
> WARNING: When generating recipes that use custom objects or fields (anything with __c, __mdt, __e, __x), you MUST: > > 1. Never assume these objects/fields exist in the target environment > 2. Document clearly that the recipe requires specific custom objects/fields > 3. Ask the user if uncertain whether an object/field is custom or standard > 4. Use standard objects whenever possible for maximum portability
Example of proper documentation:
{
"name": "Upsert contact with custom type",
"description": "REQUIRES CUSTOM FIELD: Contact.Contact_Type__c (picklist)",
...
}
Native Connector Guidance
The Salesforce connector provides 32 native actions and 15 triggers. See lint-rules.json for the authoritative list of valid action and trigger names.
> CRITICAL: All Salesforce actions require dynamicPickListSelection in addition to the input block. See [dynamicPickListSelection](#dynamicpicklistselection-critical) below.
Choosing the Right Trigger
- Polling (most common):
scheduled_sobject_soql_query— runs a SOQL query on a schedule to detect new/changed records. V2 variant:scheduled_sobject_soql_query_v2. - Real-time CDC:
change_data_capture— streams record changes as they happen. Requires CDC enabled on the SObject. Prefer overnew_pushtopic_event(legacy). - Platform Events:
new_platform_event— listens for platform event messages. - Outbound Messages:
new_outbound_message— triggered by Salesforce workflow/process builder. - Bulk:
sobject_created_bulk,sobject_batch_created,scheduled_sobject_bulk_v2_created,scheduled_sobject_bulk_v2_created_or_updated— for high-volume record processing. - Custom objects:
new_custom_object,updated_custom_object(+_webhookvariants for real-time). - Deletions:
sobject_deleted— triggers on record deletion.
Choosing the Right Action
Record CRUD:
upsert_sobject— Create or update by external ID. Best default for sync workflows. See [detail below](#upsert_sobject-detail).update_sobject— Update by Salesforce record ID when you already have the ID. See [detail below](#update_sobject-detail).delete_sobject— Delete by Salesforce record ID.create_custom_object/get_custom_object— Create or retrieve custom object records.- No native "get standard record by ID" action — use
search_sobjectswith anIdfilter orsearch_sobjects_soqlwithWHERE Id = '...'.
Search:
search_sobjects— Exact field match only (equality). Has critical EIS rules. See [detail below](#search_sobjects-detail).search_sobjects_soql— Raw SOQL for complex criteria (LIKE, IN, OR, ORDER BY). See [detail below](#searchsobjectssoql-detail).search_sobjects_soql_v2— V2 of SOQL search.
Bulk operations (thousands+ records):
insert_bulk_job/upsert_bulk_job/update_bulk_job— Bulk create/upsert/update. V1 variants (_v1suffix) also available.retry_bulk_jobs— Retry failed bulk jobs.search_sobjects_soql_bulk_csv/_v2— Bulk SOQL query returning CSV.
Composite (multiple operations in one API call):
composite_create_sobject/composite_update_sobject/upsert_composite_sobject
Approvals: approve_process, reject_process, submit_process
Files & attachments: upload_file_content, get_attachment_body, get_combined_attachment
Reports & metadata: get_report_by_id, get_related, get_sobject_schema
Platform events: create_custom_platform_event
Data categories: list_data_category_groups, read_data_category_group
Uncovered operations: Use __adhoc_http_action for REST API endpoints, Tooling API, Metadata API, or custom Apex REST services not covered by native actions.
dynamicPickListSelection (CRITICAL)
All Salesforce actions require dynamicPickListSelection in addition to the input block. This is used by the Workato UI for field discovery.
{
"provider": "salesforce",
"name": "upsert_sobject",
"as": "upsert_contact",
"keyword": "action",
"dynamicPickListSelection": {
"sobject_name": "Contact",
"query_field.primary_key": [
{ "label": "Email", "value": "Email" }
]
},
"input": {
"sobject_name": "Contact",
"query_field": { "primary_key": "Email" },
...
}
}
Note: Both dynamicPickListSelection.sobject_name AND input.sobject_name are required. They should have the same value.
upsert_sobject Detail
Use when: Creating or updating records based on an external ID field.
{
"provider": "salesforce",
"name": "upsert_sobject",
"as": "upsert_contact",
"keyword": "action",
"dynamicPickListSelection": {
"sobject_name": "Contact",
"query_field.primary_key": [
{ "label": "Email", "value": "Email" }
]
},
"input": {
"sobject_name": "Contact",
"query_field": {
"primary_key": "Email"
},
"Email": "#{email_datapill}",
"FirstName": "#{first_name_datapill}",
"LastName": "#{last_name_datapill}"
}
}
Key fields:
sobject_name- SObject API name (e.g.,Contact,Account,Booking__c)query_field.primary_key- Field to use for upsert matching (must be marked as External ID in Salesforce OR be a standard unique field)- Other fields - SObject field values to set
IMPORTANT: The query_field.primary_key value must be:
- A field marked as "External ID" in Salesforce, OR
- A standard unique field like
EmailorId - User must specify which field to use - do not assume
update_sobject Detail
Use when: Updating an existing record by Salesforce ID.
{
"provider": "salesforce",
"name": "update_sobject",
"as": "update_booking",
"keyword": "action",
"input": {
"sobject_name": "Booking__c",
"id": "#{booking_id_datapill}",
"Status__c": "#{status_datapill}",
"Check_Out_Date__c": "=checkout_date_datapill"
}
}
Key fields:
sobject_name- SObject API nameid- Salesforce 18-character record ID (required)- Other fields - Field values to update
search_sobjects Detail
Use when: Finding records by exact field match (equality only, no LIKE/IN/OR).
{
"provider": "salesforce",
"name": "search_sobjects",
"as": "search_contact",
"keyword": "action",
"dynamicPickListSelection": {
"sobject_name": "Contact"
},
"input": {
"sobject_name": "Contact",
"limit": "150",
"Email": "#{email_datapill}"
},
"extended_input_schema": [
{
"control_type": "text",
"label": "Email",
"name": "Email",
"type": "string"
}
]
}
Key fields:
sobject_name- SObject API namelimit- Max records to return (default 150)- Search criteria fields - Field names with values to match (exact equality)
Output: Returns array of matching records
CRITICAL - EIS Rules for search_sobjects:
sobject_nameandlimitare connector internals — do NOT include them inextended_input_schema. Including them causes Workato to treat them as WHERE clause field filters, producing malformed SOQL.- Search filter fields (e.g.,
Email,Id,AccountId) MUST be inextended_input_schemaor Workato silently drops them. - Only include actual Salesforce field names in EIS, never connector parameters.
IMPORTANT - Limit Parameter Type:
When accepting limit as a user input parameter, use integer type in the schema:
{
"name": "limit",
"type": "integer",
"control_type": "integer",
"parse_output": "integer_conversion"
}
Do NOT use "type": "number" - this causes Workato to treat values as floats, producing malformed SOQL (e.g., LIMIT 50.0) which Salesforce rejects.
searchsobjectssoql Detail
Use when: Finding records with complex criteria (LIKE, IN, OR, ORDER BY, relationship fields) using raw SOQL.
CRITICAL: Use action name search_sobjects_soql, NOT search_sobjects with a query parameter. The query parameter is not recognized by search_sobjects via CLI push — it gets treated as a field name.
{
"provider": "salesforce",
"name": "search_sobjects_soql",
"as": "search_bookings",
"keyword": "action",
"dynamicPickListSelection": {
"sobject_name": "Booking"
},
"input": {
"sobject_name": "Booking__c",
"query": "Room__r.Room_Number__c = '#{_dp('{...room_number...}')}' AND Status__c NOT IN ('Cancelled', 'No Show')"
}
}
SOQL Query Syntax in search_sobjects
CRITICAL: No Bind Variables
Workato's Salesforce connector does NOT support SOQL bind variable syntax (:variable). Use direct string interpolation instead.
WRONG (bind variable syntax - WILL NOT WORK):
"query": "Email = :#{_dp('...email...')}"
"query": "Room_Number__c = :#{_dp('...room...')}"
CORRECT (string values - wrap in single quotes):
"query": "Email = '#{_dp('{\"pill_type\":\"output\",\"provider\":\"workato_recipe_function\",\"line\":\"trigger\",\"path\":[\"parameters\",\"email\"]}')}'"
"query": "Room_Number__c = '#{_dp('{...room_number...}')}'"
CORRECT (dates/numbers - no quotes):
"query": "Check_In_Date__c #{_dp('{...amount...}')}"
Query Syntax Quick Reference
| Value Type | Syntax | Example | |------------|--------|---------| | String | '#{datapill}' | Email = '#{_dp(...)}' | | Date | #{datapill} | CreatedDate >= #{_dp(...)} | | Number | #{datapill} | Amount > #{_dp(...)} | | Boolean | #{datapill} | IsActive = #{_dp(...)} | | Picklist | '#{datapill}' | Status = '#{_dp(...)}' |
Complex Query Examples
Multi-condition query:
"query": "Room__r.Room_Number__c = '#{_dp('{...room_number...}')}' AND Status__c NOT IN ('Cancelled', 'No Show', 'Checked Out') AND Check_In_Date__c = #{_dp('{...checkin_date...}')}"
Date range query:
"query": "CreatedDate >= #{_dp('{...start_date...}')} AND CreatedDate <= #{_dp('{...end_date...}')}"
See: [patterns/soql-query-syntax.md](patterns/soql-query-syntax.md)
Salesforce Datapill Paths
CRITICAL: No Body Wrapper
Salesforce actions do NOT use the ["body"] wrapper in datapill paths.
This is consistent with Stripe and other native connectors:
// CORRECT for Salesforce
"path": ["Id"]
"path": ["Email"]
"path": ["Status__c"]
"path": ["Account", "Name"]
// WRONG for Salesforce - Do NOT use
"path": ["body", "Id"]
Salesforce Datapill Examples
Record ID from upsert:
"#{_dp('{\"pill_type\":\"output\",\"provider\":\"salesforce\",\"line\":\"upsert_contact\",\"path\":[\"id\"]}')}"
Standard field:
"#{_dp('{\"pill_type\":\"output\",\"provider\":\"salesforce\",\"line\":\"search_contact\",\"path\":[\"Contact\",{\"path_element_type\":\"current_item\"},\"Email\"]}')}"
Custom field:
"#{_dp('{\"pill_type\":\"output\",\"provider\":\"salesforce\",\"line\":\"upsert_booking\",\"path\":[\"Status__c\"]}')}"
Relationship field (dot notation in Salesforce, nested in datapill):
"#{_dp('{\"pill_type\":\"output\",\"provider\":\"salesforce\",\"line\":\"search_contact\",\"path\":[\"Contact\",{\"path_element_type\":\"current_item\"},\"Account\",\"Name\"]}')}"
Search Results Array Access
Search actions return arrays. Use path_element_type: current_item to access array elements:
"path": ["Contact", {"path_element_type": "current_item"}, "Id"]
Salesforce Patterns
1. Upsert with External ID
Always specify the external ID field when upserting:
{
"provider": "salesforce",
"name": "upsert_sobject",
"as": "upsert_contact",
"input": {
"sobject_name": "Contac
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [workato-devs](https://github.com/workato-devs)
- **Source:** [workato-devs/recipe-skills](https://github.com/workato-devs/recipe-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.