I have an APEX REST POST method that is being called from an external system 'A'.

Processing this POST I need to callout to another external system 'B' and based on its response continue with my application logic, eventually returning the result to system 'A'.

The problem is that I'm getting an Error: "System.CalloutException: Callout loop not allowed"

is there any way to get around this ?

  • 1
    Very interesting design, not sure what the business reason is but generally, in these cases, we do a Callout from System A directly to System B and if there is any data that you want to get from Salesforce you can do by APEX REST GET and then callout to System B (from System A only) – logontokartik Jan 11 '13 at 15:09
  • 2
    Are you testing your rest method by making an httprequest from anonymous apex by any chance? the callout loop error only happens when you try and make a callout to another salesforce method from a "call-in". If you are calling out to an external system it should work. – Greg Grinberg Jan 15 '13 at 14:38
  • 1
    Here's a business reason: System A doesn't have credentials for System B, but the Salesforce instance does. System A authenticates with Salesforce, which then retrieves data from System B to supply to System A. – tomlogic Feb 1 '13 at 22:48
  • workaround: if it were a mission critical one-off using systems you control, an HTTP proxy service (eg squid) could drop the Sfdc-Stack-Depth header before forwarding the requests ;-) – bigassforce Feb 1 '13 at 23:04
  • 1
    I just ran into this problem myself. The feature that makes them unique is one SF org (a) is making a SOAP request to a different SF org (b). After the transaction is over, b has a future method that makes a SOAP call to an external (non-SF) system, (c). That's when I get the callout loop error. – tggagne May 11 '16 at 19:33

No, there is not an immediate workaround to this :-(

The mechanism by which they measure that 'callout depth' is by transmitting an HTTP header on requests originating from Apex, Sfdc-Stack-Depth: 1 - if you try and trick the platform by explicitly setting this header to '' etc, you'll find the value is very sticky!

Unfortunately for us, there is a good business reason behind this "feature" on Salesforce' part. It is by design, to prevents callouts from blocking threads between multiple orgs / instances. sequence diagram

(hopefully this sequence diagram illustrates the intention; as an HTTP callout could take a while, the number of loopback connections is restricted to 1, otherwise imagine the DoS implications)

You might be able to overcome this issue if your B callout were read-only and its contents were updated infrequently.

You could schedule a batch process to regularly perform the callout and avail its response in a Document (or such). Then read that Document when responding to A, decoupling the two. But I admit that may be unlikely in your case...

  • 1
    Why won't an future solve this problem? I have a customer with five production orgs. Two of these orgs need to collaborate. Org A makes an future callout inside an AFTER INSERT trigger. When Org B sends Org A a SOAP message that results in triggering the future method, the future method fails with the callout exception. – tggagne May 12 '16 at 17:23
  • Future is a good idea if you don't need the value returned synchronously @tggagne – bigassforce May 12 '16 at 17:25

@user31's answer is absolutely incorrect (or I am misunderstanding the question). There is nothing preventing you from making callouts from Apex REST methods to external systems. Here is some sample code:

global with sharing class RestExample 
    global static string doGet() 
        HttpRequest req = new HttpRequest();

        system.debug('request body: '+req.getbody());

        HTTPResponse res = new http().send(req);

        return res.getBody();

Note that you cannot make callouts to Salesforce as that will give you the callout loop error.

You can test this code through curl or something similar. Testing it through anonymous Apex will give the callout loop error as you are making a callout from within Salesforce to Salesforce.

  • Ya got me there grigriforice; in my answer I've made the unstated assumption that System A or System B is a Salesforce system ;) hopefully Prafulla Patil can respond to your comment on the question itself to clarify this. – bigassforce Jan 15 '13 at 23:00
  • @user320 yeah, that definitely might be the case but he called them both external systems. Didn't want anyone else to think this was impossible. – Greg Grinberg Jan 15 '13 at 23:23
  • 1
    I can confirm that a RESTful interface called from a Force.com site cannot make a web callout, and I'll likely have to modify my workflow to use an @future method for that callout. Thankfully, in my case, I don't need to respond with data from the callout. – tomlogic Feb 1 '13 at 22:53
  • 3
    And I can now confirm that @future isn't enough to break the loop. I still get a CalloutException from my FutureHandler. I can see where Salesforce would want to avoid some runaway processes spawning connections between instances, but this is starting to make my life more difficult. – tomlogic Feb 1 '13 at 23:19
  • As of today, I can't call an external service from an Apex REST resource. Maybe this is something that was changed with the latest Salesforce release? – Michael Sobczak Sep 23 '15 at 16:38

You can solve this by placing the second API call in an implements Queueable class. It doesn't work for @future.

  • 1
    Welcome to SFSE and thanks for the answer! This got auto-flagged as low quality - probably because of the length. Can you expand on it a little just to avoid any accidental removal because I think you do have a solution here. – Matt Lacey Oct 18 '20 at 23:39

I've encountered this, but different scenario. I have a setup where we have two orgs connected via an integration tool. In addition to these two SF orgs, we are connected to an external service.

A - SF Org 1 B - SF Org 2 C - 3rd party service

B is connected to A & C directly. To save licensing costs if A wants to talk to C it must go through B.

This encounters the callout loop without a workaround.

What happens is on org B there is a service that runs and passes calls along in a new session.

Now the packages are managed, but here is what I know about how it works: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_interface_system_schedulablecontext.htm


https://help.salesforce.com/articleView?id=000340086&type=1&mode=1 https://developer.salesforce.com/forums/?id=906F0000000g27DIAQ

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.