Coder, Entrepreneur, Blogger, and Coffee Addict
If you have a custom shopping cart and you want to calculate actual shipping rates from USPS this is the post for you. After giving up searching the internet for PHP scripts or examples of implementing USPS rates I decided to create my own. I hope that by the end of this post you will have an understanding of the process and you can begin implementing USPS rates in your own website.
The function discussed below is used for communicating with the United States Postal Service (USPS). If you are looking for the United Postal Service (UPS) function see, Calculating UPS Shipping Rate with PHP.
After looking through the USPS rates manual I begain to try and create a working script. None of the examples in the manual worked for me so I called them up. They ended up just moving my account from testing to production. If you are just starting out I would suggest you call them and start mentioning how their examples didn’t produce the same results and you are attempting to create an application using their API.
When I called USPS the lady on the phone said, “I don’t know what you are talking about. I’ll just move your account to production”. Once I was moved to the production server all of the examples in the user manual worked and I was on my way to creating my very own implementation of the USPS rates API.
I am still not sure why they provide a testing server if it doesn’t work the same way as the production server.
You may wish to grab a copy of the USPS Rates Manual for yourself.
The USPS API requires cetain XML tags in the request before it will start its rate calculations. If you fail to provide the required tags USPS will return with an error code. I have provided the required XML tags for you.
A barebones request was taken straight from the USPS manual. It is a simple XML file that needs to be posted to the USPS server. As you can see it contains all the required XML tags. Of course you will need to change the USERID to your actual USERID that you got from registering with USPS.
<RateV3Request USERID="000AAAAA9999"> <Package ID="1ST"> <Service>FIRST CLASS</Service> <FirstClassMailType>LETTER</FirstClassMailType> <ZipOrigination>44106</ZipOrigination> <ZipDestination>90210</ZipDestination> <Pounds>0</Pounds> <Ounces>0.75</Ounces> <Size>REGULAR</Size> <Machinable>false</Machinable> </Package> </RateV3Request>
If you noticed there was only one package included in this request. The USPS API allows multiple packages in one XML request. To lighten the load and time it takes to generate rates for multiple packages it is recommended that you send a single XML request with multiple packages as opposed to sending multiple XML requests for single packages.
You can add more packages to the code by adding another XML package set:
<Package ID="2nd">
Finally, the code that you have all been waiting for. This is the PHP function that will return the USPS rate as a decimal value for use in displaying or calculating the shipping cost and final charge to the customer.
<?php
function USPSParcelRate($weight,$dest_zip) {
// This script was written by Mark Sanborn at http://www.marksanborn.net
// If this script benefits you are your business please consider a donation
// You can donate at http://www.marksanborn.net/donate.
// ========== CHANGE THESE VALUES TO MATCH YOUR OWN ===========
$userName = 'username'; // Your USPS Username
$orig_zip = '12345'; // Zipcode you are shipping FROM
// =============== DON'T CHANGE BELOW THIS LINE ===============
$url = "http://Production.ShippingAPIs.com/ShippingAPI.dll";
$ch = curl_init();
// set the target url
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
// parameters to post
curl_setopt($ch, CURLOPT_POST, 1);
$data = "API=RateV3&XML=<RateV3Request USERID=\"$userName\"><Package ID=\"1ST\"><Service>PRIORITY</Service><ZipOrigination>$orig_zip</ZipOrigination><ZipDestination>$dest_zip</ZipDestination><Pounds>$weight</Pounds><Ounces>0</Ounces><Size>REGULAR</Size><Machinable>TRUE</Machinable></Package></RateV3Request>";
// send the POST values to USPS
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
$result=curl_exec ($ch);
$data = strstr($result, '<?');
// echo '<!-- '. $data. ' -->'; // Uncomment to show XML in comments
$xml_parser = xml_parser_create();
xml_parse_into_struct($xml_parser, $data, $vals, $index);
xml_parser_free($xml_parser);
$params = array();
$level = array();
foreach ($vals as $xml_elem) {
if ($xml_elem['type'] == 'open') {
if (array_key_exists('attributes',$xml_elem)) {
list($level[$xml_elem['level']],$extra) = array_values($xml_elem['attributes']);
} else {
$level[$xml_elem['level']] = $xml_elem['tag'];
}
}
if ($xml_elem['type'] == 'complete') {
$start_level = 1;
$php_stmt = '$params';
while($start_level < $xml_elem['level']) {
$php_stmt .= '[$level['.$start_level.']]';
$start_level++;
}
$php_stmt .= '[$xml_elem[\'tag\']] = $xml_elem[\'value\'];';
eval($php_stmt);
}
}
curl_close($ch);
// echo '<pre>'; print_r($params); echo'</pre>'; // Uncomment to see xml tags
return $params['RATEV3RESPONSE']['1ST']['1']['RATE'];
}
?>
I have created a working model of the rates calculation that will compare rates between USPS and UPS.
To use the function you use the following format:
USPSParcelRate($weight,$dest_zip)
An example of this being called on your website would be:
echo USPSParcelRate(3,90210);
If you are not recieving a rate from the USPS servers you need to check what error message they gave. My script will output the entire XML response in html comment tags. This will allow you to view any errors generated by the USPS API. To view this you will need to uncomment the lines specified in the function and simply click view source in your browser and look for the XML data.
I plan to create a more intricate version that will have many more options. Instead of being a simple function it will be a complete rate calculation tool. I plan to eventually create a framework that allows developers an easy and quick way to develop entire full feature shipping modules. The current open source shopping projects in my opinion are very lacking and do not really allow the users complete control to integrate with their own systems or systems that are already in place. The current solutions are more like a pre-built website with a shipping module. My framework would be for those who wish to create their own shipping systems or integrate with an existing one.
So, what would you like to see in a framework? What options and configurations would you like to see? Please leave a comment below.
Also stay tuned for my post about how I created a script that calculates how many widgets will fit in a box before having to add another box to the shipping total. Many sites will end up charging the customer one package for the total weight of the cart. Other times they will charge as if each widget was shipped in its own box. I will discuss why each of these methods are flawed and how I found a solution.
I have the same Undefined offset issue as Mike and Keith above which was never addressed.
The same undefined offset Notice comes out every time there is an attribute in the XML returned from USPS. I get the notices mentioned in the UPS rate script comments as well but that is on a different line of code, but equally concerning.
I would really like some guidance in to fixing these issues. I think others don’t see the messages simply because they have notices suppressed, but I’d rather fix the code if possible. Can you offer me any guidance?
Thanks for the code, but please show how to work with FIRST CLASS.
When i am using above script i am getting below error
“Fatal error: Call to undefined function curl_init() in C:\Program Files\xampp\htdocs\sites_comp\USPS test\index.php on line 16
“.
Can u please tell where u declared ‘curl_init()’ this function.
have i need to any other file for this function….
I’ve never been more unsatisfied with a customer care department as I have been with USPS. I’ve made about 3-5 phone calls to the IT number 1-800-344-7779 and gotten the same response (even after explaining RateV2 returns invalid zip code erros and RateV3 is an invalid XML format) that I need to email icustomercare@usps.com which I have already done and gotten in a back and forth argument with the “care” representative that I know what I’m talking about and he is not helping me.
Absolutely ridiculous. And I can’t simply use UPS or FedEx because the client wants USPS for its lower prices. I can see now why, they spend no money on their technical support.
The only semi-valid response i’ve gotten was that I need to use “canned” request data when submitting to the testing server, this is great, because all the examples I see in the documentation are V3?
Does anyone know what the canned XML request is so I can get this over with? I’m going on 4 weeks of BS with these people and I’ve had the script done since the middle of january!
Sorry for hijacking your board, here are two “canned” XML requests you can use to successfully ping the testing server for your account:
Test Request #1
PRIORITY
10022
20008
10
5
Flat Rate Box
REGULAR
Test Request #2
All
10022
20008
10
5
LARGE
TRUE
Ping the server 3 times, then call 1-800-344-7779 and have them check your status on the testing server for your username
crap Mark can you edit that to have the tags? sorry, i’m out, good luck everyone!
@Tim, You need to get on the production server. Their test server is totally worthless.
Mark
I know, I am now. But what I’m saying is, I tried 7 times or so by phone and email to just ask them and tell them why and they still made me submit those queries. The XML I posted above I’m going to try and “pre” tag below, maybe it will work. Once I sent these 3 times they let me on.
Test Request #1
PRIORITY
10022
20008
10
5
Flat Rate Box
REGULAR
Test Request #2
All
10022
20008
10
5
LARGE
TRUE
(i’m sorry in advance if the pre tags don’t work)
There is this “Undefined offset: 1 in ..” mentioned in this blog several times which has yet to be solved. Reading the ups-php doesn’t help.
OK Sorry. I figured that out already. No need any fix. Sorry!
Is it possible to get estimated delivery times with a request? I noticed when doing international requests (with another script), estimated delivery times are returned, but not with domestic. When I use this script and change the SERVICE to ALL, and add a ShipDate parameter, I *do* get estimated delivery responses, but only for the Express options. Not Priority, First Class, Media Mail, etc. Do I need to use the separate delivery times API?
Hello all,
I am new to PHP.Please advice me how to intregrate Shipping rate API to my web page.
thnx in advance
Uday,
the examples are pretty helpful, but you will need to have some php knowledge to use it.
Good luck!
I can’t seem to get any delivery times for non-express non-international shipments as well.
In the webtools api document, it says that shipdate is ignored for all domestic non-express shipments.
I’m trying to figure out if there is a correlation between and delivery times, as there must be but I cannot find a chart.
Mark,
Oh no. This “Undefined offset: 1 in ..” problem comes back again and I haven’t changed anything. It never really gets solved in the first place. Seriously has anyone ever managed without this problem? Would anyone be kind to share the solution? Thanks very much.
This was the most helpful page I’ve found yet on the USPS api.
After spending several hours poring over the USPS webtools site I discovered this site through Google and I’m glad I did.
By adding a short input form, this code can be adapted to return most of the info available from the USPS. Thanks again.
I’d like to implement this in an existing form of mine so customers could add their shipping amount before our form posts to paypal for payment. Would you be willing to look at my existing checkout code (we currently sell 1 product only, nothing fancy) and point me in the right direction? I’ve been attempting to get through the usps manual and it’s unfathomable to me and yes, I know, the testing server is useless. Whatever info you need from me and however you’d like to work it, if at all, just let me know. Thanks
I’m obviously missing something as it isn’t working properly. It’s showing up as text in a web page I used to test the code. I’ve managed to get through coding problems before but this one has me at a loss. It’s probably some miniscule detail that I’m not seeing. Any help would be appreciated, I’ll send the page to you if that helps.
Mark:
Thanks SO much for this. I don’t think I could have figured this out on my own. After reading through all the comments here, I futzed around with the testing server a little, emailed the USPS on a Friday night with my production server request and got moved Saturday afternoon. The script works perfectly. You rock!
Hello Everyone, I am facing the problem. I have to integrate USPS API to my site to calculate shipping price of products. I am getting these errors on test and development server.
This error produces on test server of USPS.
These are parameters which I am using
$userName = ‘abc’; // Your USPS Username
$PWD = ’123456′;
$orig_zip = ’35006′; // Zipcode you are shipping FROM
$url = “http://testing.shippingapis.com/ShippingAPITest.dll”;
API=RateV2&XML=PRIORITY3500636310300REGULARTRUEHTTP/1.1 200 OK Connection: close Date: Fri, 05 Jun 2009 10:18:24 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET -2147219498Rate_Respond.DomesticRatesV2Test:clsRatesV2TestValidateParameters:clsRatesV2TestProcessRequest;SOLServerRatesTest.RateV2_RespondPlease enter a valid ZIP Code for the sender. 1000440
This error produces on production server
$userName = ‘abc’; // Your USPS Username
$PWD = ’123456′;
$orig_zip = ’35006′; // Zipcode you are shipping FROM
$url = ” https://Production.ShippingAPIs.com/ShippingAPI.dll”
API=RateV3&XML=PRIORITY3500636310300REGULARTRUEcURL Failed to connect!
Please help me to solve this problem.
Hi I am getting this every time
Array
(
)
with no result?
i have done registration on USPS site . i am using user_name and zip_code but not working .
please help me
hi Mark,
can you tell me how to implement USPS directly with production server bcoz in test mode you can change parameters.
If you are not in production you can use the testing server, and the only addresses that I know that will work are NY 10022, and DC 20008 with a weight of 10 lbs, 5 oz.
Talked to USPS several times and they sent me this twice:
“Thank you for contacting us. The test logs under your UserID do not show valid test requests. We are unable to move your account to the production server until a valid test request is received. If you are using third party software, testing is not required. However, you must provide us with the name of the software you are using. We can then update your account.
Thank you for using the USPS.”
Then i showed my code and they said i had to use V2 and not V3 on the testing server:
here is the code that fails even on the V2:
http://testing.shippingapis.com/ShippingAPITest.dll?API=RateV2&XML=PRIORITY1002220008105FLAT RATE BOXREGULAR5.511true
I am at a lose here anybody got any ideas, should i say im using mark sanborns code
Make sure you use 10022 as the “zip origination” (sender) and 20008 as the “zip destination.” If it’s reversed, it won’t work. Also, I could only get 10 lbs and 5 ounces to work.
Totally useless test server.
Hi mark,
First time i m using USPS.
Can u please tell me how can i call to USPS production server to access them.
Hi Jade and Mark
Thankx for ur support..I have done UPS shipping successfully
Hi mark,
Thanks for such a wonderful post.
I am getting rates for domestic request, but i dont know that what changes i have to do for getting international shipping rates.
Please help me out…
I am getting error of invalid zip code for valid india’s city zipcode..
Please help me.
Thanks.
© 2011 All rights reserved
I had the same problem as mentioned before regarding the testing server and V3. I called the support number and was instantly upgraded to the production server and all seems to be well with it.
Changing service to All is handy for getting the rates for all shipping services. It will come in handy as I give customers the option to see estimated shipping costs before final checkout in my shopping cart.
Christian