Pull live contact and deal data from Freshsales into a WhatsApp chatbot. When a prospect messages you, look up their record by phone number and reply with their lead stage, account owner, and deal context from your Freshworks 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 Freshsales-specific values.
The Freshsales Authorization header format is: Authorization: Token token=YOUR_API_KEY. The prefix is literally the two words 'Token token=' followed by your key. Do not use 'Bearer'. This unique format trips up anyone coming from HubSpot, Zoho, or Salesforce.
You need two things: your personal API key and your account's bundle alias. Both are on the same page.
acme.myfreshworks.com, your bundle alias is acme.The free Freshsales plan has limited or no API access. If you cannot find API Settings under Profile Settings, your account may be on the free tier. Paid plans (Growth, Pro, Enterprise) include full API access.
Freshsales REST API: developers.freshworks.com/crm/api
Freshsales has a dedicated lookup endpoint for searching contacts by a specific field. In your WA.Expert chatbot flow, store the customer's phone as {{customer_phone}} and add an External API Request step:
| Field | Value | Notes |
|---|---|---|
| Select Method | GET | Searching for a contact record. |
| Request URL | https://YOUR_BUNDLE.myfreshworks.com/crm/sales/api/lookup?q={{{customer_phone}}}&f=mobile_number&entities=contact | Replace YOUR_BUNDLE with your bundle alias. ?q= is the search value. ?f=mobile_number searches specifically the mobile number field. ?entities=contact restricts to contacts (not leads, deals, etc.). |
| Select Auth Type | No Auth | The Token goes in the Authorization header below. |
| Authorization | Token token=YOUR_API_KEY | Exact format: the word 'Token', a space, the word 'token=', then your key immediately after the equals sign. No quotes, no Bearer. |
| Content-Type | application/json | Standard header for Freshsales API requests. |
| Select Body Type | None | GET requests carry no body. |
| Choose Response Type | JSON | Freshsales returns structured JSON. |
Freshsales has two search options. The lookup endpoint (/api/lookup?f=mobile_number) searches a specific field, best for phone lookups. The general search endpoint (/api/search?q=PHONE&include=contact) searches across all text fields, broader but may return false matches. Use lookup for phone number searches.
A successful Freshsales lookup response looks like this:
{
"contacts": [
{
"id": 5001,
"first_name": "Priya",
"last_name": "Sharma",
"email": "priya@example.com",
"mobile_number": "9820000001",
"phone": "+919820000001",
"lead_stage_id": 3,
"lead_source_id": 2,
"owner_id": 12,
"sales_account_id": 45,
"created_at": "2026-06-15T10:30:00Z",
"updated_at": "2026-06-20T14:00:00Z",
"open_deals_count": 1,
"won_deals_count": 0
}
]
}Freshsales returns contact fields directly in the contacts array (not nested under a 'properties' or 'response' wrapper). Map using contacts[0].first_name, contacts[0].email, etc. If the contacts array is empty, no contact was found.
Map these response paths to variables in the External API Request step:
| Variable name | Response path | Example value |
|---|---|---|
| contact_id | contacts[0].id | 5001 |
| first_name | contacts[0].first_name | Priya |
| last_name | contacts[0].last_name | Sharma |
| contacts[0].email | priya@example.com | |
| open_deals | contacts[0].open_deals_count | 1 |
| won_deals | contacts[0].won_deals_count | 0 |
lead_stage_id and owner_id are numeric IDs, not labels. To get the stage name or owner name, you need a second API call to /api/settings/contacts/fields or /api/selector/owners. For a simple WhatsApp reply, open_deals_count and won_deals_count are more immediately useful.
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 Freshsales data, use an approved Utility or Marketing template.
Customer messages your WhatsApp number.
WA.Expert captures their phone as {{customer_phone}} = "9820000001".
External API Request step:
GET https://acme.myfreshworks.com/crm/sales/api/lookup
?q=9820000001&f=mobile_number&entities=contact
Authorization: Token token=sfg999666t673t7t82
Response mapped:
first_name = "Priya"
last_name = "Sharma"
open_deals = "1"
won_deals = "0"
Conditions: if contacts array is empty → "We could not find your record."
Bot replies (if found):
"Hi Priya Sharma, great to hear from you.
You have 1 open deal and 0 closed deals with us.
Reply DEAL to get an update on your open proposal,
or reply SUPPORT for assistance."| Symptom | Likely cause | Fix |
|---|---|---|
| 401 Unauthorized | Wrong auth format: using 'Bearer' instead of 'Token token=' | Change Authorization header to exactly: Token token=YOUR_API_KEY. The format is case-sensitive. |
| 404 Not Found | Wrong bundle alias in URL | Check your bundle alias in Profile Settings > API Settings. Replace YOUR_BUNDLE in the URL with the exact alias shown. |
| Empty contacts array | Phone number format mismatch or field mismatch | Try ?f=phone instead of ?f=mobile_number if contacts store the number in the Phone field rather than Mobile. Also try the number with and without country code. |
| API key not visible | On free Freshsales plan | API Settings only show an API key on paid plans. Upgrade to Growth, Pro, or Enterprise to access the API. |
| 429 Too Many Requests | Rate limit: 1,000 requests/hour exceeded | Add retry logic with delay. For a WhatsApp bot doing single lookups, this limit is very generous. |
| IDs returned instead of names | lead_stage_id, owner_id are numeric | Make a second GET request to /api/settings/contacts/fields for stage names or /api/selector/owners for owner names. For a simple bot reply, use open_deals_count instead. |
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.