Documentation You are here: start » v » 2.0 » shipping


A Shipping Haiku

Packages… point a,
point b, beyond? My mind drifts
to the endless pain.

Prior to launching FoxyCart we had months of discussions about shipping. One of the scenarios that we discussed was a mattress store. The mattress store may need to ship very large and heavy items, but also may need to ship pillows. They may also need to ship things via custom shipping carriers or freight options. In our early discussions, the afore-attributed anonymous lead developer said something like, “That's a ridiculous scenario. The average merchant won't have anywhere near the complexity in their shipping requirements.” The other person agreed, and FoxyCart development moved on.

Unfortunately, while the specifics of the mattress seller haven't come up, shipping requirements can vary so wildly from business to business that no one system can meet every need. FoxyCart's current shipping functionality does some things very well, while other things may require intermediate or advanced customizations to get right. Read on to see both how FoxyCart's shipping capabilities can meet your needs currently, as well as our plans for the future.

Different Types of Shipping Functionality

FoxyCart currently offers a few different approaches to shipping, listed here and discussed in more detail below:

  • Live rates through USPS, UPS, and FedEx.
  • Flat rates per category.
  • Special rates for “Free Ground Delivery” and “Customer Pickup”.
  • Handling fees can be applied per category in a variety of ways
  • Non-shippable / intangible / downloadable products, which don't get shipping applied, but are listed here just to clarify.
  • Custom Endpoints & Custom Logic allow you to either replace or augment the built-in Foxy shipping functionality with your own code.

Shipping and Categories

Because a single store may have multiple categories, each with its own shipping options and handling fees, it's important to understand how combining different shipping rates works. Assume you have 4 product categories: two of them may be set to use live rates, one set to no shipping, and one set to flat rates. If the customer has products from all four categories in one cart, the checkout will present the customer with all of the returned live rates, each combined with all of the additional flat fees and handling fees for the other categories.

So, regardless how many categories or options are selected, all the shipping fees will be combined when presented to the customer.

Live Shipping Rates

Live shipping rates are configured store-wide, but can be enabled per category. As of this FoxyCart version, live rates are requested from the selected carriers using the options selected in your store's config. The total weight of your products are sent to the shipping carrier(s) to get the rates, but the dimensions of the shipment are not sent, and default to a 5“x5”x5“ package unless the package type supercedes that default.

Beginning in FoxyCart 2.0, it is possible to dynamically customise the package dimensions sent to the selected carriers. Review this snippet for further details on how to do that.

We are planning a rebuild of our shipping functionality for a future version, so please add a comment with your needs and vote for this feature request.

Supporting Multiple Packages Per Shipment

We currently have basic support for multiple packages per shipment through the “max package weight” setting available on the “shipping” page of the Foxy administration. If set, this will set the maximum amount that an individual package can be before the shipment is broken into multiple packages.

This works with some basic maths to work out the number of packages required. It divides the total weight by the max package weight and rounds up to get the number of packages, then divides the total weight by the number of packages to get the individual package weight. This is then sent to the shipping carriers as the package weight. This means that the max package weight won't necessarily be the individual package weight - but it will be the most that an individual package will weigh.

It's worth noting that in some instances shipping rates may end up being cheaper when broken into smaller packages. For example, it may be cheaper to ship 2 25lb packages than 1 50lb package.

If you've set a max package weight value for your store, the number of packages and their individual weight will be saved as attributes on the transaction. These will be displayed within the transactions report in the administration, and are also available through the API.

Different carriers also have different maximum package counts that they support for rate requests. Currently USPS supports 25, UPS supports 50, and FedEx supports 999. If the package count exceeds these thresholds for a given carrier, no rate request will occur for that provider. If it exceeds all the providers you've selected for your store, the generic “no shipping results found” error will be displayed to the customer.

Residential v. Commercial Rate Requests

Some carriers offer different prices or services to residential addreses than they do to commercial addresses. You can select from three options in your store's “shipping” page in the admin:

  1. Rate as Residential. (Force residential rate requests.)
  2. Rate as Commercial. (Force as commercial rate requests.)
  3. Rate based on Company field. If you select this option the address will be rated as a commercial address if the company field (on the checkout form) for that address is not blank, otherwise it will be rated as a residential address.

Along with the above setting in the administration, you can also override it per transaction using the h:shipto_residential custom session boolean attribute. You can set it as part of a normal add to cart or a JSONP request as either true or false depending on if the transaction is a residential shipment or not.

Wholesale v. Retail Rates

Some carriers display different rates based on the drop type you select. For example, UPS defaults to Wholesale if you select “Daily Pickup”, uses Retail for “Customer Counter” and “Suggested Retail Rates” and uses what it calls Occasional Rates for “One Time Pickup”, “On Call Air”, “Letter Center” and “Air Service Center”. Some systems will always show a discount when you are logged in to the API or to their website (as opposed to getting a rate request from their website without logging in). For this and other reasons, we recommend you use your own shipping account to ensure the rates more accurately reflect your actual shipping costs.

Special Rate Notes


  • FedEx Ground is only available for commercial/business shipments or for deliveries over 70 pounds, where as FedEx Home Delivery is it's residential counterpart for packages up to 70 pounds. If you have the shipping rates set to 'commercial' (at the top of the shipping page of your stores admin) or to 'based on the company field' and the customer has entered a company name, then FedEx Ground will appear. If you've set it to be 'residential' or the customer didn't enter a company name, then FedEx Home Delivery will appear.


  • UPS Standard in the US is only available for shipments that originate in the US and have a destination in either Canada or Mexico. Full details. UPS Ground might be what you're after.
    • UPS Ground won't be returned if you've selected an express container type.


  • USPS Retail Ground (formerly Standard Post) is generally only available for shipment zones 5-9 within the US. Full details, and you can check your zones here. If you're looking for a full domestic rate, look at the First Class or Priority Mail rates.

Flat Rate Shipping

Flat rate shipping, unlike the live rates above, is configured per category and not store-wide. The flat rate value is applied once per category, regardless of the number of products in the category. (See the handling fees section for other options.)

"Custom" Options

There are two “special” options that are treated as live rates:

  • Free Ground Shipping
  • Free Customer Pickup

Both options will only be shown to customers that have a shipping country matching your store's country, as configured in your store's settings. Also, the text displayed for both options is configurable, so you could use these as other types of “free” shipping entirely.

To enable these options, navigate to your store's “Shipping” page, and towards the bottom enable the “use custom” option and select the rates you'd like to use.

Custom Shipping Endpoint

To allow you to provide completely custom shipping options, a custom endpoint option is available to you. This sends the shipping request from the cart and checkout to an endpoint script of your choosing. There you can calculate custom rates or query a subsequent request on to different carriers before returning the custom rates to the customer.

To enable this option, navigate to the “Shipping” section of your store's FoxyCart administration, at the bottom of the page enable the use custom endpoint option and provide a URL to your endpoint. It also relies on a category with a delivery type of Shipped using live shipping rates.

You'll also want to consider turning on the enable shipping rate signing option. This attaches a signature to each shipping rate returned to the customer, that is created using details of the rate, and the customer information used to get it (like weight, address etc). The signature allows us to confirm that the details that were used to generate the shipping rate match those that are submitted with the checkout. If it doesn't then the customer is sent back to the checkout to re-select a shipping rate.

As the custom shipping endpoint relies on setting categories to use live shipping rate delivery, it will also require that you enter a default weight for products in that category, and will also display the products weight in the cart. To stop the weight displaying in the cart, enable the “Customise cart display” option on the configuration page in the administration, de-select the “Show product weight” option and save the changes to the page.

Helper Libraries

We have some helper shipping endpoint libraries which will take care of some of the heavy lifting for you - so you can just focus on creating your custom shipping logic. We currently have the following languages, and will expand on them in the future as we're able. Refer to the README for each language for how to use them.

Handling the request

When the customer enters their shipping details, a POST request is sent off to your custom shipping endpoint with a JSON payload representing the current cart. It follows the same structure as our Hypermedia API, as the majority of the data comes from there.

You can see an example of the shipping payload sent with the request here.

Sending a response

In response, FoxyCart expects a JSON payload in the following format to be output on the page (prettified for display purposes):

    "ok": true,
    "data": {
        "shipping_results": [
                "service_id": 10001,
                "price": 10.55,
                "method": "FoxyPost",
                "service_name": "Standard",
                "service_id": 10002,
                "price": 20.99,
                "method": "FoxyPost",
                "service_name": "Express",

Note: service_id from a custom shipping endpoint needs to be 10000 or higher, and should be unique per rate.

    "ok": false,
    "details": "Sorry, we're unable to ship to that region"

Only a valid JSON object should be output to your custom endpoint. If you output other elements to the page that is not part of a valid JSON object, the rates will fail to load and a generic error will be displayed.

Passing custom fields to the custom shipping endpoint

By default - any custom session attributes currently in the customers session will be included in the payload within the fx:custom_fields node. This includes anything added to the cart session using h: prepended before the attribute in an add to cart.

Sometimes though you need to capture information from a customer on the checkout related to the shipping, such as whether a signature is required on delivery, which affects the rates calculated on your custom endpoint. To do that, you can add custom checkout fields to your store, and add a data-fc-shipping-custom-field data attribute to the form elements. Whenever any fields with that data attribute are changed, it will trigger the shipping rates to the refreshed, including those values in the payload sent to your endpoint.

<!-- Checkbox -->
<input type="checkbox" id="sign_on_delivery" name="sign_on_delivery" value="Yes" {% if sign_on_delivery == "Yes" %}checked{% endif %} data-fc-shipping-custom-field>
<label for="sign_on_delivery">Sign on Delivery?</label>
<!-- Radio inputs -->
<input type="radio" id="lift_required_yes" name="lift_required" value="Yes" {% if lift_required == "Yes" %}checked{% endif %} data-fc-shipping-custom-field>
<label for="lift_required_yes">Include a lift</label><br/>
<input type="radio" id="lift_required_no" name="lift_required" value="No" {% if lift_required == "No" %}checked{% endif %} data-fc-shipping-custom-field> <label for="lift_required_no">Don't include a lift</label>
<!-- Text input -->
<input type="text" id="message" name="message" value="{{ message }}" data-fc-shipping-custom-field>
<!-- Select options -->
<select name="pickup_location" data-fc-shipping-custom-field>
  <option value=""></option>
  <option value="factory">Factory</option>
  <option value="store">Store</option>

If a value is already present in the cart session, and a custom checkout field shares the same name - the custom checkout field will overwrite the existing custom field in the session when sent to the custom shipping endpoint.

If needed, you can also pass custom fields to the shipping endpoint using javascript and our events, specifically cart-shipping-options-update and checkout-shipping-options-update. Updates made by these events will overwrite any existing attributes already in the session, but will be overwritten by any matching custom checkout fields.

FC.client.on("checkout-shipping-options-update", function(params) {
	params.custom_fields = { my_custom_attr: true };

Common Errors

“Error: This store has not been setup correctly to calculate shipping to this location with this weight.”

If you receive this error in your store, that means that either no rates were returned from your custom endpoint, or it didn't return a valid JSON object.

  1. Firstly ensure that your endpoint is set to return at least one rate or an error for all requests.
  2. If you are - ensure that only the JSON output is printed on the page. You can't have any other text on the page.

Custom Shipping Code

The Custom Shipping Code option allows you to enter custom code into your store's Foxy administration which can add new rates, or modify or remove existing rates from other shipping carriers configured for your store. This provides you with complete flexibility in what rates are available for your customers.

The code also has access to an object providing information about the current customer's cart - including the products in the cart, their address details, details about the transaction like currency and language, as well as any existing rates returned from other configured carriers.

This feature currently relies on adding javascript code to handle the custom logic - but in the future will also support an interface for setting up custom rates and conditions.

Review this page for more details on configuring the Custom Shipping Code option for your store.

Handling Fees

Handling fees, like flat rates, are configured per category, but can be applied in a few different ways:

  1. Flat fee per shipment with products in this category
  2. Flat fee per product in this category
  3. Flat fee per shipment + % of price for products in this category
  4. Flat fee per shipment OR % of order total with products in this category. Whichever is greater.

When paired with a flat fee, the handling fee can become quite a powerful tool for adjusting shipping costs. Handling fees also work with live rates, but note that handing fees do not apply if a category is set to “no shipping”.

Fulfillment Houses

FoxyCart stores can integrate with a variety of fulfillment houses using functionality like the API and the transaction datafeed. Or check our integrations section for existing code or services (like Order Desk, a third-party bridge between FoxyCart and

Feature Requests, Plans, and Known Limitations

There are many common requests that can be achieved with FoxyCart, but require a little bit of code to make work. Please view this list of links, and ask in our forum if you don't see what you're looking for (or if you need help).

We are planning a rebuild of our shipping functionality for a future version, so please add a comment with your needs so we can be sure our new solution handles your situation.

Specific Workarounds

Site Tools