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.
- 1Go to Settings → Integrations
- 2Click Connect Platform → Salesforce
- 3Log in to your Salesforce account and click Allow to authorize the connection
- 4Done! Your access token refreshes automatically. No maintenance needed
| Detail | Value |
|---|---|
| Base URL | Your Salesforce instance URL (set automatically) |
| Auth Type | OAuth 2.0 (automatic) |
| Token Refresh | Automatic when expired |
| API Version | v59.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
Leads
Accounts
Opportunities
Cases
Tasks
Events
Notes 4 templates
Knowledge
Users & Queues
Products 7 templates
Campaigns 6 templates
Direct Lookups
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
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.
| Behavior | Description |
|---|---|
| No search term | Returns all records (up to 10, ordered by last modified) |
| With search term | Filters by name, email, phone, or other fields using SOQL LIKE (partial match) |
| Case number search | Uses exact match (CaseNumber='...') instead of LIKE for reliable numeric lookups |
| Confirmation | Not 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+10How 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).
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).
| Behavior | Description |
|---|---|
| Required fields | Varies by object (see table below) |
| Optional fields | Automatically excluded if not provided |
| Confirmation | Required (AI confirms details before creating) |
| API Endpoint | /services/data/v59.0/sobjects/{Object}/ |
Required Fields by Object
| Object | Required Fields | Recommended Fields |
|---|---|---|
| Contact | LastName | FirstName, Email, Phone |
| Lead | LastName, Company | FirstName, Email, Phone, Status |
| Account | Name | Phone, Website, Industry |
| Opportunity | Name, StageName, CloseDate | Amount, AccountId |
| Case | (none strictly required) | Subject, ContactId, Description, Priority |
| Task | (none strictly required) | Subject, WhoId, Status, Priority |
| Event | Subject, StartDateTime, EndDateTime | WhoId, WhatId, Location, Description |
| Note (ContentNote) | Title | Content (Base64-encoded body) |
| Product (Product2) | Name | ProductCode, Description, IsActive |
| Campaign | Name | Status, Type, StartDate, EndDate |
| Campaign Member | CampaignId, ContactId or LeadId | Status |
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).
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.
| Behavior | Description |
|---|---|
| Record ID | From a previous search result (e.g. contact_id) |
| Partial updates | Only changed fields are sent -- other fields stay untouched |
| Confirmation | Required (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
Soft-delete a record from Salesforce. The record goes to the Recycle Bin and can be recovered for 15 days.
| Behavior | Description |
|---|---|
| Record ID | From a previous search result |
| Confirmation | Required (AI always confirms before deleting) |
| Destructive | Yes -- marked as destructive action |
| Recovery | Record 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.
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.
| Field | Purpose | Example Values |
|---|---|---|
| Subject | Title of the logged call | "Inbound call re: billing issue" |
| CallType | Direction of the call | Inbound |
| CallDisposition | Outcome of the call | Connected, Left Voicemail, No Answer |
| Description | Notes about the call | Caller reported..." |
| WhoId | Links to a Contact or Lead | Contact/Lead ID from search |
| WhatId | Links to an Account, Opportunity, or Case | Account/Opp/Case ID from search |
| TaskSubtype | Pre-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).
Events: Scheduling
Schedule meetings, callbacks, or appointments on the Salesforce calendar. Both StartDateTime and EndDateTime are required in ISO 8601 format.
| Field | Purpose | Example Values |
|---|---|---|
| Subject | Title of the event | "Follow-up call with Sarah" |
| StartDateTime | When the event begins (required) | 2026-02-12T10:00:00.000Z |
| EndDateTime | When the event ends (required) | 2026-02-12T10:30:00.000Z |
| Location | Where the event takes place | "Phone", "Zoom", "Office" |
| Description | Details about the event | "Discuss renewal options" |
| WhoId | Links to a Contact or Lead | Contact/Lead ID from search |
| WhatId | Links to Account, Opportunity, or Case | Account/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.
Notes
Create, retrieve, and delete notes attached to Salesforce records. Notes use the ContentNote object and are linked to parent records via ContentDocumentLink.
| Action | Method | Description |
|---|---|---|
| Create Note | POST | Create a new note and optionally link it to a record (Contact, Account, Case, etc.) |
| Get Note | GET | Retrieve a note by its ContentNote ID, including title and body |
| Delete Note | DELETE | Delete 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).
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.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The ContentNote ID of the note to update |
| Title | body | No | New title for the note |
| Body | body | No | New 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.
Knowledge
Search and retrieve Salesforce Knowledge articles. The AI can look up help articles during a call to provide accurate answers to customer questions.
| Action | Method | Description |
|---|---|---|
| Search Knowledge | GET | Search published knowledge articles by keyword using SOQL |
| Get Article | GET | Retrieve 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.
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.
| Action | Method | Description |
|---|---|---|
| Search Users | GET | Search Salesforce users by name or email using SOQL |
| Get User | GET | Retrieve a specific user by their User ID |
| List Queues | GET | List 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.
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.
| Action | Method | Description |
|---|---|---|
| Search Products | GET | Search products by name using SOQL on the Product2 object |
| Create Product | POST | Create a new product in the product catalog |
| Add Product to Opportunity | POST | Add 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.
Search Pricebook Entries
Search the standard price book for product entries by name. Returns the PricebookEntryId needed when adding products to opportunities.
| Parameter | Location | Required | Description |
|---|---|---|---|
| search_term | path | Yes | Product 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+10Tip: Use this before Add Product to Opportunity because it returns the PricebookEntryId you need.
Update Product
Update fields on an existing product in the catalog. Uses the Product2 object. Only the fields you provide are updated.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The Product2 ID of the product to update |
| Name | body | No | New product name |
| ProductCode | body | No | New product code |
| Description | body | No | New product description |
| IsActive | body | No | true/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 Product
Delete a product from the catalog. Uses the Product2 object. The record goes to the Recycle Bin.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The 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.
Remove Product from Opportunity
Remove a line item from an opportunity. Uses the OpportunityLineItem object.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The 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.
Campaigns
Search campaigns, create new ones, and add leads or contacts as campaign members. Uses the Campaign and CampaignMember objects.
| Action | Method | Description |
|---|---|---|
| Search Campaigns | GET | Search campaigns by name using SOQL |
| Create Campaign | POST | Create a new marketing campaign |
| Add Campaign Member | POST | Add 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”).
Update Campaign
Update fields on an existing campaign. Uses the Campaign object. Only the fields you provide are updated.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The Campaign ID to update |
| Name | body | No | New campaign name |
| Status | body | No | Planned, In Progress, Completed, or Aborted |
| Type | body | No | e.g. Email, Webinar, Conference |
Endpoint:
PATCH /services/data/v59.0/sobjects/Campaign/{{record_id}}Body Template:
{
"Name": "{{Name}}",
"Status": "{{Status}}",
"Type": "{{Type}}"
}Delete Campaign
Delete a campaign from Salesforce. This also removes all associated campaign member records. The campaign goes to the Recycle Bin.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The 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.
Remove Campaign Member
Remove a contact or lead from a campaign by deleting the CampaignMember record.
| Parameter | Location | Required | Description |
|---|---|---|---|
| record_id | path | Yes | The 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.
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.
| Action | Method | Description |
|---|---|---|
| Get Contact by ID | GET | Fetch a contact record by its 18-character ID |
| Get Lead by ID | GET | Fetch a lead record by its 18-character ID |
| Get Account by ID | GET | Fetch an account record by its 18-character ID |
| Get Opportunity by ID | GET | Fetch an opportunity record by its 18-character ID |
| Get Case by ID | GET | Fetch a case record by its 18-character ID |
| Global Search | GET | Search 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
- 1Go to AI Agents and select the employee you want to configure
- 2Scroll down to Integrations and enable the Salesforce actions you want this employee to use
- 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:
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.
SOQL: Search Contacts by Phone
Automatically identify the customer using their phone number with the {{caller_phone}} variable. Great for personalized greetings.
| Setting | Value |
|---|---|
| Action Name | identify_customer |
| Description | Look up the customer in Salesforce by their phone number. Called automatically at the start of an interaction. |
| Method | GET |
| Endpoint | See 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+5Example 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.
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.
| Setting | Value |
|---|---|
| Action Name | lookup_contact_with_cases |
| Description | Look up a contact by phone and include their recent support cases. |
| Method | GET |
| Endpoint | See 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+1Subqueries: 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.
Create Contact with Auto-Fill Phone
Create a new contact with the customer's phone number automatically populated using the {{caller_phone}} variable.
| Setting | Value |
|---|---|
| Action Name | create_contact_with_phone |
| Description | Create a new Salesforce contact. Phone number is auto-filled from the customer. |
| Method | POST |
| Endpoint | /services/data/v59.0/sobjects/Contact/ |
| Confirmation | Required |
| Custom Request Body | Enabled |
| Parameter | Location | Required | Description |
|---|---|---|---|
| FirstName | body | No | Contact first name |
| LastName | body | Yes | Contact last name |
| body | No | Contact 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.
Update Contact
Update specific fields on an existing contact. Only the fields provided by the customer are sent and everything else stays untouched.
| Setting | Value |
|---|---|
| Action Name | update_contact |
| Description | Update a contact in Salesforce. Only provide the fields that need to change. |
| Method | PATCH |
| Endpoint | /services/data/v59.0/sobjects/Contact/{{contact_id}} |
| Confirmation | Required |
| Custom Request Body | Enabled |
| Parameter | Location | Required | Description |
|---|---|---|---|
| contact_id | path | Yes | Salesforce Contact ID (from search) |
| body | No | New email address | |
| FirstName | body | No | New first name |
| LastName | body | No | New last name |
| Phone | body | No | New phone number |
| Title | body | No | New 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.
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.
| Setting | Value |
|---|---|
| Action Name | search_contacts_advanced |
| Description | Search contacts by name, email, or phone. Supports partial matches. |
| Method | GET |
| Endpoint | See SOQL query below |
| Parameter | Location | Required | Description |
|---|---|---|---|
| search_term | query | No | Partial 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+10Wildcards: 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:
| Action | Method | Endpoint | Use Case |
|---|---|---|---|
| Describe object fields | GET | /services/data/v59.0/sobjects/Contact/describe | Get all available fields and picklist values for an object |
| Check API limits | GET | /services/data/v59.0/limits | Monitor how many API calls are remaining |
| Get record by ID | GET | /services/data/v59.0/sobjects/Contact/{{contact_id}} | Fetch full details for a single contact |
| List record types | GET | /services/data/v59.0/sobjects | List all available Salesforce objects |
| Search globally (SOSL) | GET | /services/data/v59.0/search/?q=FIND+{search_term}+IN+ALL+FIELDS | Search across all objects at once |
| Get picklist values | GET | /services/data/v59.0/sobjects/Case/describe | Get Status, Priority, and Type picklist values |
Available Variables
Use these in endpoint paths, SOQL queries, and body templates. They are automatically replaced at runtime.
| Variable | Description | Example Use |
|---|---|---|
| {{caller_phone}} | The customer's phone number | Auto-search contacts by phone via SOQL WHERE clause |
| {{employee_id}} | The AI agent handling the call | Log which agent made the request |
| {{call_id}} | Unique identifier for the current call | Link CRM records to call logs |
| {{previousAction.field}} | A field from the previous action's response | Use 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:
| Feature | Salesforce | HubSpot |
|---|---|---|
| Body format | Flat JSON (fields at top level) | Nested in "properties": {} wrapper |
| Field naming | PascalCase (FirstName, LastName) | camelCase (firstname, lastname) |
| Search method | SOQL queries via GET /query/?q=SELECT... | GET with ?search= query parameter |
| Update response | 204 No Content (empty = success) | 200 OK with updated record JSON |
| Delete behavior | Soft delete (Recycle Bin, 15 days) | Archive (recoverable for 90 days) |
| Record IDs | 18-character alphanumeric (003XX...) | Numeric (12345) |
| API versioning | Versioned (v59.0) | Versioned (v3) |
| Rate limits | Based on Salesforce edition + user count | Based 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
| Object | Base Endpoint | Template 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