Mark Sanborn Mark Sanborn Fishing Mark Sanborn

Coder, Entrepreneur, Blogger, and Coffee Addict

Calculating USPS Shipping Rates with PHP

Posted on by Mark Sanborn

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.

Things you Need

  • USPS Webtools Account – free but requires registration
  • USPS Username – Comes with the Webtools account
  • serverReporter

  • cURL – Most LAMP (Linux, Apache, Mysql, PHP) web hosts have this installed by default. If you are not sure you have this installed on your server you can use the serverReporter script. Just copy and paste the file upload to your webserver and view it. Go here if you want to know more about the serverReporter.
  • PHP – You should know a little bit about using PHP. After all you are about to create a custom USPS shipping calculator.
  • XML – If you know what PHP is you should know what XML is. You should at least know how XML works in a nutshell.
  • SSH access – Many web hosts offer SSH. You don’t HAVE to have it but it can make troubleshooting easier.

USPS Service Codes

  • FIRST CLASS
  • PRIORITY
  • EXPRESS
  • BPM
  • PARCEL
  • MEDIA
  • LIBRARY
  • ALL

Required XML Tags to Complete a Rate Request

 
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.

  • RateV3Request – Required Once
  • RateV3Request/USERID – Required
  • RateV3Request/Package – Required
  • RateV3Request/Package/Service – Required
  • RateV3Request/Package/ZipOrigination – Required Once
  • RateV3Request/Package/Pounds – Required Once (if it weighs less than a lb use ’0′ Max: 70lbs)
  • RateV3Request/Package/Ounces – Required (use ’0′ if you don’t use ounces)
  • RateV3Request/Package/Size – Required (LARGE,REGULAR,OVERSIZE)

Simple XML Request Example

 
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">

The USPS Rate Calculator PHP Function

 
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);

Troubleshooting

 
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.

Future Versions and More

 
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.



This entry was posted in PHP and tagged , . Bookmark the permalink.

87 Responses to Calculating USPS Shipping Rates with PHP

← Older Comments
  1. Christian says:

    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

  2. Mike says:

    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?

  3. Mark Sanborn says:

    Mike if you go check out the UPS example there are some solutions to your question in the comments.

    If that doesn’t work and you are using php5 you can convert the bottom part of the code to use the simplexml function.

  4. John says:

    Thanks for the code, but please show how to work with FIRST CLASS.

  5. Mark Sanborn says:

    Yes, look for it in an article soon.

  6. Yuvraj says:

    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….

  7. Mark Sanborn says:

    You need to have curl installed… This is a standard program, most hosts support it.

  8. Tim says:

    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.

  9. Mark Sanborn says:

    Unfortunately USPS is a quasi-government institution that makes money no matter how bad they treat their customers. They have no competition since they literally cannot go out of business. Unfortunately this is how the majority of government run operations are.

  10. Tim says:

    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!

  11. Tim says:

    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

  12. Tim says:

    crap Mark can you edit that to have the tags? sorry, i’m out, good luck everyone!

  13. Mark Sanborn says:

    @Tim, You need to get on the production server. Their test server is totally worthless.

    Mark

  14. Tim says:

    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)

  15. James says:

    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.

  16. James says:

    OK Sorry. I figured that out already. No need any fix. Sorry!

  17. Sam says:

    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?

  18. Uday says:

    Hello all,
    I am new to PHP.Please advice me how to intregrate Shipping rate API to my web page.
    thnx in advance

  19. Mark Sanborn says:

    Uday,

    Unfortuantely I don’t have the time right now to teach someone PHP. :(

  20. Mark Sanborn says:

    I beleive they have a service for that. It may infact be in the same API call. Print out the response array and check.

  21. Jade Robbins says:

    Uday,
    the examples are pretty helpful, but you will need to have some php knowledge to use it.

    Good luck!

  22. Nick says:

    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.

  23. James says:

    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.

  24. 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.

  25. Brendan says:

    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

  26. Brendan says:

    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.

  27. Debra says:

    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!

  28. imran says:

    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.

  29. pawan vidya says:

    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

  30. prash says:

    hi Mark,

    can you tell me how to implement USPS directly with production server bcoz in test mode you can change parameters.

  31. rkane says:

    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.

  32. kyle says:

    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 :)

  33. Mark Sanborn says:

    Kyle,

    Unfortunately I already have a production key and cannot test this for you. Like you, I was unable to get any of the test xml to go through, but the production ran just fine. I called them up and they just moved me over. I would suggest calling them again and telling them you would like to move to the production server.

    Hope you get through,

    Mark

  34. Steve-o says:

    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.

  35. reva says:

    Hi mark,
    First time i m using USPS.
    Can u please tell me how can i call to USPS production server to access them.

  36. Uday says:

    Hi Jade and Mark
    Thankx for ur support..I have done UPS shipping successfully

  37. Bhavana says:

    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.

← Older Comments

© 2011 All rights reserved

1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216| generic buying erythromycin alesse next day delivery without a prescription motilium no prescription needed buy cytotec pills canadian pharmacy no prescription needed provera actos by internet buying orlistat pharmacy without prescription lisinopril no prescription needed purchase femara medication buy lipitor cod actonel buy online cheap buy carbozyne online without prescription femara prescription discounts elavil without prescriptions pills buying isotretinoin online pharmacy trazodone no prescription order no prescription metformin birth control no prescriptionAccutane Online Doxycycline online Buy Cheap Lexapro Online No Prescription Prednisone Online Buy Accutane No Prescription