Calling SOAP API from Epicor

I’m trying to understand how to use SOAP APIs in EPICOR so I can call Fedex’s SOAP API. From my research, It seems like SOAP is considered legacy at this point and REST is the current recommendation. I’d much rather use rest as I already understand how to call REST API’s using a c# custom code function. The problem is I’m trying to integrate with Fedex and their RESTFUL API is underdeveloped. I found this out from their customer support when trying to figure out why my RESTFUL API calls started to fail when specifying SpecialServiceOptions like Hazmat/Dangerous Goods. They told me to not use their RESTFUL API because they don’t know when it would be fully developed to support everything their SOAP API does.

I’m new to SOAP and only learning it for this Fedex integration but I’m planning on implementing a C# custom code function that would generate an XML string and pass it using some C# SOAP library. Before trying this approach, I figured I’d check and see if this is the best way to do SOAP as I haven’t found much resources discussing SOAP API calls in Epicor.

Does anyone have any resources or help on how to perform SOAP calls in Epicor?

Thanks

I have to use SOAP to integrate with one of our 3PL warehouse.
I added each call as a function.

Here’s some code from one you can dig through to get you what you need.

using System.Xml;
using System.Net;
using System.IO;
using System.Text;


// Check if the Epicor instance is production and set the 3PL URL appropriately
var isLive = (
  from sl in Db.SysLicense.With(LockHint.NoLock)
  select sl.IsProductionInstance).DefaultIfEmpty(false).FirstOrDefault();
  
OutMsg = "";

var _url = @"<Test_API_Endpoint>";
var _action = @"<Test_API_Endpoint>";

// Set production 3PL if in production Epicor
if( isLive )
{
  _url = @"<Prod_API_Endpoint>";
  _action = @"<Prod_API_Endpoint>";
}



HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(_url);
webRequest.Headers.Add("SOAPAction", _action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";

string username = "<UserName>";
string password = "<Password>";

string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(username + ":" + password));

webRequest.Headers.Add("Authorization", "Basic " + svcCredentials);

string xml = string.Format(@"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:tpl=""urn:microsoft-dynamics-schemas/codeunit/TPLWebServiceInt"">
   <soapenv:Header/>
   <soapenv:Body>
      <tpl:GetOrderStatus>
         <tpl:pDocType>0</tpl:pDocType>
         <tpl:pDocument>{0}</tpl:pDocument>
         <tpl:pTrackingNumber></tpl:pTrackingNumber>
         <tpl:pStatus></tpl:pStatus>
      </tpl:GetOrderStatus>
   </soapenv:Body>
</soapenv:Envelope>", InDocNum);


XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(xml);

try
{
  using (Stream stream = webRequest.GetRequestStream())
  {
      soapEnvelopeDocument.Save(stream);
  }
  
  // begin async call to web request.
  IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
  
  
  // suspend this thread until call is complete. You might want to
  // do something usefull here like update your UI.
  asyncResult.AsyncWaitHandle.WaitOne();
  
  // get the response from the completed web request.
  string soapResult;
  using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
  {
      using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
      {
        soapResult = rd.ReadToEnd();
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(soapResult);
        XmlElement root = doc.DocumentElement;
        XmlNodeList nodes = root.GetElementsByTagName("GetOrderStatus_Result");
      
        if( nodes.Count > 0 )
        {
          foreach (XmlNode node in nodes)
          {
            OutMsg = node["pStatus"].InnerText.ToString();
          }
        }
      }     
  }
}
catch(WebException e)
{
  using (StreamReader rd = new StreamReader(e.Response.GetResponseStream()))
  {
      // Parse Response XML and display fault reason code
      string msg = rd.ReadToEnd();
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(msg);
      XmlElement root = doc.DocumentElement;
      XmlNodeList nodes = root.GetElementsByTagName("s:Fault");
      
      foreach (XmlNode node in nodes)
      {
          OutMsg = node["faultstring"].InnerText;
      }
  }
}

SoapUI is also helpful in testing. It’s basically the Postman of SOAP.

^ Me waiting for Mr. Wonsil to call me out on using basic auth. :sweat_smile:

2 Likes

That’s helps a ton! I’ll try it out thank you.

1 Like

Oh, I’d never call you out for being basic…