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,
pieces: 1,
packaging: 'pallet',
},
],
accessorials: ['liftgate_destination', 'residential_destination'],
})
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: ['liftgate_destination', 'residential_destination'],
}),
})
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": "/v1/quotes",
"data": [
{
"object": "quote",
"id": 1042,
"carrier_name": "Sandbox Freight Co",
"carrier_scac": "SBFC",
"service_level": "Standard LTL",
"net_charge_cents": 17500,
"fuel_surcharge_cents": 4200,
"accessorial_charges_cents": 8500,
"total_charge_cents": 30200,
"delivery_estimate": "3-5 business days",
"transit_days_min": 3,
"transit_days_max": 5,
"expires_at": "2026-05-22T00:00:00.000Z"
}
],
"has_more": false
}Notable fields:
total_charge_centsis the landed cost including fuel and accessorials. This is the number to compare across carriers —net_charge_centsalone is misleading.expires_atdefaults to ~24 hours. Re-quote anything older than its expiration before booking.transit_days_min/transit_days_maxcome from carrier published transit matrices; they exclude 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.total_charge_cents - b.total_charge_cents)[0]For production traffic, weight by carrier scorecard data:
const winner = result.data
.map((q) => ({
quote: q,
score:
q.total_charge_cents +
// Penalize slow transit by ~$10 per extra day.
(q.transit_days_max ?? 5) * 1000 +
// Penalize carriers below 95% on-time over the trailing 90 days.
(q.carrier_on_time_pct && q.carrier_on_time_pct < 0.95 ? 5000 : 0),
}))
.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 class lookup endpoint or
the SDK helper
fc.quotes.estimateClass({ density }). - Residential addresses change the carrier list. A residential delivery
filters out carriers that only run commercial freight. Always set
residential_destinationif 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