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
TerminusbotTerminusbot 

SOAP Request in APEX - Error Bad Request 400

I am sending a SOAP Request from Salesforce and I am getting a bad request 400 response. 

I have a succesfull POST request through POSTMAN so I decided to take the raw XML and insert it into string variables. Here is what I am sending. 
 
public class ClientInsertCallout {

    @future (callout=true)
    public static void sendNotification(String name, ID Id) {
		
		
		// Test Variables 
        Integer divisionNumber = 01;
      	String addr1           = '2972 Anderson Circle SE';
        Integer postalCode     = 30080;
        String city            = 'Smyrna';
        String state           = 'GA';
        Integer phone1         = null;
        String contactMethod   = 'Email';
        String email           = 'rlopez@rampartinsurance';
        
        
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        

        // Login Variables
        String account             = 'xxxx';
        String username            = 'xxxx';
        String password            = 'xxxx';
        String serverpool          = 'xxxx';
        
        // Setting login variables - commented out to try raw xml
        //Blob headerValue  = Blob.valueOf(Account  + ':' +  Username + ':' + Password + ':' + Serverpool); 
        
        // Body of Request - XML in a string 
        string soapBody = '<ClientImportRecord>' + '' + '<Guid>'+ Id + '</Guid>' + '' + 
        '<ClientName>' + name + '</ClientName>' + '' + '</ClientImportRecord>'; 
        
        string headerValue = '<Account>' + account + '</Account>' + '' + 
            '<Username>' + username + '</Username>' + '' + 
            '<Password>' + password + '</Password>' + '' +
            '<Accesscode xsi:nil="true" />' + '' +
            '<Serverpool>' + serverpool + '</Serverpool>'+ '' +
            '<Onlinecode xsi:nil="true"/>';
        
        String authorizationHeader = headerValue;
        req.setHeader('Authorization', authorizationHeader);
        req.setHeader('Accept-Encoding','gzip,deflate');
        req.setHeader('Content-Type', 'text/xml');
    	req.setHeader('SOAPAction','http://amsservices.com/clientInsert');
        req.setEndpoint('http://xxx.xxx.xxx.xxx/sagittaws/transporter.asmx');
        req.setMethod('POST');
        req.setBody(soapBody);
        
        System.debug('Full XML' + soapBody);
        req.setCompressed(true); // otherwise we hit a limit of 32000
		
        try {
            res = http.send(req);
        } catch(System.CalloutException e) {
            System.debug('Callout error: '+ e);
            System.debug(res.toString());
        }

    }

}

 
Chris Gary CloudPerformerChris Gary CloudPerformer
Usually in most cases, the Authorization Header will not contain a full XML message, unless you are doing something 'highly custom' within your SOAP Web Service.  Usually the Authorization Header contains a simple authorization token, or perhaps an encoded and encrypted Username:password value pair for Basic authentication.  Usually that XML information that you are currently sending in your HTTP Header acutally goes within your body, within a <SOAP:Header> element, inside of the <SOAP:Envelope> element, but outside of the <SOAP:Body> Element. I can only speak to 'general' usage and structure though, becuase the details of your individual SOAP Web Service are not provided.  These are usually found in the WSDL provided, and a Sample message can be pretty easily constructed using a Tool like SOAPUI. 
TerminusbotTerminusbot
Thanks for the response. I created a SOAP Request that succesfully posted in the external system using Postman. The problem I am running into is the Auth uses more than just basic username and password. Having trouble getting this request to work using Apex callout. 

Here is my successful SOAP request XML. You can see there is more than just username and password. 
 
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Header>
    <AuthenticationHeader xmlns="http://amsservices.com/">
      <Account>xxxxx</Account>
      <Username>xxx</Username>
      <Password>xxxx</Password>
      <Accesscode xsi:nil="true" />
      <Serverpool>xxxx</Serverpool>
      <Onlinecode xsi:nil="true"/>
    </AuthenticationHeader>
  </soap12:Header>
 
  <soap12:Body>
    <clientInsert xmlns="http://amsservices.com/">
      <ClientImportRecord>
        <Guid>DIACO10</Guid>
        <ClientName>Diane Court Fitness Club</ClientName>
        <DivisionNumber>01</DivisionNumber>
        <BillToCd>DIACO10</BillToCd>
        <ReferenceCd xsi:nil="true"/>
        <Addr1>2972 Anderson Circle SE</Addr1>
        <Addr2 xsi:nil="true"/>
        <PostCd>
          <PostalCode>30080</PostalCode>
          <PostalExtensionCode xsi:nil="true"/>
        </PostCd>
        <City>Smyrna</City>
        <StateProvCd>GA</StateProvCd>
        <Phone1Number>4048525765</Phone1Number>
        <Phone1ExtensionNumber xsi:nil="true"/>
        <Phone2Number xsi:nil="true"/>
        <Phone2ExtensionNumber xsi:nil="true"/>
        <FaxNumber xsi:nil="true"/>
        <ContactMethod>Email</ContactMethod>
        <EmailAddr>rlopez@rampartinsurance.com</EmailAddr>
        <WebSiteLink xsi:nil="true"/>
        <ProducerCd>
          <Producer1Cd>HO</Producer1Cd>
          <Producer2Cd xsi:nil="true"/>
          <Producer3Cd xsi:nil="true"/>
        </ProducerCd>
        <ServicerCd>
          <Servicer1Cd>HO</Servicer1Cd>
          <Servicer2Cd xsi:nil="true"/>
          <Servicer3Cd xsi:nil="true"/>
        </ServicerCd>
        <CatCd>
          <Cat1Cd>COM</Cat1Cd>
          <Cat2Cd xsi:nil="true"/>
          <Cat3Cd xsi:nil="true"/>
          <Cat4Cd xsi:nil="true"/>
          <Cat5Cd xsi:nil="true"/>
        </CatCd>
        <StatusCd>
          <StatusCdValue>
            <string xsi:nil="true"/>
            <string xsi:nil="true"/>
          </StatusCdValue>
        </StatusCd>
        <SicCd>
          <SicCdValue>
            <string xsi:nil="true"/>
            <string xsi:nil="true"/>
          </SicCdValue>
        </SicCd>
        <CommentaryRemarkText xsi:nil="true"/>
        <CreditTerms>0</CreditTerms>/>
        <NetCommissionPct xsi:nil="true"/>
        <SourceCd xsi:nil="true"/>
        <SourceDt>2016-06-24</SourceDt>
        <LegalEntityCd xsi:nil="true"/>
        <FEIN xsi:nil="true"/>
        <DateBusinessStarted xsi:nil="true"/>
        <InspectionContact xsi:nil="true"/>
        <InspectionPhoneNumber xsi:nil="true"/>
        <InspectionPhoneExtensionNumber xsi:nil="true"/>
        <BusinessNature>
          <BusinessNatureValue>
            <string xsi:nil="true"/>
            <string xsi:nil="true"/>
          </BusinessNatureValue>
        </BusinessNature>
        <AccountingContact xsi:nil="true"/>
        <AccountingPhoneNumber xsi:nil="true"/>
        <AccountingPhoneExtensionNumber xsi:nil="true"/>
        <SpecialInput1 xsi:nil="true"/>
        <SpecialInput2 xsi:nil="true"/>
        <CustomTrapdoor>
          <CustomTrapdoor>
            <CustomKey  xsi:nil="true"/>
            <CustomData xsi:nil="true" />
          </CustomTrapdoor>
          <CustomTrapdoor>
            <CustomKey  xsi:nil="true"/>
            <CustomData xsi:nil="true" />
          </CustomTrapdoor>
        </CustomTrapdoor>
      </ClientImportRecord>
    </clientInsert>
  </soap12:Body>
</soap12:Envelope>

 
Chris Gary CloudPerformerChris Gary CloudPerformer
Based on your response, I am now pretty sure that you are putting your authorization information in the wrong place.  The setHeader() method is not designed to set SOAP Headers.  It is only designed to set HTTP Headers.  For more information on the difference between the two - see http://stackoverflow.com/questions/11445400/soap-headers-versus-http-headers.  Simply put, your body String needs to contain your <SOAP12:Envelope>,<SOAP12:Header> and <SOAP12:Body> elements.  You probably don't even need the 'req.setHeader('Authorization', authorizationHeader);' line in your code. Your body String should contain the ENTIRE SOAP Envelope, including the <xml> line.  I hope this helps you.
TerminusbotTerminusbot
Thanks, I will try this in the morning! Hope it helps too. I have been spinning my wheels on this one for some time. I will update the thread tomorrow. 
TerminusbotTerminusbot
I modified the request to be enclosed in the body only. I am still receiving a 400 error code. Can you see anything that I am doing incorrectly? 
 
public class ClientInsertCallout {

    @future (callout=true)
    public static void sendNotification(String name, ID Id) {
		
        Integer divisionNumber = 01;
      	String addr1           = '2972 Anderson Circle SE';
        Integer postalCode     = xxxxx;
        String city            = 'xxxxx';
        String state           = 'GA';
        Integer phone1         = null;
        String contactMethod   = 'Email';
        String email           = 'xxxxxxx';
        
        String account             = 'xxxx';
        String username            = 'xxxx';
        String password            = 'xxxx';
        String serverpool          = 'xxxx';
        
        
        
        string soapBody = '<?xml version="1.0" encoding="utf-8"?>' + '' + 
        '<soap12:Envelope' + '' + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' + '' + 
        'xmlns:xsd="http://www.w3.org/2001/XMLSchema"' + '' + 
        'xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">' + '' + 
         '<soap12:Header>' + '' + 
        '<AuthenticationHeader xmlns="http://amsservices.com/"> ' + '' +          
        '<Account>' + account + '</Account>' + '' + 
            '<Username>' + username + '</Username>' + '' + 
            '<Password>' + password + '</Password>' + '' +
            '<Accesscode xsi:nil="true" />' + '' +
            '<Serverpool>' + serverpool + '</Serverpool>'+ '' +
            '<Onlinecode xsi:nil="true"/>' + '' + 
             '</AuthenticationHeader>' + '' + 
            '</soap12:Header>' + '' + 
            '<soap12:Body>' + '' +
            '<clientInsert xmlns="http://amsservices.com/">' + '' + 
            '<ClientImportRecord>' + '' + 
        '<Guid>'+ Id + '</Guid>' + '' + 
        '<ClientName>' + name + '</ClientName>' + '' +
      '</ClientImportRecord>' + '' +  
       '</soap12:Body>' + '' + 
        '</soap12:Envelope>'; 
        
      
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        
        
        
        req.setMethod('POST');
        req.setEndpoint('http://167.206.227.210/sagittaws/transporter.asmx');
        req.setHeader('Content-Type', 'text/xml');
        req.setHeader('SOAPAction','http://amsservices.com/clientInsert');
        req.setBody(soapBody);
       
        
        
        
        
        System.debug('Full XML' + soapBody);
       
		
        try {
            res = http.send(req);
        } catch(System.CalloutException e) {
            System.debug('Callout error: '+ e);
            System.debug(res.toString());
        }

    }

}

 
Chris Gary CloudPerformerChris Gary CloudPerformer
It looks good to me.  So you are still getting the HTTP Response of 400 - what is the detail of the error message state? Furthermore, at this point, if your postman message is making in through, but your Apex Callout isn't compare the HTTP Headers of the full HTTP message to see if there are any differences, example - any HTTP Headers that you might be missing.  I also noticed you left the IP address of the service in your code, so I tried to ping that service myself, and I'm not getting any response - taking too long to respond.  Of course, my IP Address is probably not whitelisted, but that also brings up another point - making sure the Salesforce IP Addresses are whitelisted with the service.
TerminusbotTerminusbot
Here is the error coming back in the log. Not very informative. 
 
"System.HttpResponse[Status=Bad Request, StatusCode=400]"|0x7fb57afa

I added some debug entries but I can't get the full request to post to the logs. Do you know have to see the entire POST message? 

Here is what I see in the logs currently. Not very helpful. I want to see the entire POST along with header, body, ect..
 
|CALLOUT_REQUEST|[70]|System.HttpRequest[Endpoint=http://167.206.227.210/sagittaws/transporter.asmx, Method=POST]

 
Chris Gary CloudPerformerChris Gary CloudPerformer
Really the only way to see all of the headers is to loop through them from the getHeaders method and display them.  Unfortuantely, there isn't a method that will print out the full request when it is made. At this point, I would suggest getting support from the Service Provider as well, perhaps seeing if they can provide you with a debug statement from their side for the requests originating from Salesforce, and perhaps point you in the right direction of what's wrong.  Sorry I could provide more help!
Chris Gary CloudPerformerChris Gary CloudPerformer
Hello,
Just checking in with you - did you ever get Salesforce to communicate successfully with your web service?