I am doing a fairly large implementation using the exposed APIs of all 4 major shippers. I’ve posted a few notes on USPS, and I’ve been using UPS for so long it almost seems to make perfect sense.
So, while I have to applaud FedEx for the granularity and versatility of the API they have exposed, it has caused me severe headaches due to the PHP SimpleXML issues it brings up with SOAP envelopes — particularly nested soap envelopes.
Long story short, the jist of this post is to help others deal with the responses they receive from the FedEx servers (if, like me, their pre-packaged methods do not implement tidily into your application structure).
Here is a sample response of a rate request (NOTE: this is a “Warning” response, only here for demo purposes):
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<env:Body xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<v8:RateReply xmlns:v8="http://fedex.com/ws/rate/v8">
<v8:HighestSeverity>WARNING</v8:HighestSeverity>
<v8:Notifications>
<v8:Severity>WARNING</v8:Severity>
<v8:Source>crs</v8:Source>
<v8:Code>556</v8:Code>
<v8:Message>There are no valid services available. </v8:Message>
<v8:LocalizedMessage>There are no valid services available. </v8:LocalizedMessage>
</v8:Notifications>
<v8:TransactionDetail xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<v8:CustomerTransactionId>TC05_Rate_Package_Groups_POS</v8:CustomerTransactionId>
</v8:TransactionDetail>
<v8:Version xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<v8:ServiceId>crs</v8:ServiceId>
<v8:Major>8</v8:Major>
<v8:Intermediate>0</v8:Intermediate>
<v8:Minor>0</v8:Minor>
</v8:Version>
</v8:RateReply>
</env:Body>
</soapenv:Envelope>
There are lots of ways you might envision accessing that precious “RateReply” tag, but to keep it simple and avoid inferences, you get to it like this:
$xml = simplexml_load_string ($xml_from_above);
$xml->children(‘http://schemas.xmlsoap.org/soap/envelope/’)->Body->children(‘http://fedex.com/ws/rate/v8′)->RateReply;
I do suppose this is obvious enough, but believe me, the nuances that can throw it off can still cause you to inadvertently lose ridiculous amounts of time on it.
Furthermore, if you prefer to do direct PHP cURL XML calls (which you probably do given that you’re reading this), you’ll find that FedEx is not terribly interested in your type of programmer. To find a simple sample XML call, you’ll have a tough time (although I managed to find it in the WSDL downloadable ZIP). However, this is a very basic call. To add additional data (such as the exotic field that apparently no one would ever think to use — “InsuredValue”) — this field has the form (EXACTLY, stuff in brackets is what can be changed) “<InsuredValue><Currency>[currencytype]</Currency><Amount>[float]</Amount></InsuredValue>”
The “InsuredValue” node/field must go immediately before the “Weight” node in the “RequestedPackageLineItems” node. (This of course reference FedEx API v8 — things may be different in future releases.)
Spoon Carving with a Hook Knife
May 24, 2010 at 9:44 pm
[...] Coffee Cup Half Moons » Blog Archive » FedEx Shipping XML API … [...]
Shrey Malhotra
February 25, 2011 at 11:03 am
Hey can you explain how to make the PHP cUrl Xml call even if it is just the basic call. Dreamhost doesnt support SOAP so please help me do this. Thanks!
Jeremy
February 28, 2011 at 1:42 pm
Well the way I do it is still using the SOAP envelope, I just use it with SimpleXML
Build your XML request into a string ($xmlRequest = ‘
curl_setopt ($c, CURLOPT_POST, 1);
curl_setopt ($c, CURLOPT_POSTFIELDS, $xmlRequest);
curl_setopt ($c, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec ($c);
$responseXml = simplexml_load_string ($response);
Then to access the rate info (and this part is very unintuitive, but it is as so):
$RateReply = $responseNode->children(‘http://schemas.xmlsoap.org/soap/envelope/‘)->Body->children(‘http://fedex.com/ws/rate/v8‘)->RateReply;
Then to see the structure of the replay, just:
echo (htmlentities($RateReply->asXML()));
Shrey Malhotra
March 26, 2011 at 9:13 am
Thanks alot it gave me a solid start ..
Benjamin
December 1, 2011 at 8:39 pm
I am trying to use your method for cURL over xml. My response keeps coming back as:
9999: Empty web-service request, unable to determine service.
Any chance we could get a bigger picture of what you are doing to see if there are other errors?
Jeremy
December 1, 2011 at 8:41 pm
I’m not sure what you mean by other errors. This works fine just the way it is (I have it running on multiple production sites).
You just need to send that request as the payload as a single POST string to the endpoint URL for FedEx’s API.
Benjamin
December 1, 2011 at 8:52 pm
Ah! I forgot the sting part! It is now working correctly. Thanks so much!