Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
All errors
Governor limits

System.LimitException: Too many callouts: 101

A single transaction can make at most 100 HTTP callouts. Almost always caused by a callout inside a loop. Batch the calls or move them to async with proper batching.

Also seen asToo many callouts: 101·Too many callouts·System.LimitException: Too many callouts

The cap is 100 HTTP callouts per transaction, counting every Http.send, WebService SOAP call, and Continuation together. Hit 101, the platform throws.

The shape of the bug

for (Account a : accounts) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://api.example.com/companies/' + a.External_Id__c);
    req.setMethod('GET');
    HttpResponse res = new Http().send(req);   // one per Account
}

100 Accounts → 100 callouts → fine. 101 Accounts → boom.

Fix 1: Use a batch endpoint

Most external APIs offer a "look up many at once" mode. Send the IDs as a comma-joined query parameter or a JSON array body:

List<String> ids = new List<String>();
for (Account a : accounts) ids.add(a.External_Id__c);

HttpRequest req = new HttpRequest();
req.setEndpoint('https://api.example.com/companies?ids=' + EncodingUtil.urlEncode(String.join(ids, ','), 'UTF-8'));
req.setMethod('GET');
HttpResponse res = new Http().send(req);   // one callout, all results

If the API supports POST with a body, you have effectively no upper bound on the IDs you can ship per request.

Fix 2: Move to Batch Apex

Each chunk in execute() gets a fresh 100-callout budget. Set the chunk size to whatever fits inside 100:

Database.executeBatch(new MyCalloutBatch(), 50);

The 50 is the chunk size. Each chunk gets a fresh callout budget and a fresh CPU/heap budget, which is often the real reason callout-heavy work moves to batch.

Fix 3: Aggregate work into a single endpoint

If your code is doing N HTTP calls to compose one logical operation, ask the API team for an endpoint that does the composition server-side. "Get a record + its line items + its history in one call" is a common addition that pays for itself the first time you'd have hit this limit.

A subtle gotcha: queueables don't fix this alone

Moving the loop into a queueable doesn't change the cap — each queueable invocation is still one transaction with 100 callouts max. What queueables let you do is chain them: do 100 callouts, enqueue the next queueable, that one does 100 more, etc. Use this only when the work is genuinely independent across the boundary.

Diagnostic

System.debug('Callouts: '
    + Limits.getCallouts() + ' / ' + Limits.getLimitCallouts());

Print this in your loop to confirm where the count is climbing.

When the count surprises you

@future(callout=true) and Continuation callouts each count separately against their own transactions. So you don't accumulate 100 from a future call into your synchronous transaction. But a chain of synchronous callouts in a controller invoked by a Lightning page request all count together.

Related dictionary terms