Query live Salesforce contact and lead data from a WhatsApp chatbot. When a prospect messages you, search their record by phone number using SOQL, fetch their lead source and account owner, and reply with context from your CRM.
Before following this guide, read the External API Request step foundation guide. It covers every field in the step interface so this guide can focus on Salesforce-specific values.
Unlike most APIs where you paste a token directly, Salesforce requires two steps: (1) authenticate at login.salesforce.com to get an access token and instance URL, then (2) use that instance URL for all data calls. The instance URL is unique to your org and looks like https://yourorg.my.salesforce.com.
A Connected App provides the Consumer Key and Consumer Secret needed to authenticate. You need System Administrator access to create one.
https://login.salesforce.com/services/oauth2/success. Under Selected OAuth Scopes, add Access and manage your data (api). Save.Salesforce disables the username-password OAuth flow by default since Spring '22. Go to Setup > OAuth and OpenID Connect Settings and enable 'Allow OAuth Username-Password Flows'. Without this, the token request returns an error.
Salesforce Connected Apps: developer.salesforce.com/docs/atlas.en-us.api_rest
You need your Salesforce username, password + security token, Consumer Key, and Consumer Secret. The security token is separate from your password. Find it under your profile → Settings → Reset My Security Token.
POST https://login.salesforce.com/services/oauth2/token
Content-Type: application/x-www-form-urlencoded
Body (form fields):
grant_type = password
client_id = YOUR_CONSUMER_KEY
client_secret = YOUR_CONSUMER_SECRET
username = your@salesforce.com
password = YourPassword123YourSecurityToken
Response:
{
"access_token": "00D5e000001N20Q!ASAAQEDBeG8bOwPu8N...",
"instance_url": "https://yourorg.my.salesforce.com",
"token_type": "Bearer"
}
Save BOTH: access_token and instance_url.
All subsequent API calls go to instance_url, not login.salesforce.com.The password field in the token request must be your Salesforce login password immediately followed by your security token, with no separator. If password is 'Pass123' and token is 'abc123', send 'Pass123abc123'. Get your security token from Profile > Settings > My Personal Information > Reset My Security Token.
In your WA.Expert chatbot flow, store the customer's phone number as {{customer_phone}}. Add an External API Request step using the instance URL from Step 2:
| Field | Value | Notes |
|---|---|---|
| Select Method | GET | Running a SOQL query to search records. |
| Request URL | https://yourorg.my.salesforce.com/services/data/v67.0/query?q=... | Replace yourorg.my.salesforce.com with your instance_url from Step 2. v67.0 is Summer '26. The ?q= parameter takes a URL-encoded SOQL query. |
| Select Auth Type | No Auth | The Bearer token goes in the Authorization header below. |
| Authorization | Bearer 00D5e000001N20Q!... | Include the word 'Bearer' followed by a space, then the access_token from Step 2. |
| Content-Type | application/json | Standard header for Salesforce REST API. |
| Select Body Type | None | GET requests carry no body. |
| Choose Response Type | JSON | Salesforce returns structured JSON. |
SOQL (Salesforce Object Query Language) is Salesforce's SQL-like language. You only need one template for a contact lookup:
| What you want | SOQL query |
|---|---|
| Contact by phone | SELECT Id, FirstName, LastName, Email, Phone, LeadSource FROM Contact WHERE Phone = '9820000001' |
| Contact by mobile | SELECT Id, FirstName, LastName, Email, MobilePhone FROM Contact WHERE MobilePhone = '9820000001' |
| Phone or mobile | SELECT Id, FirstName, LastName FROM Contact WHERE Phone = '9820000001' OR MobilePhone = '9820000001' |
| Lead by phone | SELECT Id, FirstName, LastName, Email, Status, LeadSource FROM Lead WHERE Phone = '9820000001' |
| Account by name | SELECT Id, Name, Phone, BillingCity FROM Account WHERE Name LIKE '%Sharma%' |
SOQL is case-insensitive for keywords (SELECT, FROM, WHERE) but case-sensitive for field names. Salesforce standard fields use PascalCase: FirstName, LastName, LeadSource, OwnerId.
A successful Salesforce SOQL query response looks like this:
{
"totalSize": 1,
"done": true,
"records": [
{
"attributes": {
"type": "Contact",
"url": "/services/data/v67.0/sobjects/Contact/003Dp000003xyzABC"
},
"Id": "003Dp000003xyzABC",
"FirstName": "Priya",
"LastName": "Sharma",
"Email": "priya@example.com",
"Phone": "+919820000001",
"LeadSource": "Web",
"OwnerId": "005Dp000002abcDEF"
}
]
}Salesforce wraps results in a 'records' array. If totalSize is 0, no contact matched the phone number. Add a conditions branch in your chatbot: if totalSize equals 0, reply 'We could not find your record. Please contact support.'
Map these response paths to variables in the External API Request step:
| Variable name | Response path | Example value |
|---|---|---|
| result_count | totalSize | 1 |
| contact_id | records[0].Id | 003Dp000003xyzABC |
| first_name | records[0].FirstName | Priya |
| last_name | records[0].LastName | Sharma |
| records[0].Email | priya@example.com | |
| lead_source | records[0].LeadSource | Web |
The attributes object in each record is Salesforce metadata. Your actual contact data is in the named fields alongside it.
If the contact messaged you first within the last 24 hours, your reply is a free service conversation. For proactive outbound follow-up triggered by Salesforce data, use an approved Utility or Marketing template at Rs. 0.115 per message.
Customer messages your WhatsApp number.
WA.Expert captures their phone as {{customer_phone}} = "+919820000001".
External API Request step:
GET https://yourorg.my.salesforce.com/services/data/v67.0/query
?q=SELECT+Id,FirstName,LastName,LeadSource+FROM+Contact+WHERE+Phone='+919820000001'
Authorization: Bearer 00D5e000001N20Q!...
Response mapped:
result_count = "1"
first_name = "Priya"
last_name = "Sharma"
lead_source = "Web"
Conditions branch: if result_count = 0 → "We could not find your record."
Bot replies (if found):
"Hi Priya Sharma, welcome back.
We have your account on file (Source: Web).
Your dedicated account manager will follow up shortly.
Reply URGENT to escalate immediately."| Symptom | Likely cause | Fix |
|---|---|---|
| unsupported_grant_type or invalid_grant | Username-password OAuth flow disabled | Go to Salesforce Setup > OAuth and OpenID Connect Settings > enable 'Allow OAuth Username-Password Flows'. |
| INVALID_SESSION_ID / 401 | Access token expired or wrong | Salesforce access tokens can expire. Re-run Step 2 to get a fresh token. For production, implement token refresh. |
| instance_url used incorrectly | Calling login.salesforce.com for data queries | Use the instance_url returned in Step 2 (e.g. https://yourorg.my.salesforce.com) for all data calls. login.salesforce.com is only for authentication. |
| IP Restrictions error | Connected App IP policy blocking the request | Set IP Relaxation to 'Relax IP Restrictions' in the Connected App's OAuth Policies settings. |
| Empty records / totalSize: 0 | Phone format mismatch | Check how phone numbers are stored in Salesforce. Some orgs store +91XXXXXXXXXX, others store 0XXXXXXXXXX or just XXXXXXXXXX. Match the format exactly in your WHERE clause. |
| MALFORMED_QUERY | SOQL syntax error | Check field names (case-sensitive: FirstName not firstname). Quote strings in single quotes. URL-encode spaces as + in the query parameter. |
HubSpot CRM API v3 with Private App token: simpler single-step auth.
Read guide →Zoho CRM API v8: Zoho-oauthtoken auth, India data centre, phone search.
Read guide →Master every field in WA.Expert's HTTP action step.
Read foundation guide →Free trial, no credit card required. And if you ever get stuck, we are the only platform in India that answers you live on WhatsApp.