In this article, we’ll explore how to use the Agentforce Models AI API to automatically generate and post Chatter messages when a Salesforce Case status changes. Leveraging Apex @future methods and OpenAI-powered prompts, we offload the writing to AI—so agents can focus on solving problems, not posting updates.
Let’s walk through a practical and scalable use case: Automatically generating Chatter posts when a Case transitions to “Working” using the Agentforce AI Models API.
🧠 The Idea
Every time a support Case enters the “Working” status, we want to notify internal stakeholders with a professionally written Chatter message. Instead of hardcoding a message, we’ll let AI craft a natural, contextual update—tailored to each Case.
💡 Design Overview
This solution uses:
- Apex Triggers + Handler Pattern
- @future(callout=true) method to invoke the AI API asynchronously
- Agentforce’s
aiplatform.ModelsAPI.createGenerations()to generate the message - Chatter FeedItem to post the result
⚙️ How It Works
1. Trigger Fires
The CaseTrigger invokes the CaseTriggerHandler on insert and update.
trigger CaseTrigger on Case (after insert, after update) {
if (Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {
CaseTriggerHandler.handleAfterInsertOrUpdate(Trigger.new, Trigger.oldMap);
}
}2. Business Logic in Handler
We detect when a Case changes status to “Working” and queue it for Chatter posting.
public class CaseTriggerHandler {
public static void handleAfterInsertOrUpdate(List<Case> newCases, Map<Id, Case> oldMap) {
if (newCases == null || newCases.isEmpty()) {
return;
}
List<Id> toChatter = new List<Id>();
for (Case newCase : newCases) {
if (newCase == null || String.isBlank(newCase.Status)) {
continue;
}
Case oldCase = oldMap != null ? oldMap.get(newCase.Id) : null;
String oldStatus = oldCase != null ? oldCase.Status : null;
// Check for transition to 'Working'
if (oldStatus != 'Working' && newCase.Status == 'Working') {
toChatter.add(newCase.Id);
}
}
// Trigger async actions
for (Id caseId : toChatter) {
CaseChatterAIService.postChatterOnCaseCloseAsync(caseId);
}
}
}3. AI Generates Message Asynchronously
The core of this approach is CaseChatterAIService, which builds a prompt and sends it to the AI model.
public class CaseChatterAIService {
private static final String MODEL_NAME = 'sfdc_ai__DefaultOpenAIGPT4OmniMini';
private static final String PROMPT_TEMPLATE =
'Generate a positive and professional Chatter message announcing that Case #%s titled "%s" has been handled by the agent. ' +
'Here are the relevant details:\n%s';
@future(callout = true)
public static void postChatterOnCaseCloseAsync(Id caseId) {
if (caseId == null) {
return;
}
try {
Case caseRecord = [
SELECT Id, CaseNumber, Subject, Status, Priority, Owner.Name
FROM Case
WHERE Id = :caseId
LIMIT 1
];
String caseDetails = String.format(
'Case Number: {0}\nSubject: {1}\nStatus: {2}\nPriority: {3}\nOwner: {4}',
new List<String>{
String.valueOf(caseRecord.CaseNumber),
String.valueOf(caseRecord.Subject),
String.valueOf(caseRecord.Status),
String.valueOf(caseRecord.Priority),
String.valueOf(caseRecord.Owner.Name)
}
);
String prompt = String.format(
PROMPT_TEMPLATE,
new List<String>{
String.valueOf(caseRecord.CaseNumber),
String.valueOf(caseRecord.Subject),
caseDetails
}
);
aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
aiplatform.ModelsAPI.createGenerations_Request request =
new aiplatform.ModelsAPI.createGenerations_Request();
request.modelName = MODEL_NAME;
aiplatform.ModelsAPI_GenerationRequest requestBody =
new aiplatform.ModelsAPI_GenerationRequest();
requestBody.prompt = prompt;
request.body = requestBody;
aiplatform.ModelsAPI.createGenerations_Response response = modelsAPI.createGenerations(request);
String chatterMessage = (response != null && response.Code200 != null)
? response.Code200.generation.generatedText
: null;
if (String.isNotBlank(chatterMessage)) {
FeedItem post = new FeedItem();
post.ParentId = caseRecord.Id;
post.Body = chatterMessage;
insert post;
}
} catch (QueryException qe) {
System.debug(LoggingLevel.ERROR, 'Query failed for Case Id: ' + caseId + ' => ' + qe.getMessage());
} catch (aiplatform.ModelsAPI.createGenerations_ResponseException ae) {
System.debug(LoggingLevel.ERROR, 'AI API error for Case Id: ' + caseId + ' => ' + ae.getMessage());
} catch (DmlException de) {
System.debug(LoggingLevel.ERROR, 'DML error while posting to Chatter for Case Id: ' + caseId + ' => ' + de.getMessage());
} catch (Exception e) {
System.debug(LoggingLevel.ERROR, 'Unexpected error for Case Id: ' + caseId + ' => ' + e.getMessage());
}
}
}✅ Key Benefits
- Real-Time AI Messaging: Trigger contextual Chatter updates right from Apex, no manual effort required.
- Fully Native: No external integrations or third-party AI calls—Salesforce-hosted Gen AI does the heavy lifting.
⚠️ Gotchas and Best Practices
- Callout Limits:
@future(callout=true)allows external calls but still has per-transaction limits. - Resilience: Catch exceptions from the AI API or DML and log them (as demonstrated).
- Avoid Redundant Posts: Use status comparisons in the handler to prevent duplicate AI requests.
- Test AI Output Quality: Model hallucination is rare but possible—validate critical messages before posting if needed.
🔚 Final Thoughts
With Agentforce Models AI API, Chatter becomes more than a collaboration tool—it becomes a canvas for real-time, intelligent communication. This is Apex infused with AI, native to the Salesforce Platform, and built for scale.
Agentforce is here—and Chatter just got a lot smarter.
Demo: Agentforce Models AI API: Posting Chatter with Apex

Do you need help?
Are you stuck while working on this requirement? Do you want to get review of your solution? Now, you can book dedicated 1:1 with me on Lightning Web Component and Agentforce completely free.
GET IN TOUCH

One comment