Walkthroughs
Rate shop an LTL shipment
Quote a freight shipment across every carrier in your network, compare landed cost, and pick the winner.
This walkthrough takes a single shipment request — origin, destination, items — and returns a ranked list of carrier quotes. By the end you’ll be able to:
- Submit a multi-item LTL rate request
- Read the response envelope and per-carrier quote shape
- Filter by service level, transit time, and accessorials
- Pick a winning quote ID to feed into Create a shipment
The full request
import { fc } from './freightcake'
const result = await fc.quotes.create({
origin: {
city: 'Chicago',
state: 'IL',
zip: '60601',
},
destination: {
city: 'Los Angeles',
state: 'CA',
zip: '90001',
},
items: [
{
description: 'Pallet of widgets',
weight: 500, // lbs
freight_class: '70',
length: 48, // in
width: 40,
height: 48,
quantity: 1,
},
],
accessorials: {
destination_liftgate: true,
residential_delivery: true,
},
})
console.log(`${result.data.length} carriers quoted`)
for (const quote of result.data) {
console.log(
`${quote.carrier_name} — $${(quote.net_charge_cents / 100).toFixed(2)} — ${quote.delivery_estimate}`,
)
}Equivalent raw fetch
const res = await fetch('https://api.freightcake.com/api/v1/quotes', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.FREIGHTCAKE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
origin: { city: 'Chicago', state: 'IL', zip: '60601' },
destination: { city: 'Los Angeles', state: 'CA', zip: '90001' },
items: [
{
weight: 500,
freight_class: '70',
length: 48,
width: 40,
height: 48,
},
],
accessorials: {
destination_liftgate: true,
residential_delivery: true,
},
}),
})
if (!res.ok) {
throw new Error(`Quote failed: ${res.status} ${await res.text()}`)
}
const result = await res.json()Reading the response
A successful response is a list envelope of quote objects:
{
"object": "list",
"url": "/api/v1/quotes",
"data": [
{
"object": "quote",
"id": 1042,
"carrier_name": "Sandbox Freight Co",
"carrier_scac": "SBFC",
"service_level": "Standard LTL",
"net_charge_cents": 17500,
"delivery_estimate": "3-5 business days",
"transit_days": 3,
"expires_at": "2026-05-22T00:00:00.000Z"
}
],
"has_more": false
}Notable fields:
net_charge_centsis the quoted amount in cents and includes the carrier charges returned for the request.expires_atdefaults to 5 days after creation. Re-quote anything older than its expiration before booking.transit_dayscomes from the carrier transit estimate and excludes pickup day and weekends.
Picking a winner
The simplest strategy — cheapest landed cost — is one line:
const winner = result.data
.slice()
.sort((a, b) => a.net_charge_cents - b.net_charge_cents)[0]For production traffic, weight by carrier scorecard data:
const winner = result.data
.map((q) => ({
quote: q,
score:
q.net_charge_cents +
// Penalize slow transit by ~$10 per extra day.
(q.transit_days ?? 5) * 1000,
}))
.sort((a, b) => a.score - b.score)[0].quotePass winner.id straight into the next step.
Common gotchas
- Freight class is required for LTL. If you don’t know the class, use the freight class calculator before requesting rates.
- Residential addresses change the carrier list. A residential delivery
filters out carriers that only run commercial freight. Always set
residential_deliveryif applicable — surprise reclasses get expensive. - Quotes expire. Trying to book against an expired quote returns
quote_expired. Re-quote and book in one user session.
Next steps
- Create a shipment using the winning quote ID
- Subscribe to
quote.createdwebhooks to log every rate shop centrally