Rating
One request quotes every eligible carrier on your account at once. The rates come back as one list in one shape, so a quote from Saia and a quote from XPO can be compared field for field.
How it works
-
Create a rating job
with
POST /rating/jobs. Describe the shipment once. The response is immediate: a job inPROCESSINGwith no rates yet. - Shipwell contacts every carrier in parallel , so a slow carrier never holds up a fast one.
-
Read rates as they arrive.
Each carrier's rates are saved the moment it answers, so
?include=ratesreturns the fast carriers' quotes while slower ones are still working. You never wait on the slowest carrier to show the first price. -
Poll the job
with
GET /rating/jobs/{rating_job_id}untilis_terminalistrue. -
Read the full set
with
?include=ratesonceis_terminalistrue. -
Book one
by passing its
idto dispatch asrate_id. FTL rates are the exception: you book them by tendering in the Shipwell app. See Full truckload (FTL) .
A job always finishes. Carrier attempts still waiting after about 30 minutes are closed as errored, so your polling loop has a known end even when a carrier never answers.
Endpoints
| Endpoint | What it does |
|---|---|
POST /rating/jobs |
Create a rating job. Returns 201 with the job in PROCESSING. |
GET /rating/jobs/{rating_job_id} |
Read the job. Add ?include=rates to expand its rates. |
GET /rating/jobs/{rating_job_id}/rates/{rate_id} |
Read one rate on its own. This is the URL in the rate's self_link. |
Create a rating job
modes accepts LTL, VLTL and FTL, alone or together. equipment is required: LTL and VLTL are quoted on a dry van, so send [{"equipment_type": "DRY_VAN"}]. FTL has its own equipment rules, covered in Full truckload (FTL). Leave out capacity_providers to quote every carrier eligible for your account, or list the ones you want by provider_code.
Example request
curl --request POST 'https://sandbox-api.shipwell.com/rating/jobs' \
--header 'Authorization: Token <user-token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 3c9e7a10-po-4417' \
--data-raw '{
"modes": ["LTL"],
"customer_reference_number": "PO-4417",
"equipment": [{"equipment_type": "DRY_VAN"}],
"stops": [
{
"sequence_number": 1,
"location": {"line_1": "515 Congress Ave", "locality": "Austin", "region": "TX", "postal_code": "78701", "country": "US"},
"contact": {"company_name": "Acme", "first_name": "Dock", "last_name": "Team", "phone": "+15125551234"},
"requested_window": {"earliest": "2026-12-01T14:00:00Z", "latest": "2026-12-01T22:00:00Z"}
},
{
"sequence_number": 2,
"location": {"line_1": "4340 Directors Row", "locality": "Houston", "region": "TX", "postal_code": "77092", "country": "US"},
"contact": {"company_name": "Beta Receiving", "first_name": "Receiving", "last_name": "Desk", "phone": "+17135554500"}
}
],
"handling_units": [
{
"description": "Palletized boxes",
"quantity": 1,
"freight_class": "70",
"weight": {"value": 500, "unit": "LB", "qualifier": "PER_ITEM"},
"dimensions": {"measurement_type": "DIMENSIONS", "unit": "IN", "length": {"value": 48, "unit": "IN"}, "width": {"value": 40, "unit": "IN"}, "height": {"value": 50, "unit": "IN"}}
}
]
}'Example response (201)
{
"data": {
"id": "01HZKD8QKZQ8Z7XV9MKZ5QXW3H",
"resource_type": "rating_job",
"self_link": "https://sandbox-api.shipwell.com/rating/jobs/01HZKD8QKZQ8Z7XV9MKZ5QXW3H",
"status": "PROCESSING",
"is_terminal": false,
"created_at": "2026-08-19T15:30:32.591Z"
}
}What to send for usable quotes
The API only enforces what every carrier needs to accept a request. Individual carriers need more to return a price, so send a complete shipment:
| Field | Required by the API | Needed by most carriers |
|---|---|---|
modes |
Yes | |
stops (2 or more) |
Yes | |
stops[].location |
Yes | A full address: line_1, locality, region, postal_code, country. A bare postal code is accepted, but Saia, Peninsula and Pitt Ohio reject it. |
requested_window on the pickup stop |
Yes | |
stops[].contact |
No | Not needed to rate, but booking needs a pickup contact (company_name, first_name, phone) and a delivery contact (company_name, phone). Send both now and the booking needs only rate_id; otherwise send them when you dispatch. |
handling_units (1 or more), with weight |
Yes | |
equipment (1 or more) |
Yes | LTL and VLTL: DRY_VAN, because that freight moves in the carrier's standard enclosed dry van. FTL: exactly one of DRY_VAN, FLATBED or REEFER. See Full truckload (FTL). |
handling_units[].freight_class |
No | Saia, Peninsula and Duie Pyle reject the request without it. |
handling_units[].dimensions |
No | Saia requires it. |
total_linear_feet |
No | Required when modes includes VLTL. |
Tip
Send an Idempotency-Key header with a value unique to the shipment. If your request times out and you retry it with the same key and body, you get the original job back instead of quoting every carrier a second time. A retry while the first request is still being created answers 409.
Read the rates
Read the job with ?include=rates. While the job is still PROCESSING you get the rates collected so far; once is_terminal is true you get every carrier's answer. There is one entry per carrier attempt and service level.
Example request
curl --request GET 'https://sandbox-api.shipwell.com/rating/jobs/01HZKD8QKZQ8Z7XV9MKZ5QXW3H?include=rates' \
--header 'Authorization: Token <user-token>'Example response (200, abridged)
{
"data": {
"id": "01HZKD8QKZQ8Z7XV9MKZ5QXW3H",
"resource_type": "rating_job",
"status": "COMPLETED",
"is_terminal": true,
"rates": [
{
"id": "01HZKD9M4TQ4Z8XW0NKZ6RYX4J",
"resource_type": "rate",
"self_link": "https://sandbox-api.shipwell.com/rating/jobs/01HZKD8QKZQ8Z7XV9MKZ5QXW3H/rates/01HZKD9M4TQ4Z8XW0NKZ6RYX4J",
"provider_code": "ESTES",
"carrier_name": "Estes Express Lines",
"capacity_provider": {"account_id": "01KBZ91QKW3D9VDP5PVY4HWQ1G", "account_name": "Estes - Main"},
"transportation_mode": "LTL",
"charges": {
"total_charges": {"amount": 412.37, "currency": "USD"},
"charge_breakdown": [
{"charge_code": "BASE", "description": "Linehaul"},
{"charge_code": "FSC", "description": "Fuel surcharge"}
]
},
"transit_time": {"transit_days": 2},
"expiration_date": "2026-08-26T00:00:00Z",
"messages": []
},
{
"id": "01HZKD9M4TQ4Z8XW0NKZ6RYX4K",
"provider_code": "SAIA",
"carrier_name": "Saia",
"charges": null,
"messages": [
{"title": "Rate request failed", "detail": "Destination postal code is outside this carrier's service area."}
]
}
]
}
}-
A rate with
chargesis bookable. Pass itsidto dispatch asrate_id. An FTL rate (transportation_mode: "FTL") is booked by tendering in the Shipwell app instead. See Full truckload (FTL) . -
A rate with
charges: nullis a failed attempt. The carrier's reason is inmessages, in the carrier's own words. There's no separate success flag, because a rate with no price can't be booked. -
chargesis the carrier's own price, with no markup applied. See Carrier Rules & Markup .
Volume LTL
For shipments too large for standard LTL but short of a full truckload, include VLTL in modes and send total_linear_feet. The carriers that support it are marked in Supported Carriers.
Full truckload (FTL)
FTL quotes come from TQL (Total Quality Logistics). TQL is the only carrier quoting FTL through this API.
Note
FTL is available in production. It isn't in sandbox yet, where a request with FTL in modes is rejected with 400.
-
Ask for it in
modes. Send["FTL"]on its own, or alongsideLTLandVLTLto compare a truckload quote with LTL quotes in one job. Every rate carries the mode it was quoted for intransportation_mode. -
Choosing carriers.
Leave out
capacity_providersand FTL goes to TQL. If you name carriers,["FTL"]on its own may name onlyTQL, and FTL with other modes needsTQLamong the names. -
Equipment.
Send exactly one entry:
DRY_VAN,FLATBEDorREEFER.REEFERneeds atemperaturewith a finiteminimum,maximum, or both.FLATBEDandREEFERneedFTLon its own inmodes. -
No price is still an answer.
When TQL can't price a lane, its rate comes back with
charges: nulland TQL's reason inmessages, like any other carrier.
"modes": ["FTL"],
"equipment": [
{"equipment_type": "REEFER", "temperature": {"unit": "FAHRENHEIT", "minimum": 34, "maximum": 38}}
]Booking an FTL rate
An FTL rate from this API tells you TQL's price for the load. It can't be booked through this API: sending its id to POST /dispatching/jobs returns 400 with the code unsupported_transportation_mode.
FTL is booked by tendering by email in the Shipwell app, and the tender belongs to a shipment in the app. A rating job created through this API isn't linked to any app shipment, so its FTL rate can't be tendered as it is. To book the load:
- Create the shipment in the Shipwell app.
- Get its quotes there. TQL's FTL quote appears alongside the others.
- Select the TQL FTL quote and send the tender. TQL accepts or rejects it, and the shipment moves to Tendered once it's accepted.
Contact your Shipwell representative to turn FTL on for your account.
Rating statuses
See Statuses for what each rating job status means.
API reference
Rating API reference: every field, with request and response examples and code samples.
Next steps
Pick a rate and dispatch it.