The Agentforce Healthcare Assistant is a smart Salesforce-based solution that assists users in:
Determining whether they need a medical checkup based on disease input.
-
Recommending nearby doctors or hospitals.
-
Collecting and storing doctor ratings from patients.
-
Displaying relevant doctor availability and advice.
-
In this blog, we’ll break down how to implement this solution in Salesforce using custom objects, fields, flows, and Apex code.
OBJECT STRUCTURE
- Health Check Request (Custom Object) This object stores user (patient) data, health Advice, and recommendation results.
Fields:
Name – Text(80)
Disease__c – Picklist
Phone__c – Phone
Age__c – Number(3, 0)
Gender__c – Picklist
CheckupRecommendation__c – Checkbox
Pin_Code__c – Text
Location__c – Geolocation
NearbyDoctorMap__c – Formula (Text)
IF( NOT(ISBLANK(PinCode__c)), HYPERLINK( "https://www.google.com/maps/search/doctor+near+" & PinCode__c, "View Nearby Doctors by Pin Code", "_blank" ), "Pin Code not available" )
HealthAdvice__c – Formula (Text)
CASE( TEXT(Disease__c), "Common Cold", "Rest well, stay hydrated, and consider steam inhalation. See a doctor if symptoms worsen.", "Mild Fever", "Take paracetamol, rest, and drink plenty of fluids. Consult a doctor if fever persists.", "Mild Headache", "Take rest, avoid screen time, and consider mild pain relief. Visit a doctor if it continues.", "No specific advice available for this condition." )
- Doctor Detail (Custom Object)
Fields:
Name – Text(80)
AverageRating__c – Number(2, 1)
- Rating (Custom Object)
Fields:
Name – Text(80)
DoctorsDetail__c – Lookup(Doctors Detail)
Phone__c – Phone
RatingScore__c – Number(1, 0)
FLOWS OVERVIEW
Flow 1: Health Check Requests Details
Type: Autolaunched Flow
-
Input Variables:
- nameInput (Text)
- phoneInput (Text)
- ageInput (Number)
- genderInput (Text)
- diseaseInput (Text)
-
Logic:
- If disease is Common Cold, Mild Fever, or Headache → "No Checkup Required"
- Else → "Checkup Recommended"
-
Output Variable:
- checkupRecommendationOutput
Flow 2: Update Pin Code Of Health Check Request
Type: Autolaunched Flow
-
Input Variables:
- nameInput (Text)
- phoneInput (Text)
- ageInput (Number)
- genderInput (Text)
- diseaseInput (Text)
- pinCodeInput (Text)
-
Logic:
- Use Update Records to set the PinCode__c field.
-
Output Variable:
- nearByDoctorMapOuput
Flow 3: Create Rating For Doctors
Type: Autolaunched Flow
-
Input Variables:
- doctorNameInput (Text)
- phoneInput (Text)
- patientNameInput (Number)
- ratingInput (Text)
-
Logic:
- Create a new Rating record and link it to the doctor
-
Output Variable:
- ratingRecordOutput
APEX CLASSES & TRIGGERS
HealthCheckRequestTrigger
Automatically enqueues a Queueable Apex job when a pincode is entered or updated:
HealthCheckRequestTrigger.apxttrigger HealthCheckRequestTrigger on HealthCheckRequest__c (after insert, after update) { for (HealthCheckRequest__c h : Trigger.new) { if (h.PinCode__c != null) { System.enqueueJob(new PincodeToLocationQueue(h.Id, h.PinCode__c)); } } }
PincodeToLocationQueue
Fetches latitude and longitude from the OpenStreetMap API using a pincode.
PincodeToLocationQueue.apxcpublic class PincodeToLocationQueue implements Queueable, Database.AllowsCallouts { private Id recordId; private String pincode; public PincodeToLocationQueue(Id recordId, String pincode) { this.recordId = recordId; this.pincode = pincode; } public void execute(QueueableContext context) { try { Http http = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('https://nominatim.openstreetmap.org/search?postalcode=' + EncodingUtil.urlEncode(pincode, 'UTF-8') + '&country=India&format=json'); req.setMethod('GET'); req.setHeader('User-Agent', 'SalesforcePincodeLookup'); HttpResponse res = http.send(req); System.debug('HTTP Status: ' + res.getStatusCode()); System.debug('Raw Response: ' + res.getBody()); if (res.getStatusCode() == 200) { List<Object> rawList = (List<Object>) JSON.deserializeUntyped(res.getBody()); if (!rawList.isEmpty()) { Map<String, Object> first = (Map<String, Object>) rawList[0]; Double lat = Double.valueOf((String)first.get('lat')); Double lon = Double.valueOf((String)first.get('lon')); System.debug('Lat: ' + lat + ', Lon: ' + lon); HealthCheckRequest__c h = [SELECT Id FROM HealthCheckRequest__c WHERE Id = :recordId LIMIT 1]; h.Location__Latitude__s = lat; h.Location__Longitude__s = lon; update h; } else { System.debug('No results found for pincode.'); } } } catch (Exception e) { System.debug('Error fetching geolocation: ' + e.getMessage()); } } }
RatingTrigger
Handles recalculation of Doctor Average Ratings after insert, update, delete, or undelete:
RatingTrigger.apxttrigger RatingTrigger on Rating__c (after insert, after update, after delete, after undelete) { Set<Id> doctorIds = new Set<Id>(); if (Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete) { for (Rating__c r : Trigger.new) { if (r.DoctorsDetail__c != null) { doctorIds.add(r.DoctorsDetail__c); } } } if (Trigger.isUpdate || Trigger.isDelete) { for (Rating__c r : Trigger.old) { if (r.DoctorsDetail__c != null) { doctorIds.add(r.DoctorsDetail__c); } } } if (!doctorIds.isEmpty()) { DoctorRatingService.updateAverageRatings(doctorIds); } }
DoctorRatingService
Calculates average ratings per doctor manually, bypassing the need for roll-up summary fields:
DoctorRatingService.apxcpublic class DoctorRatingService { public static void updateAverageRatings(Set<Id> doctorIds) { Map<Id, List<Rating__c>> ratingsMap = new Map<Id, List<Rating__c>>(); for (Rating__c rating : [ SELECT Id, RatingScore__c, DoctorsDetail__c FROM Rating__c WHERE DoctorsDetail__c IN :doctorIds ]) { if (!ratingsMap.containsKey(rating.DoctorsDetail__c)) { ratingsMap.put(rating.DoctorsDetail__c, new List<Rating__c>()); } ratingsMap.get(rating.DoctorsDetail__c).add(rating); } List<DoctorsDetail__c> doctorsToUpdate = new List<DoctorsDetail__c>(); for (Id docId : ratingsMap.keySet()) { List<Rating__c> ratings = ratingsMap.get(docId); Decimal total = 0; Integer count = 0; for (Rating__c r : ratings) { if (r.RatingScore__c != null) { total += r.RatingScore__c; count++; } } Decimal avg = count > 0 ? total / count : null; doctorsToUpdate.add(new DoctorsDetail__c( Id = docId, AverageRating__c = avg.setScale(1) )); } if (!doctorsToUpdate.isEmpty()) { update doctorsToUpdate; } } }
Validation Rule (on Rating__c)
Name: Validate_RatingScore
OR(
RatingScore__c < 1,
RatingScore__c > 5
)
Error Message: Please enter a rating between 1 and 5.
AGENT INSTRUCTIONS
These are the custom instructions given to the Agentforce digital assistant:
Greeting Handling
When the user starts the conversation by saying hi, hello, or hlo, then ask: "Would you like to provide a rating for a doctor, or do you need information related to a health issue?"
Health Info Flow
If user selects health issue, ask: "Please provide your name, the disease you are experiencing, your phone number, age, and gender."
Once user provides the info, run action: "Health Check Requests Details"
If the user confirms checkup is needed, ask for pincode and run action: "Update Pin Code Of Health Check Request"
Doctor Rating Flow
If user selects doctor rating, ask: "Please provide the Doctor Name, your name (patient), your phone number, and the rating (1 to 5)."
Once info is provided, run action: "Give Rating to the Doctors"
Output:
Summary
Agentforce combines custom objects, Apex logic, automation, and external API calls into a seamless healthcare assistant. It checks health eligibility, locates nearby doctors, and collects feedback, enhancing healthcare engagement with smart, structured flows.