Calculating USPS Shipping Rates with PHP

Last updated: May 14, 2008
Update: For a no fuss, 100% complete USPS script with label printing support, integration and support, I have created, RocketShipIt.

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
  • 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 https://www.marksanborn.net  
// If this script benefits you are your business please consider a donation  
// You can donate at https://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.

Need to print shipping labels on your site?

Checkout my product RocketShipIt for simple easy-to-use developer tools for UPS™ FedEx™ USPS™ and more.

Get notified on new posts or other things I'm working on

Share: