checkoutintegrationshipping-ratesdevelopersecommerce

Pincode-Based Shipping Rates in Shopify and WooCommerce (India)

Flat shipping tables do not know that Guwahati costs twice what Pune does. Here is how to show accurate, pincode-based shipping rates in Shopify, WooCommerce or a custom storefront by plugging a rate API into checkout.

P
Postpin Team5 min read
Pincode-Based Shipping Rates in Shopify and WooCommerce (India)

Most Indian stores start with one shipping rule: "₹79 everywhere, free above ₹999". It is easy to set up and wrong for most orders. The fix is the same on every platform: when the customer enters a pincode, ask a rate engine what that lane really costs, and show that number. This guide covers where that call goes in Shopify, WooCommerce and a custom storefront.

Why platform shipping tables fall short

Built-in shipping settings work on countries, states and weight bands. Indian courier pricing works on zones resolved from pincodes: within city, within state, metro to metro, rest of India and special zones. A state-level table cannot tell that:

  • Mumbai (400001) to Pune is a within-state lane, about ₹106 for 1 kg
  • Mumbai to Bengaluru (560001) is a metro lane, about ₹123
  • Mumbai to Guwahati (781001) is a special-zone lane, about ₹221

Add volumetric weight, COD fees and GST and the gap between your table and your courier invoice grows. Our zones guide explains the lanes in detail.

The pattern on every platform

Whatever you run, the integration has the same four steps:

  1. Checkout sends you the cart (weights, dimensions) and the destination pincode.
  2. Your code calls the rate API with origin, destination, weight and payment mode.
  3. The API returns the zone, delivery estimate and an itemised, GST-inclusive total.
  4. You hand the total back to checkout as a shipping option.

The rate call itself is small:

POST /v1/rates/calculate
{
  "origin": "400001",
  "destination": "781001",
  "weight_grams": 1000,
  "service": "surface",
  "payment_mode": "prepaid"
}

Shopify

Shopify supports third-party rates through carrier-calculated shipping. You register a carrier service with a callback URL; at checkout Shopify POSTs the cart and destination to that URL and shows whatever rates you return. Carrier-calculated shipping has to be enabled for your store, so check your Shopify plan before you build.

A minimal callback in Node.js:

app.post("/shopify/rates", async (req, res) => {
  const { origin, destination, items } = req.body.rate;
  const grams = items.reduce((sum, i) => sum + i.grams * i.quantity, 0);

  const quote = await fetch("https://api.postpin.in/v1/rates/calculate", {
    method: "POST",
    headers: {
      "authorization": "Bearer " + process.env.POSTPIN_KEY,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      origin: origin.postal_code,
      destination: destination.postal_code,
      weight_grams: grams,
      service: "surface",
      payment_mode: "prepaid",
    }),
  }).then((r) => r.json());

  res.json({
    rates: [{
      service_name: "Standard delivery",
      service_code: "STD",
      total_price: String(Math.round(quote.total * 100)), // paise
      currency: "INR",
    }],
  });
});

Shopify expects prices in the smallest currency unit, so rupees are multiplied by 100. Keep the endpoint fast and always return a fallback rate if your call fails — a checkout with no shipping options cannot complete.

WooCommerce

WooCommerce lets a plugin register its own shipping method. You extend WC_Shipping_Method, and WooCommerce calls your calculate_shipping function with the cart package whenever the address changes. Inside it you:

  1. Read the destination pincode from the package's destination postcode
  2. Add up the cart weight (and dimensions, if you store them per product)
  3. Call the rate API from PHP with wp_remote_post
  4. Register the result with add_rate, using the GST-inclusive total as the cost

Cache quotes in a transient keyed on pincode and weight bucket. WooCommerce recalculates shipping often, and identical carts for the same pincode do not need a fresh call each time.

Custom storefronts

With a headless or custom build you control the whole flow, so use it earlier in the funnel:

  • Product page: a pincode box showing "Delivery to 560001: ₹123, 2–4 days"
  • Cart: shipping estimate from the saved pincode
  • Checkout: final quote, recalculated when the customer switches between prepaid and COD

Call the API from your server, never from the browser, so your key stays private. The Node.js integration guide covers keys, caching and error handling.

Details that decide accuracy

  • Send dimensions, not just weight. Bulky products are billed on volumetric weight (L × W × H ÷ 5000). Without dimensions you undercharge on every one of them.
  • Recalculate for COD. COD adds roughly ₹35 plus 1.5% of the order value, so the COD option should show its own total.
  • Pick one origin per order. If you ship from two warehouses, quote from the one that will actually fulfil.
  • Decide your display rule. Show the live rate as it is, round it to a clean number, or use it only as a floor behind a flat rate. All three are valid; the live number is what makes them safe.

You can sanity-check any lane by hand with the shipping rate calculator before writing code. The free plan includes 1,000 rate calls a month, which is enough to build and test the whole integration — create a key and try it against your own top pincodes.

Frequently asked questions

Can Shopify calculate shipping by pincode in India?

Not with its built-in rate tables, which work on regions and weight bands. You can do it through carrier-calculated shipping: Shopify calls your endpoint with the destination pincode and cart, and you return rates from a pincode-level rate API. The feature must be enabled on your store's plan.

How do I add pincode-based shipping charges in WooCommerce?

Register a custom shipping method in a small plugin and call a rate API inside its calculate function, using the destination postcode and cart weight. Return the total with add_rate, and cache results briefly so repeated cart updates do not trigger repeated calls.

Should I show live shipping rates or a flat rate to customers?

Either can work. Many stores show a simple flat or free-above-threshold rate on cheap lanes and live rates on expensive ones such as special zones and bulky items. What matters is that you know the true cost per order, even when the customer sees a simpler number.