function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Hemanth BakthavatsaluHemanth Bakthavatsalu 

Retrieve data from external system using HTTP calls

I am trying make a API call to an external system (CPQ) from the Salesforce.
1. I am able to successfully login to the external system through http post
2. After successful login, now I want to query Account object on the external system and retrieve the results
3. How do i make a query to the external system using Get method. When I make a external call after login, using a new request object with GET method, I am getting Unauthorized error.

Error that I am getting: System.HttpResponse[Status=Unauthorized, StatusCode=401]
The external system is CPQ (fpx vendor). Below is the API document that was shared

http://docs.fpx.com/docs/api/restful/14/html/cpq_login_(post).html



Below is the code:

public void cpqCallOut() {

        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        String strname = 'Username';
        String strpwd= 'password';
        
         Blob headerValue = Blob.valueOf(strname+':'+strpwd);
                String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
        
        
        
        String SessionId = Userinfo.getSessionId();
        String strURL = System.URL.getSalesforceBaseURL().toExternalForm();
        
        req.setHeader('Authorization', authorizationHeader);
        req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login');
        req.setMethod('POST');
        req.setBody('un ='+EncodingUtil.urlEncode(strname, 'UTF-8') + 'pw =' + EncodingUtil.urlEncode(strpwd, 'UTF-8') +
        'SfdcSessionID  =' + EncodingUtil.urlEncode(SessionId, 'UTF-8') + 
        'SfdcServerURL ='+  EncodingUtil.urlEncode(strURL , 'UTF-8'));
        req.setCompressed(true); // otherwise we hit a limit of 32000
        
        String strQuery = 'Select+name+from+Account+where+id+=+158000000000010'; 
        
        //new request object
        HttpRequest req1 = new HttpRequest();
        HttpResponse res1 = new HttpResponse();
        Http http1 = new Http();
     
        try {
            res = http.send(req);
        
         if(res.getStatusCode()== 200)
            {
                System.debug('SUCCESS!!!');
                
               req1.setMethod('GET');               
               req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
               req1.setCompressed(true);
               res = http.send(req1);
                
               System.debug('MY REQUEST===>'+req1.toString());
               System.debug('RESPONSE FROM CPQ 2222'+res.toString());
            }
        
        } catch(System.CalloutException e) {
            System.debug('Callout error: '+ e);
            System.debug('RESPONSE FROM CPQ'+res.toString());
        }
    }
}
Daniel BallingerDaniel Ballinger
I can see that you build up the POST request req, send it, and check the StatusCode that gets returned.

Do you need to do something with the response to that initial POST request and feed it back into the subsequent GET request? Maybe read some sort of token response and use that to set a Header on the subsequent GET. Otherwise why are you doing the login call.
Hemanth BakthavatsaluHemanth Bakthavatsalu
I reviewed the CPQ API documentation (Login part).
http://docs.fpx.com/docs/api/restful/14/html/cpq_login_(post).html

Based on that, I changed my code to make a POST using JSON format..

When I print the response object, I am getting the status code 200; however if I print the response body I am getting the below error. Does it indicate the login is not successful, eventhough I am getting status as 200.

USER_DEBUG [36]|DEBUG|RESPONSE BODY--->{"error":"Username or password is not recognized","success":false}

Updated code:

 HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        String strname = 'Username';
        String strpwd= 'pwd';
        String SessionId = Userinfo.getSessionId();
        String strURL = System.URL.getSalesforceBaseURL().toExternalForm();
        req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login');
        req.setMethod('POST');
        
        JSONGenerator gen = JSON.createGenerator(true);
            gen.writeStartArray();
            gen.writeStartObject();
            gen.writeStringField('username', EncodingUtil.urlEncode(strname, 'UTF-8'));
            gen.writeStringField('password', EncodingUtil.urlEncode(strpwd, 'UTF-8'));
            gen.writeEndObject();              
            gen.writeEndArray();
            String jsonOrders = gen.getAsString();
            System.debug('jsonOrders: ' + jsonOrders);
            req.setHeader('Content-Type', 'application/json');
            req.setBody(jsonOrders);

            req.setCompressed(true); // otherwise we hit a limit of 32000

        try {
            res = http.send(req);
            
            if (res.getStatusCode() == 200) {
             System.debug('CALLOUOT SUCCESSFUL');
             System.debug('RESPONSE FROM CPQ 1111--->'+res.toString());
             System.debug('RESPONSE BODY--->'+res.getBody());
            }
        }             
        catch(System.CalloutException e) {
            System.debug('Callout error: '+ e);
            System.debug('RESPONSE FROM CPQ'+res.toString());
        }
 
Daniel BallingerDaniel Ballinger
I'm not familiar with the CPQ API, but the Response body definitely indicates a problem with the Salesforce credentials.

Looking at the documentation you linked to, they have an option for a sfdcsessionid and sfdcserverurl. These might be better options that submitting your Salesforce user password. You can get the Session Id using UserInfo.getSessionId() (https://developer.salesforce.com/docs/atlas.en-us.198.0.apexcode.meta/apexcode/apex_methods_system_userinfo.htm#apex_System_UserInfo_getSessionId) in Apex.

I'd experiment with the API using something outside of Apex until you can get the raw JSON API calls going correctly. Then convert them to an Apex HttpRequest. I personally like the Postman plugin for Chrome.
Hemanth BakthavatsaluHemanth Bakthavatsalu
Thanks for your response.. Last evening I changed the code and now  I am able to successfully login to CPQ through API.

I did a POST request and returned response body has User id and rfst id... 
Response for login request:
{"rfst":"D9RnIQGcGOpa","userId":"09a0000evyj7m671","success":true}

Now I am trying to query the Account object through a GET request..I am getting the Unauthorized error when trying to do a Get request. I am following the step in “Query” function in the API document. (http://docs.fpx.com/docs/api/restful/14/)

        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();

        req.setHeader('Connection','keep-alive');
        req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login?un=Username&pw=Password');
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.setMethod('POST');

        
        req.setCompressed(true); // otherwise we hit a limit of 32000
        
        //new request object
        HttpRequest req1 = new HttpRequest();
        HttpResponse res1 = new HttpResponse();
        
        String strQuery = 'Select+name+from+Account';
        
        try {
            res = http.send(req);
        
         if(res.getStatusCode()== 200)
            {
                System.debug('SUCCESS BODY!!!'+ res.getBody());          

               System.debug('RESPONSE FROM CPQ '+res.toString());
               
               JSONParser parser = JSON.createParser(res.getBody());
               String strUsrId;

              while (parser.nextToken() != null) {
              
                  if(parser.getCurrentName() == 'rfst')
                  {
                    System.debug('getCurrentToken===>'+ parser.getCurrentToken());
                    System.debug('getCurrentName==>'+ parser.getCurrentName());
                    System.debug('getText===>'+ parser.getText());
                    strUsrId= parser.getText();
                    }
                    parser.nextToken();          

                }
                System.debug('Userid===>'+ strUsrId);
                
               req1.setMethod('GET');
               req1.setHeader('Authorization', strUsrId);
               req1.setHeader('Connection','keep-alive');
               req1.setHeader('Content-Type', 'application/x-www-form-urlencoded');          
               req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
               req1.setCompressed(true);
               res1 = http.send(req1);
               
                System.debug('GET REQUEST BODY===>'+req1);
               System.debug('GET RESPONSE FROM CPQ 2222'+res1.toString());
               
            }
Hemanth BakthavatsaluHemanth Bakthavatsalu
I did use the Postman to test REST endpoints. In postman I made the below calls in sequence and my GET request is successful
 
POST:  https://sbx.fpx.com/rs/8/cpq/login?un=username&pw=password
GET: https://sbx.fpx.com/rs/8/cpq?query=Select+name+from+Account 

Whereas if i do the same thing in my code it is failing.. (the GET is failing; throwing  below error)

System.HttpResponse[Status=Unauthorized, StatusCode=401

I believe the issue is with my GET request.
HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();

        req.setHeader('Connection','keep-alive');
        req.setEndpoint('https://sbx.fpx.com/rs/8/cpq/login?un=Username&pw=Password');
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.setMethod('POST');

        
        req.setCompressed(true); // otherwise we hit a limit of 32000
        
        //new request object
        HttpRequest req1 = new HttpRequest();
        HttpResponse res1 = new HttpResponse();
        
        String strQuery = 'Select+name+from+Account';
        
        try {
            res = http.send(req);
        
         if(res.getStatusCode()== 200)
            {
                System.debug('SUCCESS BODY!!!'+ res.getBody());          

               System.debug('RESPONSE FROM CPQ '+res.toString());
               
               JSONParser parser = JSON.createParser(res.getBody());
               String strUsrId;

              while (parser.nextToken() != null) {
              
                  if(parser.getCurrentName() == 'rfst')
                  {
                    System.debug('getCurrentToken===>'+ parser.getCurrentToken());
                    System.debug('getCurrentName==>'+ parser.getCurrentName());
                    System.debug('getText===>'+ parser.getText());
                    strUsrId= parser.getText();
                    }
                    parser.nextToken();          

                }
                System.debug('Userid===>'+ strUsrId);
                
               req1.setMethod('GET');
               req1.setHeader('Authorization', strUsrId);
               req1.setHeader('Connection','keep-alive');
               req1.setHeader('Content-Type', 'application/x-www-form-urlencoded');          
               req1.setEndpoint('https://sbx.fpx.com/rs/8/cpq?query='+ strQuery);
               req1.setCompressed(true);
               res1 = http.send(req1);
               
                System.debug('GET REQUEST BODY===>'+req1);
               System.debug('GET RESPONSE FROM CPQ 2222'+res1.toString());
               
            }
Daniel BallingerDaniel Ballinger

What Headers are you using with Postman? Do you use the userId from the prior login request as the Authorization header?

Do you need this line for the GET request - I think it is only applicable to a POST request.
 

req1.setHeader('Content-Type', 'application/x-www-form-urlencoded');
 


 
 

Hemanth BakthavatsaluHemanth Bakthavatsalu
I am just running the below requests in Postman:
1. POST: https://sbx.fpx.com/rs/8/cpq/login?un=USERNAME.cpqnew&pw=PASSWORD
Authorization: NO AUTH
Headers: NO HEADERS
Body:x-www-form-urlencoded

2. GET https://sbx.fpx.com/rs/8/cpq?query=Select+name+from+Account
Authorization: NO AUTH
​Headers: NO HEADERS
BodyNO BODY
Sitaram Gollapudi 11Sitaram Gollapudi 11
Hemanth,

I am facing the same issue, although my use case is slightly different to yours. I am trying to connect to FPX CPQ On Demand through a web data connector that I am building, for pulling FPX Data into Tableau Desktop. I am writing a simple webpage using HTML and Javascript to make this webservice call to FPX. When I test my WebService calls with POSTMAN, I am able to connect. But I am struggling to figure out how to retain session when I make a GET Query call after establishing credentials through login call. Were you able to figure out this issue

Also, since you seem to be working on FPX CPQ ON Demand, I have a question. Do you know if CPQ's REST API supports OAUTH protocal for authentication? 
 
Daniel BallingerDaniel Ballinger
It seems kindof crazy that you can use Postman to do a POST request to login and then do a subsequent GET request with no form of authorization header or parameter. How does the web service know you are authenticated. I doubt it is using cookies. Maybe they have some kind of crazy stateful server side tracking based on IP address. It doesn't make much sense.