Salesforce is the world's leading CRM platform, used by over 150,000 companies to manage customer relationships. Integrating AI voice assistants with Salesforce creates powerful, context-aware phone interactions that know your customers before they even say hello.
This guide covers how to build Salesforce-integrated voice AI for customer service.
Why Salesforce + Voice AI?
The Power of CRM Context
When a customer calls, your AI already knows:
| Data Point | Source | Value |
|---|---|---|
| Customer name | Contact/Account | Personalized greeting |
| Purchase history | Opportunities | Relevant recommendations |
| Open cases | Service Cloud | Continue conversations |
| Account status | Custom fields | VIP treatment |
| Past interactions | Activity history | Full context |
Traditional vs AI-Powered Calls
Without AI:
Agent: "Thank you for calling. Can I have your name?"
Customer: "John Smith"
Agent: "And your account number?"
Customer: "12345"
Agent: "Let me pull up your account... How can I help?"
[30 seconds wasted on identification]
With Salesforce-Integrated AI:
AI: "Hi John! I see you're calling about the support case you
opened yesterday regarding your Pro subscription. I have an
update for you. Would you like to hear it?"
[Instant personalized service]
Use Cases for Salesforce Voice AI
Sales Cloud Integration
| Use Case | Functionality |
|---|---|
| Lead Qualification | AI qualifies leads, updates Lead records |
| Appointment Setting | Schedule meetings, sync to Salesforce Calendar |
| Quote Follow-ups | Check Quote status, remind about expiring quotes |
| Opportunity Updates | Provide deal status to stakeholders |
Service Cloud Integration
| Use Case | Functionality |
|---|---|
| Case Management | Create, update, check case status |
| Knowledge Base | Answer questions from Knowledge Articles |
| Warranty Lookup | Check warranty status from Assets |
| Escalation | Transfer with full case context |
Account Management
| Use Case | Functionality |
|---|---|
| Account Status | Billing, subscription, contract info |
| Contact Updates | Update customer information |
| Activity Logging | Automatic call logging |
| Task Creation | Create follow-up tasks |
Salesforce Integration Architecture
Authentication
Use OAuth 2.0 for Salesforce API access:
const jsforce = require('jsforce');
const conn = new jsforce.Connection({
oauth2: {
clientId: process.env.SF_CLIENT_ID,
clientSecret: process.env.SF_CLIENT_SECRET,
redirectUri: process.env.SF_REDIRECT_URI
}
});
// Using refresh token for server-to-server
await conn.oauth2.refreshToken(process.env.SF_REFRESH_TOKEN);
Data Flow
Incoming Call → Identify Customer → Fetch CRM Data → AI Conversation → Update CRM → End Call
Key Salesforce Objects
| Object | Purpose |
|---|---|
| Contact | Customer identification |
| Account | Company information |
| Case | Service tickets |
| Opportunity | Sales deals |
| Task/Activity | Call logging |
| Knowledge | FAQ answers |
Customer Identification
Lookup by Phone Number
async function identifyCustomer(phoneNumber) {
// Normalize phone number
const normalized = normalizePhone(phoneNumber);
// Search Contact by phone
const contacts = await conn.sobject('Contact')
.find({
$or: [
{ Phone: { $like: `%${normalized}%` } },
{ MobilePhone: { $like: `%${normalized}%` } }
]
})
.limit(1)
.execute();
if (contacts.length > 0) {
return {
type: 'contact',
record: contacts[0],
accountId: contacts[0].AccountId
};
}
// Search Lead if no Contact found
const leads = await conn.sobject('Lead')
.find({ Phone: { $like: `%${normalized}%` } })
.limit(1)
.execute();
if (leads.length > 0) {
return { type: 'lead', record: leads[0] };
}
return null; // Unknown caller
}
Fetch Customer Context
async function getCustomerContext(customerId) {
// Parallel queries for efficiency
const [contact, cases, opportunities, activities] = await Promise.all([
conn.sobject('Contact').retrieve(customerId),
getOpenCases(customerId),
getActiveOpportunities(customerId),
getRecentActivities(customerId)
]);
return {
contact,
account: await conn.sobject('Account').retrieve(contact.AccountId),
openCases: cases,
opportunities,
recentActivities: activities,
isVIP: contact.Account?.Type === 'Enterprise'
};
}
async function getOpenCases(contactId) {
return conn.sobject('Case')
.find({
ContactId: contactId,
IsClosed: false
})
.sort({ CreatedDate: -1 })
.limit(5)
.execute();
}
Case Management
Check Case Status
async function getCaseStatus(caseId) {
const caseRecord = await conn.sobject('Case').retrieve(caseId);
return {
caseNumber: caseRecord.CaseNumber,
subject: caseRecord.Subject,
status: caseRecord.Status,
priority: caseRecord.Priority,
owner: caseRecord.Owner?.Name,
createdDate: caseRecord.CreatedDate,
lastModified: caseRecord.LastModifiedDate,
description: caseRecord.Description
};
}
Create New Case
async function createCase(context) {
const { contactId, subject, description, priority } = context;
const caseRecord = await conn.sobject('Case').create({
ContactId: contactId,
AccountId: context.accountId,
Subject: subject,
Description: description,
Priority: priority || 'Medium',
Status: 'New',
Origin: 'Phone',
Type: 'Problem',
RecordTypeId: process.env.SF_CASE_RECORD_TYPE
});
return caseRecord;
}
Update Case
async function updateCase(caseId, updates) {
const { status, comments } = updates;
// Update case
await conn.sobject('Case').update({
Id: caseId,
Status: status
});
// Add case comment
if (comments) {
await conn.sobject('CaseComment').create({
ParentId: caseId,
CommentBody: comments,
IsPublished: true
});
}
}
Call Logging
Automatic Activity Creation
async function logCall(context) {
const {
contactId,
accountId,
subject,
description,
duration,
outcome,
relatedCaseId
} = context;
const task = await conn.sobject('Task').create({
WhoId: contactId,
WhatId: relatedCaseId || accountId,
Subject: `Voice AI Call: ${subject}`,
Description: description,
Status: 'Completed',
Priority: 'Normal',
TaskSubtype: 'Call',
CallDurationInSeconds: duration,
CallDisposition: outcome,
ActivityDate: new Date().toISOString().split('T')[0],
Type: 'Call'
});
return task;
}
Call Transcript Storage
async function saveTranscript(callId, transcript) {
// Save as ContentDocument (file)
const contentVersion = await conn.sobject('ContentVersion').create({
Title: `Call Transcript - ${callId}`,
PathOnClient: `transcript_${callId}.txt`,
VersionData: Buffer.from(transcript).toString('base64'),
ContentLocation: 'S'
});
// Link to related record
const contentDocId = await getContentDocumentId(contentVersion.id);
await conn.sobject('ContentDocumentLink').create({
ContentDocumentId: contentDocId,
LinkedEntityId: callId,
ShareType: 'V',
Visibility: 'AllUsers'
});
}
Knowledge Base Integration
Search Knowledge Articles
async function searchKnowledge(query) {
const results = await conn.search(
`FIND {${query}} IN ALL FIELDS
RETURNING Knowledge__kav(
Id, Title, Summary, ArticleBody, UrlName
WHERE PublishStatus = 'Online' AND Language = 'en_US'
)`
);
return results.searchRecords.map(article => ({
id: article.Id,
title: article.Title,
summary: article.Summary,
content: article.ArticleBody
}));
}
AI-Powered FAQ Responses
async function handleFAQ(question, context) {
// Search knowledge base
const articles = await searchKnowledge(question);
if (articles.length === 0) {
return null; // No article found
}
// Use AI to generate response from article
const bestArticle = articles[0];
const response = await generateResponseFromArticle(bestArticle, question);
return response;
}
Lead Qualification
Qualify and Update Lead
async function qualifyLead(leadId, qualificationData) {
const {
budget,
authority,
need,
timeline,
score
} = qualificationData;
await conn.sobject('Lead').update({
Id: leadId,
Budget__c: budget,
Decision_Maker__c: authority,
Need_Identified__c: need,
Timeline__c: timeline,
Lead_Score__c: score,
Status: score > 70 ? 'Qualified' : 'Working'
});
// Create task for sales rep if qualified
if (score > 70) {
await createFollowUpTask(leadId, 'High-score lead qualified by AI');
}
}
Conversation Flow
AI: "Thanks for your interest! To better assist you, I have a few questions.
What's your approximate budget for this project?"
Lead: "Around fifty thousand"
AI: "Great. And are you the decision maker for this purchase?"
Lead: "I'll need to involve my manager"
AI: "Understood. What's your timeline for implementation?"
Lead: "We're looking to start in Q2"
AI: "Perfect. Based on what you've told me, I think our Enterprise plan
would be a great fit. I'll have a sales representative reach out
within 24 hours to discuss further. Does that work?"
Opportunity Management
Check Deal Status
async function getOpportunityStatus(opportunityId) {
const opp = await conn.sobject('Opportunity').retrieve(opportunityId);
return {
name: opp.Name,
stage: opp.StageName,
amount: opp.Amount,
closeDate: opp.CloseDate,
probability: opp.Probability,
nextStep: opp.NextStep,
owner: opp.Owner?.Name
};
}
Quote Information
async function getQuoteDetails(opportunityId) {
const quotes = await conn.sobject('Quote')
.find({
OpportunityId: opportunityId,
Status: 'Presented'
})
.sort({ CreatedDate: -1 })
.limit(1)
.execute();
if (quotes.length === 0) return null;
const quote = quotes[0];
const lineItems = await conn.sobject('QuoteLineItem')
.find({ QuoteId: quote.Id })
.execute();
return {
quoteNumber: quote.QuoteNumber,
total: quote.TotalPrice,
discount: quote.Discount,
expirationDate: quote.ExpirationDate,
lineItems: lineItems
};
}
Warm Transfer with Context
Transfer to Agent with CRM Data
async function prepareTransfer(context) {
const { customerId, conversationSummary, intent } = context;
// Get full customer context
const customerData = await getCustomerContext(customerId);
// Create case for tracking
const caseId = await createCase({
contactId: customerId,
accountId: customerData.account.Id,
subject: `Phone inquiry: ${intent}`,
description: conversationSummary
});
// Prepare agent briefing
const briefing = {
customerName: customerData.contact.Name,
accountType: customerData.account.Type,
openCases: customerData.openCases.length,
conversationSummary,
caseId,
recommendedAction: determineRecommendedAction(intent, customerData)
};
return briefing;
}
// Agent hears briefing before customer connects
function generateAgentWhisper(briefing) {
return `Incoming call from ${briefing.customerName},
${briefing.accountType} account.
They're calling about ${briefing.conversationSummary}.
Case ${briefing.caseId} has been created.`;
}
Real-Time Salesforce Updates
Streaming API for Live Data
// Subscribe to Case updates
const subscription = conn.streaming.topic('CaseUpdates').subscribe((message) => {
const updatedCase = message.sobject;
// Notify AI if case status changed during call
if (activeCallsByCaseId[updatedCase.Id]) {
notifyAI(activeCallsByCaseId[updatedCase.Id], {
event: 'case_updated',
newStatus: updatedCase.Status
});
}
});
Push Updates to Caller
AI: "I just received an update - your case has been assigned to
Sarah from our technical team. She's reviewing it now and
will have a response within the hour."
Service Cloud Voice Integration
Native Salesforce Voice
For enterprises using Service Cloud Voice:
// Salesforce Voice API integration
const serviceCloudVoice = {
// Transcription flows through Salesforce
transcriptionCallback: '/voice/transcription',
// Real-time agent assist
agentAssist: {
enabled: true,
suggestResponses: true,
autoPopCase: true
}
};
Benefits of Service Cloud Voice + AI
| Feature | Benefit |
|---|---|
| Unified interface | Agents see AI + CRM in one view |
| Real-time transcription | Automatic call documentation |
| AI suggestions | Help agents during complex calls |
| Omni-channel | Voice + chat + email unified |
Analytics and Reporting
Track Voice AI Metrics in Salesforce
async function logCallMetrics(metrics) {
await conn.sobject('Voice_AI_Metrics__c').create({
Call_Date__c: new Date(),
Call_Duration__c: metrics.duration,
AI_Handled__c: metrics.resolvedByAI,
Transferred__c: metrics.transferred,
Intent__c: metrics.intent,
Sentiment__c: metrics.sentiment,
CSAT__c: metrics.csat,
Contact__c: metrics.contactId
});
}
Salesforce Reports
Create reports to track:
| Report | Metrics |
|---|---|
| AI Resolution Rate | % of calls resolved without transfer |
| Call Volume by Intent | What customers call about |
| CSAT by Channel | Voice AI vs human agents |
| Cost Savings | AI calls vs agent calls |
Edesy + Salesforce Integration
Edesy provides enterprise Salesforce integration:
Quick Setup
const edesy = require('@edesy/voice-ai');
edesy.integrations.salesforce.connect({
instanceUrl: process.env.SF_INSTANCE_URL,
clientId: process.env.SF_CLIENT_ID,
clientSecret: process.env.SF_CLIENT_SECRET,
refreshToken: process.env.SF_REFRESH_TOKEN
});
edesy.handleIncoming({
// Auto-identify from Salesforce
customerIdentification: 'salesforce',
// Intents map to Service Cloud
intents: {
'case_status': 'service_cloud',
'account_inquiry': 'account',
'sales_question': 'opportunity'
},
// Auto-log all calls
callLogging: true,
// Transfer with context
transferBriefing: true
});
Pre-Built Features
| Feature | Description |
|---|---|
| Auto-identification | Lookup Contact/Lead by phone |
| Case integration | Create, update, check cases |
| Call logging | Automatic Task creation |
| Knowledge search | FAQ from Knowledge Base |
| Warm transfer | Full context to agents |
| Analytics | Custom object logging |
Conclusion
Salesforce + AI voice assistants create intelligent, context-aware phone support that knows your customers. By leveraging CRM data, every call becomes personalized and efficient.
Key Takeaways:
- Identify customers instantly from phone number
- Personalize greetings with CRM context
- Auto-log calls as Activities in Salesforce
- Create/update Cases during calls
- Transfer to agents with full context briefing
Ready to add voice AI to your Salesforce instance? Get started with Edesy.
Related Resources
Published: January 2026