Yes. A @future method can make HTTP callouts as long as you set callout=true in the annotation. Without that flag, any callout from a future method throws CalloutException: You have uncommitted work pending or simply fails with “Callout from triggers are currently not supported.”
The syntax
@future(callout=true)
public static void postToErp(List<Id> orderIds) {
List<Order__c> orders = [SELECT Id, Name, Total__c FROM Order__c WHERE Id IN :orderIds];
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:ERP_Credentials/orders');
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setBody(JSON.serialize(orders));
HttpResponse resp = http.send(req);
if (resp.getStatusCode() != 200) {
// log to a custom object, send alert, etc.
}
}
Two things make this work:
callout=true— explicitly tells Salesforce this method will hit an external service.- It’s
@future— the callout runs in a new transaction. The original trigger has committed by then, so the “uncommitted work” rule doesn’t apply.
Why triggers can’t call out directly
The platform enforces that you cannot make a callout while DML is pending in the same transaction. A trigger runs mid-transaction with uncommitted changes, so any direct callout throws:
“You have uncommitted work pending. Please commit or rollback before calling out.”
Wrapping the callout in a @future(callout=true) defers it to a fresh transaction after the parent commits — perfectly legal.
Typical trigger pattern
trigger OrderTrigger on Order__c (after insert, after update) {
Set<Id> idsToSync = new Set<Id>();
for (Order__c o : Trigger.new) {
if (o.Sync_To_ERP__c) idsToSync.add(o.Id);
}
if (!idsToSync.isEmpty()) {
OrderSync.postToErp(new List<Id>(idsToSync));
}
}
Limits to know
| Limit | Value |
|---|---|
| Callouts per transaction | 100 |
| Callout timeout | 120 seconds |
| Future methods per transaction | 50 |
| Future methods per 24 hours (org-wide) | 250,000 or 200 × user licenses, whichever is greater |
If your trigger needs to call out for 200 records, do not invoke 200 separate future methods — bulkify into one call with a List<Id>.
Named Credentials are the right call
Notice the endpoint above is callout:ERP_Credentials/orders — a Named Credential. They store the auth, the URL, and the cert handling outside your code. Using raw URLs and hardcoded API keys is a security review red flag.
Common interview follow-ups
- What error appears if
callout=trueis missing? —CalloutException: You have uncommitted work pending. - Can I use Queueable instead? — Yes. Implement
Database.AllowsCalloutson your Queueable class — same idea, more flexibility. - Can I receive the response back to the user? — Not in the same request. The future runs async. To inform the user, write the result to a record they’re viewing.
Verified against: Apex Developer Guide — Invoking Callouts Using Apex. Last reviewed 2026-05-17.