Making a Callout from a Trigger
“You cannot make HTTP callouts from a synchronous trigger context. Period.”
What Happened
Mobilization Funding needed real-time sync with their construction lending platform. I wrote a trigger on Opportunity that fired an HTTP POST on every update. Worked great in my scratch org with one record. In production, bulk updates from a data loader threw CalloutException on every single record. 200 opps failed to save.
The Wrong Way
trigger OpportunitySync on Opportunity (after update) {
for (Opportunity opp : Trigger.new) {
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://api.lender.com/sync');
req.setMethod('POST');
req.setBody(JSON.serialize(opp));
h.send(req); // CalloutException: callout not allowed from triggers
}
}The Right Way
trigger OpportunitySync on Opportunity (after update) {
Set<Id> oppIds = new Set<Id>();
for (Opportunity opp : Trigger.new) {
if (opp.StageName != Trigger.oldMap.get(opp.Id).StageName) {
oppIds.add(opp.Id);
}
}
if (!oppIds.isEmpty()) {
OpportunitySyncQueueable job = new OpportunitySyncQueueable(oppIds);
System.enqueueJob(job);
}
}
public class OpportunitySyncQueueable implements Queueable, Database.AllowsCallouts {
private Set<Id> oppIds;
public OpportunitySyncQueueable(Set<Id> ids) { this.oppIds = ids; }
public void execute(QueueableContext ctx) {
List<Opportunity> opps = [SELECT Id, StageName, Amount FROM Opportunity WHERE Id IN :oppIds];
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:LenderAPI/sync');
req.setMethod('POST');
req.setBody(JSON.serialize(opps));
h.send(req);
}
}The Lesson
Callouts from triggers require async. Use Queueable with Database.AllowsCallouts — not future methods, because you'll need the flexibility later.
Enjoyed this? Get more like it.
Glen's Musings — AI, investing, and building things. Occasional. Free.
More Integration Mistakes
Hardcoding API Credentials Instead of Using Named Credentials
Hardcoded API keys in Apex are a security audit's worst nightmare.
Read moreAnnoyingNo Retry Logic on External API Calls
External APIs fail. Your integration should expect that.
Read morePainfulPublishing Platform Events Without Error Handling
Platform Events can fail to publish. If you don't check, you'll never know.
Read more