Skip to main content

Salesforce Integration

Connect your AI agents to Salesforce CRM

One-Click Connect available! Salesforce connects via OAuth. Just click “Connect Platform” and authorize. No API keys, tokens, or manual configuration needed.

Step 1: Connect Salesforce

Recommended: Use the one-click OAuth connection. It automatically handles authentication, token refresh, and grants access to all Salesforce API scopes your account supports.

  1. 1Go to Settings Integrations
  2. 2Click Connect Platform Salesforce
  3. 3Log in to your Salesforce account and click Allow to authorize the connection
  4. 4Done! Your access token refreshes automatically. No maintenance needed
DetailValue
Base URLYour Salesforce instance URL (set automatically)
Auth TypeOAuth 2.0 (automatic)
Token RefreshAutomatic when expired
API Versionv59.0

Step 2: Add Actions with Pre-Built Templates

Once connected, click Add Action to open the template picker. Choose from 56 pre-built actions across 13 Salesforce object types, so there is no need to configure endpoints, SOQL queries, or body templates manually.

New: Pre-built templates configure everything for you in one click. Just select a template, review the settings, and save. You can always customize the action after adding it.

Available Templates (56 total)

Contacts

GETSearch Contact
POSTCreate Contact
PATCHUpdate Contact
DELETEDelete Contact

Leads

GETSearch Lead
POSTCreate Lead
PATCHUpdate Lead
DELETEDelete Lead

Accounts

GETSearch Account
POSTCreate Account
PATCHUpdate Account
DELETEDelete Account

Opportunities

GETSearch Opportunity
POSTCreate Opportunity
PATCHUpdate Opportunity
DELETEDelete Opportunity

Cases

GETSearch Case
POSTCreate Case
PATCHUpdate Case
DELETEDelete Case

Tasks

GETSearch Task
POSTLog Call / Create Task
PATCHUpdate Task
DELETEDelete Task

Events

GETSearch Event
POSTSchedule Event
PATCHUpdate Event
DELETEDelete Event

Notes 4 templates

POSTCreate Note
GETGet Note
PATCHUpdate Note
DELETEDelete Note

Knowledge

GETSearch Knowledge
GETGet Article

Users & Queues

GETSearch Users
GETGet User
GETList Queues

Products 7 templates

GETSearch Products
POSTCreate Product
GETSearch Pricebook Entries
POSTAdd Product to Opportunity
PATCHUpdate Product
DELETEDelete Product
DELETERemove Product from Opportunity

Campaigns 6 templates

GETSearch Campaigns
POSTCreate Campaign
POSTAdd Campaign Member
PATCHUpdate Campaign
DELETEDelete Campaign
DELETERemove Campaign Member

Direct Lookups

GETGet Contact by ID
GETGet Lead by ID
GETGet Account by ID
GETGet Opportunity by ID
GETGet Case by ID
GETGlobal Search

Tip: You can add the same template multiple times (e.g. two “Search Contact” actions with different configurations). Each gets a unique name automatically.

What Each Action Does

GET

Search

List all records or filter by a search term using SOQL (Salesforce Object Query Language). The AI can call this with or without a search query.

BehaviorDescription
No search termReturns all records (up to 10, ordered by last modified)
With search termFilters by name, email, phone, or other fields using SOQL LIKE (partial match)
Case number searchUses exact match (CaseNumber='...') instead of LIKE for reliable numeric lookups
ConfirmationNot required (read-only)
API Endpoint/services/data/v59.0/query/?q=SELECT...FROM...

Example: customer says “show me all contacts”:

GET /services/data/v59.0/query/?q=SELECT+Id,FirstName,LastName,Email,Phone,MobilePhone,Title,AccountId
  +FROM+Contact+ORDER+BY+LastModifiedDate+DESC+LIMIT+10

Response:
{
  "totalSize": 3,
  "done": true,
  "records": [
    {
      "Id": "003XX000004TmfQQAS",
      "FirstName": "Sarah",
      "LastName": "Johnson",
      "Email": "[email protected]",
      "Phone": "+15551234567"
    },
    ...
  ]
}

Example: customer says “find Sarah Johnson”:

GET /services/data/v59.0/query/?q=SELECT+Id,FirstName,LastName,Email,Phone
  +FROM+Contact
  +WHERE+Name+LIKE+'%25Sarah Johnson%25'
  +OR+Email+LIKE+'%25Sarah Johnson%25'
  +OR+Phone+LIKE+'%25Sarah Johnson%25'
  +ORDER+BY+LastModifiedDate+DESC+LIMIT+10

How it works: When a search_term is provided, the template adds WHERE ... LIKE '%term%' clauses across multiple fields. When no search term is given, the placeholders are removed and it returns all records up to the limit. Note: %25 in the URL is the URL-encoded form of % (the SOQL wildcard).

POST

Create

Create a new record. The AI collects the required fields from the customer and confirms before creating. Salesforce uses flat JSON (no nested “properties” wrapper).

BehaviorDescription
Required fieldsVaries by object (see table below)
Optional fieldsAutomatically excluded if not provided
ConfirmationRequired (AI confirms details before creating)
API Endpoint/services/data/v59.0/sobjects/{Object}/

Required Fields by Object

ObjectRequired FieldsRecommended Fields
ContactLastNameFirstName, Email, Phone
LeadLastName, CompanyFirstName, Email, Phone, Status
AccountNamePhone, Website, Industry
OpportunityName, StageName, CloseDateAmount, AccountId
Case(none strictly required)Subject, ContactId, Description, Priority
Task(none strictly required)Subject, WhoId, Status, Priority
EventSubject, StartDateTime, EndDateTimeWhoId, WhatId, Location, Description
Note (ContentNote)TitleContent (Base64-encoded body)
Product (Product2)NameProductCode, Description, IsActive
CampaignNameStatus, Type, StartDate, EndDate
Campaign MemberCampaignId, ContactId or LeadIdStatus

Example: creating a contact:

POST /services/data/v59.0/sobjects/Contact/

{
  "FirstName": "Sarah",
  "LastName": "Johnson",
  "Email": "[email protected]",
  "Phone": "+15551234567"
}

Response (201 Created):
{
  "id": "003XX000004TmfQQAS",
  "success": true,
  "errors": []
}

Flat JSON: Unlike HubSpot which wraps fields in a "properties": {} object, Salesforce takes fields directly at the top level. Field names use PascalCase (e.g. FirstName, LastName).

PATCH

Update

Update specific fields on an existing record. The AI uses the record ID from a previous search and only sends the fields that need to change.

BehaviorDescription
Record IDFrom a previous search result (e.g. contact_id)
Partial updatesOnly changed fields are sent -- other fields stay untouched
ConfirmationRequired (AI confirms the change before updating)
API Endpoint/services/data/v59.0/sobjects/{Object}/{id}

Example: updating only the email:

PATCH /services/data/v59.0/sobjects/Contact/003XX000004TmfQQAS

{
  "Email": "[email protected]"
}

Response: 204 No Content (empty response = success!)

Important: Salesforce returns 204 No Content for successful updates, meaning the response body is empty. An empty response is the success signal! This is different from HubSpot, which returns the updated record as JSON.

DELETE

Delete

Soft-delete a record from Salesforce. The record goes to the Recycle Bin and can be recovered for 15 days.

BehaviorDescription
Record IDFrom a previous search result
ConfirmationRequired (AI always confirms before deleting)
DestructiveYes -- marked as destructive action
RecoveryRecord stays in Recycle Bin for 15 days

Example:

DELETE /services/data/v59.0/sobjects/Contact/003XX000004TmfQQAS

Response: 204 No Content (empty response = success!)

Safety: Delete actions are marked as destructive. The AI will always ask the customer for explicit confirmation before deleting. Records go to the Recycle Bin for 15 days, so accidental deletes can be recovered from Salesforce Setup. Consider adding Identity Verification to prevent unauthorized deletions.

POST

Tasks: Call Logging

The “Log Call / Create Task” template is special: it pre-sets TaskSubtype to "Call", so the task appears as a Logged Call in the Salesforce Activity Timeline, not just a regular task.

FieldPurposeExample Values
SubjectTitle of the logged call"Inbound call re: billing issue"
CallTypeDirection of the callInbound
CallDispositionOutcome of the callConnected, Left Voicemail, No Answer
DescriptionNotes about the callCaller reported..."
WhoIdLinks to a Contact or LeadContact/Lead ID from search
WhatIdLinks to an Account, Opportunity, or CaseAccount/Opp/Case ID from search
TaskSubtypePre-set to "Call" by template(automatic)

Example: logging a call linked to a contact and case:

POST /services/data/v59.0/sobjects/Task/

{
  "Subject": "Inbound call - billing question",
  "TaskSubtype": "Call",
  "CallType": "Inbound",
  "CallDisposition": "Connected",
  "Description": "Customer called about invoice #1234. Issue resolved.",
  "WhoId": "003XX000004TmfQQAS",
  "WhatId": "500XX000001ABCDEF",
  "Status": "Completed",
  "Priority": "Normal"
}

Response:
{
  "id": "00TXX000003GHIJKL",
  "success": true,
  "errors": []
}

Activity Timeline: Because TaskSubtype is set to "Call", this shows up in the “Logged Calls” section of the contact's Activity Timeline in Salesforce, not in the regular tasks list. WhoId links to a person (Contact or Lead), while WhatId links to a thing (Account, Opportunity, or Case).

POST

Events: Scheduling

Schedule meetings, callbacks, or appointments on the Salesforce calendar. Both StartDateTime and EndDateTime are required in ISO 8601 format.

FieldPurposeExample Values
SubjectTitle of the event"Follow-up call with Sarah"
StartDateTimeWhen the event begins (required)2026-02-12T10:00:00.000Z
EndDateTimeWhen the event ends (required)2026-02-12T10:30:00.000Z
LocationWhere the event takes place"Phone", "Zoom", "Office"
DescriptionDetails about the event"Discuss renewal options"
WhoIdLinks to a Contact or LeadContact/Lead ID from search
WhatIdLinks to Account, Opportunity, or CaseAccount/Opp/Case ID from search

Example: scheduling a callback for tomorrow:

POST /services/data/v59.0/sobjects/Event/

{
  "Subject": "Callback - discuss renewal options",
  "StartDateTime": "2026-02-12T10:00:00.000Z",
  "EndDateTime": "2026-02-12T10:30:00.000Z",
  "Description": "Customer requested callback to discuss contract renewal.",
  "WhoId": "003XX000004TmfQQAS",
  "WhatId": "006XX000001OPQRST",
  "Location": "Phone"
}

Response:
{
  "id": "00UXX000002MNOPQR",
  "success": true,
  "errors": []
}

ISO 8601 format: Both StartDateTime and EndDateTime must be in ISO 8601 format (e.g. 2026-02-12T10:00:00.000Z). The AI automatically converts natural language like “tomorrow at 10am” into the correct format.

POST

Notes

Create, retrieve, and delete notes attached to Salesforce records. Notes use the ContentNote object and are linked to parent records via ContentDocumentLink.

ActionMethodDescription
Create NotePOSTCreate a new note and optionally link it to a record (Contact, Account, Case, etc.)
Get NoteGETRetrieve a note by its ContentNote ID, including title and body
Delete NoteDELETEDelete a note by its ContentNote ID

Example: creating a note linked to a contact:

POST /services/data/v59.0/sobjects/ContentNote/

{
  "Title": "Call summary - billing question",
  "Content": "Q3VzdG9tZXIgY2FsbGVkIGFib3V0IGludm9pY2UgIzEyMzQu"
}

Response:
{
  "id": "069XX000001ABCDEF",
  "success": true,
  "errors": []
}

Then link to a record:
POST /services/data/v59.0/sobjects/ContentDocumentLink/

{
  "ContentDocumentId": "069XX000001ABCDEF",
  "LinkedEntityId": "003XX000004TmfQQAS",
  "ShareType": "V"
}

Base64 content: The Content field must be Base64-encoded. The template handles this encoding automatically. Notes are linked to records via a separate ContentDocumentLink record with ShareType set to "V" (Viewer).

PATCH

Update Note

Update the title or body of an existing note. Uses the ContentNote object. Only the fields you provide are updated and everything else stays untouched.

ParameterLocationRequiredDescription
record_idpathYesThe ContentNote ID of the note to update
TitlebodyNoNew title for the note
BodybodyNoNew body content for the note

Endpoint:

PATCH /services/data/v59.0/sobjects/Note/{{record_id}}

Body Template:

{
  "Title": "{{Title}}",
  "Body": "{{Body}}"
}

Confirmation required: The AI will confirm the changes with the customer before updating the note. Only the fields provided are sent and unused template fields are automatically removed.

GET

Knowledge

Search and retrieve Salesforce Knowledge articles. The AI can look up help articles during a call to provide accurate answers to customer questions.

ActionMethodDescription
Search KnowledgeGETSearch published knowledge articles by keyword using SOQL
Get ArticleGETRetrieve a specific knowledge article by its KnowledgeArticle ID

Example: searching knowledge articles:

GET /services/data/v59.0/query/?q=SELECT+Id,Title,Summary,ArticleNumber
  +FROM+KnowledgeArticleVersion
  +WHERE+PublishStatus='Online'
  +AND+Language='en_US'
  +AND+Title+LIKE+'%25billing%25'
  +ORDER+BY+LastModifiedDate+DESC+LIMIT+5

Response:
{
  "totalSize": 2,
  "done": true,
  "records": [
    {
      "Id": "kaXXX000000ABCDEF",
      "Title": "How to resolve billing discrepancies",
      "Summary": "Steps to check and correct invoice amounts...",
      "ArticleNumber": "000001234"
    },
    ...
  ]
}

Example: retrieving a specific article:

GET /services/data/v59.0/sobjects/KnowledgeArticleVersion/kaXXX000000ABCDEF

Response:
{
  "Id": "kaXXX000000ABCDEF",
  "Title": "How to resolve billing discrepancies",
  "Summary": "Steps to check and correct invoice amounts...",
  "ArticleNumber": "000001234",
  "UrlName": "how-to-resolve-billing-discrepancies"
}

Knowledge articles: Only articles with PublishStatus='Online' are searchable. The AI can use articles to answer customer questions in real time without needing to escalate. Make sure Salesforce Knowledge is enabled in your org.

GET

Users & Queues

Look up Salesforce users and queues. Useful for assigning cases to the right team member or queue, or for looking up who owns a record.

ActionMethodDescription
Search UsersGETSearch Salesforce users by name or email using SOQL
Get UserGETRetrieve a specific user by their User ID
List QueuesGETList all queues available for case/lead assignment

Example: searching for a user:

GET /services/data/v59.0/query/?q=SELECT+Id,Name,Email,IsActive,Profile.Name
  +FROM+User
  +WHERE+Name+LIKE+'%25Sarah%25'
  +AND+IsActive=true
  +ORDER+BY+Name+ASC+LIMIT+10

Response:
{
  "totalSize": 1,
  "done": true,
  "records": [
    {
      "Id": "005XX000001ABCDEF",
      "Name": "Sarah Johnson",
      "Email": "[email protected]",
      "IsActive": true,
      "Profile": { "Name": "Standard User" }
    }
  ]
}

Example: listing queues:

GET /services/data/v59.0/query/?q=SELECT+Id,Name,DeveloperName
  +FROM+Group
  +WHERE+Type='Queue'
  +ORDER+BY+Name+ASC+LIMIT+20

Response:
{
  "totalSize": 3,
  "done": true,
  "records": [
    { "Id": "00GXX000001ABCDEF", "Name": "Billing Support", "DeveloperName": "Billing_Support" },
    { "Id": "00GXX000001GHIJKL", "Name": "Technical Support", "DeveloperName": "Technical_Support" },
    ...
  ]
}

Case routing: Combine List Queues with Update Case to route cases to the right team. For example, the AI can ask the customer about their issue type and assign the case to the appropriate queue using the queue's Id as the case OwnerId.

POST

Products

Search your product catalog, create new products, and add line items to opportunities. Uses the Product2 object for products and OpportunityLineItem for opportunity line items.

ActionMethodDescription
Search ProductsGETSearch products by name using SOQL on the Product2 object
Create ProductPOSTCreate a new product in the product catalog
Add Product to OpportunityPOSTAdd a product as a line item on an opportunity

Example: searching products:

GET /services/data/v59.0/query/?q=SELECT+Id,Name,ProductCode,Description,IsActive
  +FROM+Product2
  +WHERE+Name+LIKE+'%25Enterprise%25'
  +AND+IsActive=true
  +ORDER+BY+Name+ASC+LIMIT+10

Response:
{
  "totalSize": 2,
  "done": true,
  "records": [
    {
      "Id": "01tXX000003ABCDEF",
      "Name": "Enterprise License",
      "ProductCode": "ENT-001",
      "Description": "Annual enterprise license",
      "IsActive": true
    },
    ...
  ]
}

Example: adding a product to an opportunity:

POST /services/data/v59.0/sobjects/OpportunityLineItem/

{
  "OpportunityId": "006XX000001OPQRST",
  "PricebookEntryId": "01uXX000002ABCDEF",
  "Quantity": 1,
  "UnitPrice": 5000.00
}

Response:
{
  "id": "00kXX000001ABCDEF",
  "success": true,
  "errors": []
}

Price books: Adding a product to an opportunity requires a PricebookEntryId (not the Product2 ID directly). The opportunity must have a Price Book assigned. Use a SOQL query on PricebookEntry to find the right entry for a given product.

GET

Search Pricebook Entries

Search the standard price book for product entries by name. Returns the PricebookEntryId needed when adding products to opportunities.

ParameterLocationRequiredDescription
search_termpathYesProduct name to search for

Endpoint:

GET /services/data/v59.0/query/?q=SELECT+Id,Product2.Name,Product2.ProductCode,UnitPrice,Pricebook2.Name+FROM+PricebookEntry+WHERE+Product2.Name+LIKE+'%25{{search_term}}%25'+AND+Pricebook2.IsStandard=true+LIMIT+10

Tip: Use this before Add Product to Opportunity because it returns the PricebookEntryId you need.

PATCH

Update Product

Update fields on an existing product in the catalog. Uses the Product2 object. Only the fields you provide are updated.

ParameterLocationRequiredDescription
record_idpathYesThe Product2 ID of the product to update
NamebodyNoNew product name
ProductCodebodyNoNew product code
DescriptionbodyNoNew product description
IsActivebodyNotrue/false -- whether the product is active

Endpoint:

PATCH /services/data/v59.0/sobjects/Product2/{{record_id}}

Body Template:

{
  "Name": "{{Name}}",
  "ProductCode": "{{ProductCode}}",
  "Description": "{{Description}}",
  "IsActive": "{{IsActive}}"
}
DELETE

Delete Product

Delete a product from the catalog. Uses the Product2 object. The record goes to the Recycle Bin.

ParameterLocationRequiredDescription
record_idpathYesThe Product2 ID of the product to delete

Endpoint:

DELETE /services/data/v59.0/sobjects/Product2/{{record_id}}

Destructive action: This action is marked as destructive. The AI will always ask the customer for explicit confirmation before deleting. The record goes to the Recycle Bin for 15 days.

DELETE

Remove Product from Opportunity

Remove a line item from an opportunity. Uses the OpportunityLineItem object.

ParameterLocationRequiredDescription
record_idpathYesThe OpportunityLineItem ID to remove

Endpoint:

DELETE /services/data/v59.0/sobjects/OpportunityLineItem/{{record_id}}

Destructive action: This action is marked as destructive. The AI will always ask the customer for explicit confirmation before removing the line item from the opportunity.

POST

Campaigns

Search campaigns, create new ones, and add leads or contacts as campaign members. Uses the Campaign and CampaignMember objects.

ActionMethodDescription
Search CampaignsGETSearch campaigns by name using SOQL
Create CampaignPOSTCreate a new marketing campaign
Add Campaign MemberPOSTAdd a Contact or Lead to a campaign

Example: searching campaigns:

GET /services/data/v59.0/query/?q=SELECT+Id,Name,Status,Type,StartDate,EndDate
  +FROM+Campaign
  +WHERE+Name+LIKE+'%25Q1%25'
  +AND+IsActive=true
  +ORDER+BY+StartDate+DESC+LIMIT+10

Response:
{
  "totalSize": 1,
  "done": true,
  "records": [
    {
      "Id": "701XX000001ABCDEF",
      "Name": "Q1 2026 Outreach",
      "Status": "In Progress",
      "Type": "Email",
      "StartDate": "2026-01-01",
      "EndDate": "2026-03-31"
    }
  ]
}

Example: adding a contact as a campaign member:

POST /services/data/v59.0/sobjects/CampaignMember/

{
  "CampaignId": "701XX000001ABCDEF",
  "ContactId": "003XX000004TmfQQAS",
  "Status": "Sent"
}

Response:
{
  "id": "00vXX000001ABCDEF",
  "success": true,
  "errors": []
}

Members: Use ContactId or LeadId (not both) when adding a campaign member. Valid Status values depend on your campaign member status configuration (e.g. “Sent”, “Responded”).

PATCH

Update Campaign

Update fields on an existing campaign. Uses the Campaign object. Only the fields you provide are updated.

ParameterLocationRequiredDescription
record_idpathYesThe Campaign ID to update
NamebodyNoNew campaign name
StatusbodyNoPlanned, In Progress, Completed, or Aborted
TypebodyNoe.g. Email, Webinar, Conference

Endpoint:

PATCH /services/data/v59.0/sobjects/Campaign/{{record_id}}

Body Template:

{
  "Name": "{{Name}}",
  "Status": "{{Status}}",
  "Type": "{{Type}}"
}
DELETE

Delete Campaign

Delete a campaign from Salesforce. This also removes all associated campaign member records. The campaign goes to the Recycle Bin.

ParameterLocationRequiredDescription
record_idpathYesThe Campaign ID to delete

Endpoint:

DELETE /services/data/v59.0/sobjects/Campaign/{{record_id}}

Destructive action: This action is marked as destructive. Deleting a campaign also removes all campaign member records associated with it. The AI will always ask the customer for explicit confirmation before deleting. The record goes to the Recycle Bin for 15 days.

DELETE

Remove Campaign Member

Remove a contact or lead from a campaign by deleting the CampaignMember record.

ParameterLocationRequiredDescription
record_idpathYesThe CampaignMember record ID to remove

Endpoint:

DELETE /services/data/v59.0/sobjects/CampaignMember/{{record_id}}

Destructive action: This action is marked as destructive. The AI will always ask the customer for explicit confirmation before removing the member from the campaign.

GET

Direct Lookups

Fetch a single record directly by its Salesforce ID, or perform a cross-object search using SOSL (Salesforce Object Search Language). Faster than SOQL when you already have the record ID.

ActionMethodDescription
Get Contact by IDGETFetch a contact record by its 18-character ID
Get Lead by IDGETFetch a lead record by its 18-character ID
Get Account by IDGETFetch an account record by its 18-character ID
Get Opportunity by IDGETFetch an opportunity record by its 18-character ID
Get Case by IDGETFetch a case record by its 18-character ID
Global SearchGETSearch across all objects using SOSL

Example: fetching a contact by ID:

GET /services/data/v59.0/sobjects/Contact/003XX000004TmfQQAS

Response:
{
  "Id": "003XX000004TmfQQAS",
  "FirstName": "Sarah",
  "LastName": "Johnson",
  "Email": "[email protected]",
  "Phone": "+15551234567",
  "AccountId": "001XX000003ABCDEF",
  "Title": "VP of Operations"
}

Example: global search across all objects:

GET /services/data/v59.0/search/?q=FIND+{Sarah+Johnson}
  +IN+ALL+FIELDS
  +RETURNING+Contact(Id,Name,Email),Lead(Id,Name,Email),Account(Id,Name)
  +LIMIT+10

Response:
{
  "searchRecords": [
    {
      "attributes": { "type": "Contact" },
      "Id": "003XX000004TmfQQAS",
      "Name": "Sarah Johnson",
      "Email": "[email protected]"
    },
    {
      "attributes": { "type": "Account" },
      "Id": "001XX000003ABCDEF",
      "Name": "Johnson & Associates"
    }
  ]
}

SOSL vs SOQL: SOSL (/search/) searches across multiple objects at once and uses Salesforce's full-text search index. It's ideal when you don't know which object type a record belongs to. SOQL (/query/) is better when you know the exact object and need precise field filtering.

Step 3: Enable on Your AI Agent

  1. 1Go to AI Agents and select the employee you want to configure
  2. 2Scroll down to Integrations and enable the Salesforce actions you want this employee to use
  3. 3Save. The AI agent can now use these actions during phone calls

Example Conversation

Here's a full conversation showing how the AI uses multiple Salesforce actions together in a single call:

Customer calls in from +1 (555) 234-5678
AI calls search_contact with search_term="+15552345678" → finds Sarah Johnson at Acme Corp
AI:"Hello! I can see you're calling from Acme Corporation. Is this Sarah Johnson?"
Caller:"Yes, that's me. I'm having an issue with my latest invoice. The amount doesn't match what we agreed on."
AI:"I'm sorry to hear that, Sarah. Let me create a support case for this right away. The subject would be ‘Invoice amount discrepancy.’ Does that sound right?"
Caller:"Yes, and mark it as high priority please."
AI calls create_case with Subject="Invoice amount discrepancy", ContactId=Sarah's ID, Priority="High", Origin="Phone" → Case created (ID: 500XX...)
AI:"Done! I've created a high-priority case for the invoice discrepancy. Your case number is 500XX. I'm also logging this call to your account."
AI calls log_call with Subject="Inbound call - invoice discrepancy", WhoId=Sarah's Contact ID, WhatId=Case ID, CallType="Inbound", CallDisposition="Connected"
Caller:"Great. Can someone call me back tomorrow morning to follow up?"
AI:"Of course. I'll schedule a callback for tomorrow at 10:00 AM. Does that work?"
Caller:"Perfect."
AI calls schedule_event with Subject="Callback - invoice discrepancy follow-up", StartDateTime=tomorrow 10:00, EndDateTime=tomorrow 10:30, WhoId=Sarah's Contact ID, WhatId=Case ID
AI:"All set! I've scheduled a callback for tomorrow at 10:00 AM and linked it to your case. You'll get a follow-up on the invoice discrepancy. Is there anything else I can help with?"
Caller:"No, that's everything. Thanks!"

What happened: In a single phone call, the AI searched for the contact, created a case, logged the call as a task, and scheduled a follow-up event, all linked together via WhoId and WhatId. Everything shows up on Sarah's Activity Timeline in Salesforce.

Custom Actions (From Scratch)

Need something beyond the 56 templates? Click Custom Action in the template picker to configure any Salesforce API endpoint manually. Below are ready-to-use examples.

GET

SOQL: Search Contacts by Phone

Automatically identify the customer using their phone number with the {{caller_phone}} variable. Great for personalized greetings.

SettingValue
Action Nameidentify_customer
DescriptionLook up the customer in Salesforce by their phone number. Called automatically at the start of an interaction.
MethodGET
EndpointSee SOQL query below

Endpoint (full SOQL query):

/services/data/v59.0/query/?q=SELECT+Id,FirstName,LastName,Email,Phone,Account.Name+FROM+Contact+WHERE+Phone='{{caller_phone}}'+LIMIT+5

Example response:

{
  "totalSize": 1,
  "done": true,
  "records": [
    {
      "Id": "003XX000004TmfQQAS",
      "FirstName": "Sarah",
      "LastName": "Johnson",
      "Email": "[email protected]",
      "Phone": "+15551234567",
      "Account": {
        "Name": "Acme Corporation"
      }
    }
  ]
}

Tip: {{caller_phone}} is auto-filled with the customer's phone number, so there is no need to ask for it. This action has no parameters since everything is automatic.

GET

SOQL: Contacts with Recent Cases (Subquery)

Fetch a contact and their 3 most recent support cases in a single query. Uses a SOQL subquery to pull related Case records.

SettingValue
Action Namelookup_contact_with_cases
DescriptionLook up a contact by phone and include their recent support cases.
MethodGET
EndpointSee SOQL query below

Endpoint (SOQL with subquery):

/services/data/v59.0/query/?q=SELECT+Id,Name,Email,Phone,Account.Name,(SELECT+Id,Subject,Status,Priority,CreatedDate+FROM+Cases+ORDER+BY+CreatedDate+DESC+LIMIT+3)+FROM+Contact+WHERE+Phone='{{caller_phone}}'+LIMIT+1

Subqueries: SOQL supports nested queries using the relationship name (e.g. Cases for the Contact-to-Case relationship). This lets you fetch related records without a second API call.

POST

Create Contact with Auto-Fill Phone

Create a new contact with the customer's phone number automatically populated using the {{caller_phone}} variable.

SettingValue
Action Namecreate_contact_with_phone
DescriptionCreate a new Salesforce contact. Phone number is auto-filled from the customer.
MethodPOST
Endpoint/services/data/v59.0/sobjects/Contact/
ConfirmationRequired
Custom Request BodyEnabled
ParameterLocationRequiredDescription
FirstNamebodyNoContact first name
LastNamebodyYesContact last name
EmailbodyNoContact email address

Body Template:

{
  "FirstName": "{{FirstName}}",
  "LastName": "{{LastName}}",
  "Email": "{{Email}}",
  "Phone": "{{caller_phone}}"
}

Auto-fill: The {{caller_phone}} variable is replaced automatically with the customer's phone number. The AI only needs to collect the name and email from the customer.

PATCH

Update Contact

Update specific fields on an existing contact. Only the fields provided by the customer are sent and everything else stays untouched.

SettingValue
Action Nameupdate_contact
DescriptionUpdate a contact in Salesforce. Only provide the fields that need to change.
MethodPATCH
Endpoint/services/data/v59.0/sobjects/Contact/{{contact_id}}
ConfirmationRequired
Custom Request BodyEnabled
ParameterLocationRequiredDescription
contact_idpathYesSalesforce Contact ID (from search)
EmailbodyNoNew email address
FirstNamebodyNoNew first name
LastNamebodyNoNew last name
PhonebodyNoNew phone number
TitlebodyNoNew job title

Body Template:

{
  "Email": "{{Email}}",
  "FirstName": "{{FirstName}}",
  "LastName": "{{LastName}}",
  "Phone": "{{Phone}}",
  "Title": "{{Title}}"
}

Example: updating only the email (other fields auto-removed):

PATCH /services/data/v59.0/sobjects/Contact/003XX000004TmfQQAS

Sent to Salesforce:
{
  "Email": "[email protected]"
}

Response: 204 No Content (success!)

Safe updates: Unused template fields like {{FirstName}} are automatically cleaned up. Only fields the AI provides are sent, so a single-field update won't overwrite other data.

GET

Advanced SOQL: Multi-Field Search with LIKE

Search across multiple fields at once using SOQL's LIKE operator with wildcards. Useful when the customer gives a partial name or email.

SettingValue
Action Namesearch_contacts_advanced
DescriptionSearch contacts by name, email, or phone. Supports partial matches.
MethodGET
EndpointSee SOQL query below
ParameterLocationRequiredDescription
search_termqueryNoPartial name, email, or phone to search for

Endpoint (SOQL with LIKE):

/services/data/v59.0/query/?q=SELECT+Id,FirstName,LastName,Email,Phone,Account.Name+FROM+Contact+WHERE+Name+LIKE+'%25{{search_term}}%25'+OR+Email+LIKE+'%25{{search_term}}%25'+OR+Phone+LIKE+'%25{{search_term}}%25'+ORDER+BY+LastModifiedDate+DESC+LIMIT+10

Wildcards: Use %25 (URL-encoded %) for SOQL LIKE wildcards in endpoint paths. Salesforce receives LIKE '%Johnson%' after URL decoding. When {{search_term}} is empty, the unreplaced placeholder is automatically removed from the URL.

Other Useful Endpoints

These endpoints don't have templates but can be configured as custom actions:

ActionMethodEndpointUse Case
Describe object fieldsGET/services/data/v59.0/sobjects/Contact/describeGet all available fields and picklist values for an object
Check API limitsGET/services/data/v59.0/limitsMonitor how many API calls are remaining
Get record by IDGET/services/data/v59.0/sobjects/Contact/{{contact_id}}Fetch full details for a single contact
List record typesGET/services/data/v59.0/sobjectsList all available Salesforce objects
Search globally (SOSL)GET/services/data/v59.0/search/?q=FIND+{search_term}+IN+ALL+FIELDSSearch across all objects at once
Get picklist valuesGET/services/data/v59.0/sobjects/Case/describeGet Status, Priority, and Type picklist values

Available Variables

Use these in endpoint paths, SOQL queries, and body templates. They are automatically replaced at runtime.

VariableDescriptionExample Use
{{caller_phone}}The customer's phone numberAuto-search contacts by phone via SOQL WHERE clause
{{employee_id}}The AI agent handling the callLog which agent made the request
{{call_id}}Unique identifier for the current callLink CRM records to call logs
{{previousAction.field}}A field from the previous action's responseUse contact_id from a search in a follow-up create or update

Chaining actions: Use {{previousAction.field}} to pass data between actions. For example, after a Search Contact returns an ID, you can use {{search_contact.Id}} in a subsequent Create Case action's ContactId field.

Key Differences from HubSpot

If you're familiar with our HubSpot integration, here's a quick comparison of how Salesforce differs:

FeatureSalesforceHubSpot
Body formatFlat JSON (fields at top level)Nested in "properties": {} wrapper
Field namingPascalCase (FirstName, LastName)camelCase (firstname, lastname)
Search methodSOQL queries via GET /query/?q=SELECT...GET with ?search= query parameter
Update response204 No Content (empty = success)200 OK with updated record JSON
Delete behaviorSoft delete (Recycle Bin, 15 days)Archive (recoverable for 90 days)
Record IDs18-character alphanumeric (003XX...)Numeric (12345)
API versioningVersioned (v59.0)Versioned (v3)
Rate limitsBased on Salesforce edition + user countBased on HubSpot plan tier

Switching from HubSpot? The biggest differences to remember are: flat JSON (no “properties” wrapper), PascalCase field names, and 204 No Content for successful updates/deletes. The pre-built templates handle all of this automatically.

Salesforce API Reference

ObjectBase EndpointTemplate Actions
Contacts/services/data/v59.0/sobjects/Contact/Search, Create, Update, Delete
Leads/services/data/v59.0/sobjects/Lead/Search, Create, Update, Delete
Accounts/services/data/v59.0/sobjects/Account/Search, Create, Update, Delete
Opportunities/services/data/v59.0/sobjects/Opportunity/Search, Create, Update, Delete
Cases/services/data/v59.0/sobjects/Case/Search, Create, Update, Delete
Tasks/services/data/v59.0/sobjects/Task/Search, Log Call, Update, Delete
Events/services/data/v59.0/sobjects/Event/Search, Schedule, Update, Delete
Notes/services/data/v59.0/sobjects/ContentNote/Create, Get, Update, Delete
Knowledge/services/data/v59.0/sobjects/KnowledgeArticleVersion/Search, Get Article
Users/services/data/v59.0/sobjects/User/Search, Get User, List Queues
Products/services/data/v59.0/sobjects/Product2/Search, Create, Search Pricebook Entries, Add to Opportunity, Update, Delete, Remove from Opportunity
Campaigns/services/data/v59.0/sobjects/Campaign/Search, Create, Add Member, Update, Delete, Remove Member
Direct Lookups/services/data/v59.0/sobjects/{Object}/{id}Get by ID, Global Search
SOQL Queries/services/data/v59.0/query/?q=...Used by all Search templates
SOSL Search/services/data/v59.0/search/?q=...Used by Global Search

Full API documentation: developer.salesforce.com/docs/atlas.en-us.api_rest

SOQL reference: developer.salesforce.com/docs/atlas.en-us.soql_sosl

Object reference: developer.salesforce.com/docs/atlas.en-us.object_reference

Last updated: February 2026

Salesforce Integration | Staffify Docs