agentsclimarketplace

Salesforce recipes

Skill workato-devs/recipe-skills/skills/salesforce-recipes

Salesforce integration recipes for Workato. Enables AI agents to generate valid recipe JSON for Salesforce operations including record creation, updates, upserts, and searches using standard SObjects and custom objects.From its SKILL.md

Install
npx -y skills add workato-devs/recipe-skills --skill salesforce-recipes

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 18 stars18 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

20.3 KB, as published. Nobody here has run it

Salesforce Recipes Skill - Agent Instructions

⚠️ DEPENDENCY: Load the workato-recipes base skill 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:

  1. Read existing Salesforce .recipe.json files to understand local patterns

For GREENFIELD projects:

  1. Use skill templates - see templates/upsert-contact.json as reference
  2. Use descriptive UUIDs - e.g., upsert-contact-001, search-account-002

ALWAYS:

  1. Ask for connection name - exact name of Salesforce connection in Workato
  2. Confirm object type - standard (Contact, Account) vs custom (ends in __c)
  3. Verify external ID field - for upsert operations, which field is the external ID?
  4. Use API endpoint trigger for testability via curl
  5. Use descriptive UUIDs - never copy random hex UUIDs from existing recipes
  6. 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

  1. When to Use This Skill
  2. Salesforce Config Requirements
  3. Standard vs Custom Objects and Fields
  4. Native Connector Guidance
  5. Salesforce Datapill Paths
  6. Salesforce Patterns
  7. 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-recipes base 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

SuffixTypeExampleNotes
__cCustom Object/FieldBooking__c, Status__cNOT standard across orgs
__mdtCustom Metadata TypeConfig__mdtNOT standard across orgs
__ePlatform EventOrder_Event__eNOT standard across orgs
__xExternal ObjectSAP_Account__xNOT standard across orgs
(none)Standard Object/FieldContact, EmailStandard 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 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 over new_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 (+ _webhook variants 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.
  • update_sobject — Update by Salesforce record ID when you already have the ID. See detail below.
  • 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_sobjects with an Id filter or search_sobjects_soql with WHERE Id = '...'.

Search:

  • search_sobjects — Exact field match only (equality). Has critical EIS rules. See detail below.
  • search_sobjects_soql — Raw SOQL for complex criteria (LIKE, IN, OR, ORDER BY). See detail below.
  • 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 (_v1 suffix) 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 Email or Id
  • 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 name
  • id - 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 name
  • limit - 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_name and limit are connector internals — do NOT include them in extended_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 in extended_input_schema or 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.

search_sobjects_soql 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('{...date...}')}"
"query": "Amount__c > #{_dp('{...amount...}')}"

Query Syntax Quick Reference

Value TypeSyntaxExample
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('{...checkout_date...}')} AND Check_Out_Date__c >= #{_dp('{...checkin_date...}')}"

Date range query:

"query": "CreatedDate >= #{_dp('{...start_date...}')} AND CreatedDate <= #{_dp('{...end_date...}')}"

See: 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": "Contact",
    "query_field": {
      "primary_key": "Unique_Email__c"  // User specifies this field
    },
    "Unique_Email__c": "#{email}",
    "Email": "#{email}",
    "FirstName": "#{first_name}",
    "LastName": "#{last_name}"
  }
}

Pattern:

  • User provides external ID field name
  • Set the external ID field value in input
  • Set other field values
  • Workato handles create-or-update logic

2. Conditional Field Updates

Use Workato formulas (from base skill) to conditionally set fields:

"FirstName": "=_dp('{...}').present? ? _dp('{...}') : skip",
"Phone": "=_dp('{...}').present? ? _dp('{...}') : skip"

This skips fields when values are empty, preventing overwrites with blanks.

3. Search Before Update Pattern

Search for record, then update if found:

// Step 1: Search
{
  "provider": "salesforce",
  "name": "search_sobjects",
  "as": "search_contact",
  "input": {
    "sobject_name": "Contact",
    "Email": "#{email}"
  }
}

// Step 2: Check if found
{
  "keyword": "if",
  "input": {
    "conditions": [{
      "operand": "present",
      "lhs": "#{search_contact.Contact[].Id}"
    }]
  },
  "block": [
    // Update found record
    {
      "provider": "salesforce",
      "name": "update_sobject",
      "input": {
        "sobject_name": "Contact",
        "id": "#{search_contact.Contact[].Id}",
        "Status": "#{new_status}"
      }
    }
  ]
}

4. Working with Picklists

Picklist fields have specific allowed values. Use exact API values:

"Status__c": "Confirmed",           // Correct - exact picklist value
"Contact_Type__c": "Guest"          // Correct - exact picklist value

Note: Picklist values are case-sensitive and must match Salesforce configuration.

5. Required Fields

Standard SObjects have required fields:

  • Contact: LastName (required)
  • Account: Name (required)
  • Opportunity: Name, StageName, CloseDate (required)

Custom objects may have different requirements based on implementation.


Validation

See validation-checklist.md for Salesforce-specific validation, which references the base checklist in workato-recipes/validation-checklist.md.

Common Salesforce Errors

ErrorCauseSolution
"Required field missing"Missing required fieldAdd LastName for Contact, Name for Account, etc.
"Invalid field"Field doesn't exist in orgVerify field API name, check if custom field exists
"Invalid external ID field"Field not marked as External IDVerify field is marked as External ID in Salesforce
"Duplicate value"Unique constraint violationCheck for existing records before creating
"Invalid picklist value"Wrong picklist valueUse exact API value from Salesforce picklist
Query returns no results unexpectedlyUsing SOQL bind variable syntaxReplace :#{datapill} with '#{datapill}' for strings

Extended Input Schema Requirements

Like all Workato connectors, Salesforce actions require complete extended_input_schema definitions.

Salesforce-Specific Schema Fields

Salesforce schema entries include metadata fields:

{
  "name": "Email",
  "label": "Email",
  "type": "string",
  "control_type": "text",
  "custom": false,              // false for standard, true for custom
  "optional": true,
  "sfdc_createable": true,      // Can be set on create
  "sfdc_updateable": true       // Can be updated
}

Custom field example:

{
  "name": "Contact_Type__c",
  "label": "Contact Type",
  "type": "string",
  "control_type": "select",
  "custom": true,               // Custom field
  "optional": true,
  "pick_list": "sobject_field_values_list",
  "sfdc_createable": true,
  "sfdc_updateable": true
}

Templates

See templates/ directory:

  • upsert-contact.json - Upsert contact with external ID
  • search-contact.json - Search contact by email
  • update-record.json - Update record by Salesforce ID

References

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.