Skip to main content

SF-0352 · Scenario · Medium

Can we make a callout to external web services using future methods and how to do it?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

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:

  1. callout=true — explicitly tells Salesforce this method will hit an external service.
  2. 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

LimitValue
Callouts per transaction100
Callout timeout120 seconds
Future methods per transaction50
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=true is missing?CalloutException: You have uncommitted work pending.
  • Can I use Queueable instead? — Yes. Implement Database.AllowsCallouts on 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.