Main site

Sample codes > UPS live rates

UPS live rates

This example shows how to integrate UPS live carrier rates into JsRates using the UPS Rating API.

It demonstrates how to:

  • Authenticate with UPS using OAuth 2.0 (UPS_CLIENT_ID / UPS_CLIENT_SECRET)
  • Read product dimensions and weight from Shopify metafields via enrichItemDetails
  • Build a UPS RateRequest with packages, weights, and addresses
  • Request negotiated UPS rates and time-in-transit
  • Convert UPS service codes (e.g. 01, 02, 03, 07, 65) into Shopify shipping rates
  • Return delivery dates (min_delivery_date / max_delivery_date) for checkout

This sample is designed for stores that want real-time UPS pricing instead of flat-rate or rule-based shipping.

Prerequisites

1) Required UPS credentials (JsRates Secrets)

Create the following secrets in Settings → Secrets (see more information here):

  • UPS_CLIENT_ID
  • UPS_CLIENT_SECRET
  • UPS_SHIPPER_NUMBER (also known as shipper/account number)

See here on how to create UPS credentials: How to Generate UPS Credentials

2) Product dimensions metafields

This sample reads item dimensions from the custom variant metafield namespace (first 10 values). Make sure to use the correct namespace defined in your store.
Example keys per item (as strings or numbers):

  • length
  • width
  • height

Note: This sample converts item weight from DATA.items[*].grams to pounds for UPS.

UPS API Reference

UPS live rates in this example are fetched using the UPS Rating API.

Official UPS API documentation:
UPS Rating API Reference
https://developer.ups.com/tag/Rating?loc=en_US#section/Reference

This documentation explains:

  • Service codes (Ground, 2nd Day Air, Next Day Air, etc)
  • Request / response schema
  • Rate, negotiated rate, and time-in-transit fields
  • Error handling and validation rules

If you need to support additional UPS services or fields (Saturday delivery, residential flags, etc), refer to the UPS API documentation above and update the request payload accordingly.

Sample code

Copy the following code and paste it to a blank calculateShippingRates.js module and save it.

import { enrichItemDetails } from "./modules.js"; // Enriches item data with metafields like dimensions

// 🔐 Generate a UPS OAuth token using Basic Authorization headers
async function getToken(env) {
    const formData = {
        grant_type: "client_credentials"
    };

    const url = "https://onlinetools.ups.com/security/v1/oauth/token";

    const resp = await fetch(url, {
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
            "x-merchant-id": env.UPS_SHIPPER_NUMBER, // Required UPS field
            "Authorization": "Basic " + btoa(`${env.UPS_CLIENT_ID}:${env.UPS_CLIENT_SECRET}`) // Base64(client_id:client_secret)
        },
        body: new URLSearchParams(formData).toString()
    });

    const data = await resp.json();
    return data.access_token;
}

// 🕒 Add business days (skipping weekends)
function addBusinessDays(numDays) {
    const currentDate = new Date();
    let daysAdded = 0;

    while (daysAdded < numDays) {
        currentDate.setDate(currentDate.getDate() + 1);
        const day = currentDate.getDay();
        if (day !== 0 && day !== 6) daysAdded++; // Skip Sunday (0) and Saturday (6)
    }

    const year = currentDate.getFullYear();
    const month = String(currentDate.getMonth() + 1).padStart(2, "0");
    const day = String(currentDate.getDate()).padStart(2, "0");

    return `${year}${month}${day}`; // Format: YYYYMMDD
}

// 📆 Format UPS date/time into Shopify ISO format
function formatToShopifyMaxDeliveryDate(date, time) {
    const year = date.substring(0, 4);
    const month = date.substring(4, 6);
    const day = date.substring(6, 8);
    return `${year}-${month}-${day}`; // YYYY-MM-DD (Shopify-friendly)
}

// 🚚 Main shipping rate calculator
export async function calculateShippingRates(DATA, env) {
    try {
        // 1. Enrich item dimensions via metafields
        DATA = await enrichItemDetails(DATA, [{
            namespace: "custom",
            size: 10
        }]);
        
        const token = await getToken(env); // 2. Get UPS OAuth token
        console.log("token",token);

        const url = `https://onlinetools.ups.com/api/rating/v2409/shop?additionalinfo=timeintransit`;

        const destination = DATA.destination;
        const origin = DATA.origin;

        // 3. Prepare box/package data for each item
        const boxes = DATA.items.map(item => {
            const dims = item.metafields?.custom || {};
            const weightLbs = (item?.grams || 100) / 453.592; // Convert grams to pounds
            return {
                totalWeightInPounds: weightLbs,
                dimensions: {
                    length: Number(dims.length || 10),
                    width: Number(dims.width || 10),
                    height: Number(dims.height || 10)
                }
            };
        });

        // 4. Calculate total shipment weight
        const totalWeight = boxes.reduce((sum, b) => sum + b.totalWeightInPounds, 0);
        const ShipmentTotalWeight = {
            UnitOfMeasurement: {
                Code: "LBS",
                Description: "Pounds"
            },
            Weight: totalWeight.toFixed(2)
        };

        // 5. Construct package list for UPS API
        const packages = boxes.map(box => ({
            PackagingType: {
                Code: "02",
                Description: "Package"
            },
            PackageWeight: {
                UnitOfMeasurement: {
                    Code: "LBS",
                    Description: "Pounds"
                },
                Weight: box.totalWeightInPounds.toFixed(2)
            },
            Dimensions: {
                UnitOfMeasurement: {
                    Code: "IN",
                    Description: "Inches"
                },
                Length: box.dimensions.length.toString(),
                Width: box.dimensions.width.toString(),
                Height: box.dimensions.height.toString()
            }
        }));

        const pickupDate = addBusinessDays(2); // Assume 2 business days prep time

        // 6. Construct UPS API request payload
        const requestBody = {
            RateRequest: {
                Request: {
                    TransactionReference: {
                        CustomerContext: "CustomerContext"
                    }
                },
                PickupType: {
                    Code: "01", // Daily pickup
                    Description: "Daily Pickup"
                },
                CustomerClassification: {
                    Code: "00", // Rates Associated with Shipper Number
                    Description: "Rates Associated with Shipper Number"
                },
                Shipment: {
                    Shipper: {
                        Name: "Store",
                        ShipperNumber: env.UPS_SHIPPER_NUMBER,
                        Address: {
                            AddressLine: [origin.address1],
                            City: origin.city,
                            StateProvinceCode: origin.province,
                            PostalCode: origin.postal_code.replace(/\s/g, ""),
                            CountryCode: origin.country
                        }
                    },
                    ShipTo: {
                        Name: "ShipToName",
                        Address: {
                            AddressLine: [destination.address1],
                            City: destination.city,
                            StateProvinceCode: destination.province,
                            PostalCode: destination.postal_code.replace(/\s/g, ""),
                            CountryCode: destination.country
                        }
                    },
                    ShipFrom: {
                        Name: "Store",
                         Address: {
                            AddressLine: [origin.address1],
                            City: origin.city,
                            StateProvinceCode: origin.province,
                            PostalCode: origin.postal_code.replace(/\s/g, ""),
                            CountryCode: origin.country
                        }
                    },
                    PaymentDetails: {
                        ShipmentCharge: [{
                            Type: "01", // Bill to Shipper
                            BillShipper: {
                                AccountNumber: env.UPS_SHIPPER_NUMBER
                            }
                        }]
                    },
                    ShipmentRatingOptions: {
                        TPFCNegotiatedRatesIndicator: "Y",
                        NegotiatedRatesIndicator: "Y"
                    },
                    ShipmentTotalWeight,
                    NumOfPieces: boxes.length.toString(),
                    Package: packages,
                    RatingMethodRequestedIndicator: "Y",
                    DeliveryTimeInformation: {
                        PackageBillType: "03", //  Non-Document
                        Pickup: {
                            Date: pickupDate
                        }
                    }
                }
            }
        };
        
        console.log("requestBody",requestBody);

        // 7. Fetch UPS rates with transit info
        const response = await fetch(url, {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                transId: "transactionId123", // Arbitrary transaction ID
                transactionSrc: "Shopify", // Source ID for tracking
                Authorization: `Bearer ${token}`
            },
            body: JSON.stringify(requestBody)
        });

        const data = await response.json();
        
         console.log("response data",data);
         
        const ups_service_codes = ["03","01","02","07","54","65","11","08"]; // Added international codes
        const service_names = ["UPS® Ground","UPS Next Day Air®","UPS 2nd Day Air®","UPS Worldwide Express®","UPS Worldwide Express Plus®","UPS Worldwide Saver®","UPS Standard®","UPS Worldwide Expedited®"];
        const shopify_service_codes = ["UPS_Ground","UPS_Next_Day_Air","UPS_2nd_Day_Air","UPS_Worldwide_Express","UPS_Worldwide_Express_Plus","UPS_Worldwide_Saver","UPS_Standard","UPS_Worldwide_Expedited"];

        const shipments = data?.RateResponse?.RatedShipment || [];
        const filtered= shipments.filter(shipment => ups_service_codes.includes(shipment.Service.Code) );


        // 8. Transform into Shopify rate objects
        const rates = filtered.map(svc => {
            const ups_code = svc?.Service?.Code;
            const code_index = ups_service_codes.indexOf(ups_code);
            
            const arrival = svc?.TimeInTransit?.ServiceSummary?.EstimatedArrival?.Arrival || {};
            const deliveryDate = arrival.Date && arrival.Time ? formatToShopifyMaxDeliveryDate(arrival.Date, arrival.Time) : "";
            
            let description = "";

            const arrivalDays = svc?.GuaranteedDelivery || svc?.EstimatedArrival;
    
            if (arrivalDays?.BusinessDaysInTransit) {
              description += `Estimated to arrive by ${arrivalDays.BusinessDaysInTransit} business days`;
            }

            return {
                service_name: service_names[code_index],
                service_code: shopify_service_codes[code_index],
                total_price: ( parseFloat(svc?.NegotiatedRateCharges?.TotalCharge?.MonetaryValue) * 100 ).toFixed(0),
                currency: DATA.currency,
                description,
                min_delivery_date: deliveryDate,
                max_delivery_date: deliveryDate
            };
        });

        return {
            rates
        };
    } catch (error) {
        console.error("UPS Rate Error:", error.message);
        return {
            rates: []
        };
    }
}

Notes

  • Transit times: additionalinfo=timeintransit is requested; if UPS does not return arrival info for a service, delivery dates will be empty for that rate.

  • Units: UPS rate requests use LBS for weight and IN for dimensions in this example.

UPS Service Codes (Common)

Code Service name
01 UPS Next Day Air
02 UPS 2nd Day Air
03 UPS Ground
07 UPS Worldwide Express
08 UPS Worldwide Expedited
11 UPS Standard (Canada / Europe ground)
12 UPS 3 Day Select
13 UPS Next Day Air Saver
14 UPS Next Day Air Early A.M.
54 UPS Worldwide Express Plus
59 UPS 2nd Day Air A.M.
65 UPS Worldwide Saver
82 UPS Today Standard
83 UPS Today Dedicated Courier
84 UPS Today Intercity
85 UPS Today Express
86 UPS Today Express Saver

Note
UPS does not guarantee that every service code will be returned for every shipment.
The services returned depend on:

  • Your UPS account & shipper number
  • Origin & destination countries
  • Package dimensions & weight
  • Negotiated rates & enabled services