Sample codes > FedEx live rates
FedEx live rates
This example shows how to integrate FedEx live carrier rates into JsRates using the FedEx Rates and Transit Times API.
It demonstrates how to:
- Authenticate with FedEx using OAuth 2.0 (
FEDEX_API_KEY/FEDEX_API_SECRET) - Read product dimensions and weight from Shopify metafields via
enrichItemDetails - Build a FedEx rate quote request (
/rate/v1/rates/quotes) with shipper/recipient + packages - Request account rates (and optionally list rates) plus transit times
- Convert FedEx service types (e.g.
FEDEX_GROUND,PRIORITY_OVERNIGHT) into Shopify shipping rates - Return estimated delivery dates (
min_delivery_date/max_delivery_date) for checkout
This sample is designed for stores that want real-time FedEx pricing instead of flat-rate or rule-based shipping.
Prerequisites
1) Required FedEx credentials (JsRates Secrets)
Create the following secrets in Settings → Secrets (see more information here):
FEDEX_API_KEY(FedEx Project API Key / Client ID)FEDEX_API_SECRET(FedEx Project Secret / Client Secret)FEDEX_ACCOUNT_NUMBER(your FedEx account number)
FedEx APIs use an OAuth bearer token (expires in ~60 minutes), so your app must request a token and reuse it until it expires.
2) Product dimensions + weight metafields
This sample reads item dimensions and weight 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(CM)width(CM)height(CM)weight(KG)
If you only store weight in grams (Shopify grams), you can convert it to KG automatically (this sample supports both).
FedEx API Reference
FedEx live rates in this example are fetched using:
- OAuth token:
POST /oauth/token(x-www-form-urlencoded) - Rate quotes:
POST /rate/v1/rates/quotes(JSON)
Use the correct base URL for your environment:
- Sandbox:
https://apis-sandbox.fedex.com - Production:
https://apis.fedex.com
If you need to support additional FedEx request fields (declared value, special services, duties/taxes, pickup rates, etc.), refer to the official FedEx Rates and Transit Times API documentation and update the request payload accordingly. FedEx Rates and Transit Times APIDocumentation
Sample code
Copy the following code and paste it to a blank calculateShippingRates.js module and save it.
import { enrichItemDetails } from "./modules.js";
// ---------------------------
// OAuth: get FedEx access token
// ---------------------------
async function getFedExToken(env) {
// Sand box url: https://apis-sandbox.fedex.com/oauth/token
// Production url: https://apis.fedex.com/oauth/token
const url = "https://apis.fedex.com/oauth/token";
const body = `grant_type=client_credentials&client_id=${env.FEDEX_API_KEY}&client_secret=${env.FEDEX_API_SECRET}`;
const resp = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
const data = await resp.json();
return data?.access_token || "";
}
// ---------------------------
// Helpers
// ---------------------------
function yyyyMmDd(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, "0");
const d = String(date.getDate()).padStart(2, "0");
return `${y}-${m}-${d}`;
}
function getItemNumber(v, fallback) {
const n = Number(v);
return Number.isFinite(n) ? n : fallback;
}
function toKgFromGrams(grams) {
const g = Number(grams);
if (!Number.isFinite(g)) return 0;
return +(g / 1000).toFixed(3);
}
// ---------------------------
// Main rate calculator
// ---------------------------
export async function calculateShippingRates(DATA, env) {
try {
// 1) Enrich item metafields (dimensions / weight)
DATA = await enrichItemDetails(DATA, [
{ namespace: "custom", size: 10 },
]);
const origin = DATA.origin;
const destination = DATA.destination;
// 2) Build requestedPackageLineItems
// FedEx supports groupPackageCount to represent multiple identical packages.
const requestedPackageLineItems = DATA.items.map((item, idx) => {
const mf = item.metafields?.custom || {};
const lengthCm = getItemNumber(mf.length, 10);
const widthCm = getItemNumber(mf.width, 10);
const heightCm = getItemNumber(mf.height, 10);
// Prefer metafield weight in KG; otherwise convert Shopify grams -> KG.
const weightKg = Number.isFinite(Number(mf.weight)) ? getItemNumber(mf.weight, 0.2) : Math.max(toKgFromGrams(item?.grams || 0), 0.2);
return {
subPackagingType: "PACKAGE",
groupPackageCount: Math.max(1, Number(item.quantity || 1)),
weight: {
units: "KG",
value: weightKg.toFixed(2),
},
dimensions: {
units: "CM",
length: Math.round(lengthCm),
width: Math.round(widthCm),
height: Math.round(heightCm),
},
};
});
// 3) Build rate request payload
// Tip: If you omit requestedShipment.serviceType, FedEx can return multiple services (depending on your account & shipment).
const shipDate = new Date();
const requestBody = {
accountNumber: { value: env.FEDEX_ACCOUNT_NUMBER },
// Optional controls: transit times, sorting, etc.
rateRequestControlParameters: {
returnTransitTimes: true,
servicesNeededOnRateFailure: true,
rateSortOrder: "SERVICENAMETRADITIONAL",
},
requestedShipment: {
shipper: {
address: {
// Use as much detail as you have (city/state helps for US shipments)
postalCode: origin.postal_code,
countryCode: origin.country_code || origin.country,
stateOrProvinceCode: origin.province_code || origin.province || undefined,
city: origin.city || undefined,
},
},
recipient: {
address: {
postalCode: destination.postal_code,
countryCode: destination.country_code || destination.country,
stateOrProvinceCode: destination.province_code || destination.province || undefined,
city: destination.city || undefined,
residential: destination.residential === true ? true : undefined,
},
},
preferredCurrency: DATA.currency || "USD",
// Request both account and list rates
rateRequestType: ["ACCOUNT", "LIST"],
shipDateStamp: yyyyMmDd(shipDate),
pickupType: "USE_SCHEDULED_PICKUP",
packagingType: "YOUR_PACKAGING",
documentShipment: false,
requestedPackageLineItems,
},
};
// 4) Call FedEx Rate Quotes endpoint
// Sand box url: "https://apis-sandbox.fedex.com/rate/v1/rates/quotes
// Production url: https://apis.fedex.com/rate/v1/rates/quotes
const url = "https://apis.fedex.com/rate/v1/rates/quotes";
const token = await getFedExToken(env);
if (!token) return { rates: [] };
const resp = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-locale": "en_US",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(requestBody),
});
const json = await resp.json();
// 5) Transform FedEx reply -> Shopify rates
const replies = json?.output?.rateReplyDetails || [];
const rates = replies
.map((r) => {
const serviceName = r?.serviceName || r?.serviceType || "FedEx";
const serviceCode = r?.serviceType || "FEDEX";
// Prefer ACCOUNT rates if present
const rated = Array.isArray(r?.ratedShipmentDetails) ? r.ratedShipmentDetails : [];
const account = rated.find((x) => x?.rateType === "ACCOUNT") || rated[0];
const amount = account?.totalNetFedExCharge;
const currency = account?.currency || DATA.currency || "USD";
// Transit time / delivery date (if available)
const dayFormat = r?.commit?.dateDetail?.dayFormat || "";
const deliveryDate = dayFormat ? new Date(dayFormat) : "";
if (amount == null) return null;
return {
service_name: serviceName,
service_code: serviceCode,
total_price: (Number(amount) * 100).toFixed(0), // dollars -> cents (string)
currency,
min_delivery_date: deliveryDate,
max_delivery_date: deliveryDate,
};
})
.filter(Boolean);
return { rates };
} catch (err) {
console.error("FedEx Rate Error:", err?.message || err);
return { rates: [] };
}
}
Notes
- Units: This sample sends weights in KG and dimensions in CM.
- Multiple services: If you do not set
requestedShipment.serviceType, FedEx can return multiple services (depending on account eligibility and shipment details). - Transit times: Set
returnTransitTimes: trueto request transit time details when supported. - International customs: For some international rating scenarios, you may need to include
customsClearanceDetailand commodities (depends on your shipment type and account). Add those fields only when needed based on FedEx docs.
Common FedEx service types (examples)
FedEx returns the service type in rateReplyDetails[*].serviceType. Common examples include:
FEDEX_GROUNDFEDEX_2_DAYSTANDARD_OVERNIGHTPRIORITY_OVERNIGHTINTERNATIONAL_PRIORITYINTERNATIONAL_ECONOMY
(Exact availability depends on your origin/destination and account configuration.)
