TruckTabs API · v1
A quote is priced by the same engine as trucktabs.com. It works out the states on the route, adds oversize/overweight permits where the load is over a state's legal limits, and returns every fee.
POSThttps://trucktabs.com/api/v1/quotes
Needs a write key. Every quote becomes a draft order on our side, which is what lets the carrier pay from resume_url, so send an Idempotency-Key if you might retry.
| Field | Type | Required | Notes |
|---|---|---|---|
| permit_types | array | Yes | Any of trip, fuel, osow. Oversize/overweight is added by us in each state where the load needs it, so you rarely ask for it. |
| route.origin | place | Yes* | Where the trip starts. See Places below. |
| route.destination | place | Yes* | Where the trip ends. |
| route.states | array | Yes* | Instead of origin and destination: the states crossed, in order, each { "state": "OR", "miles": 210 }. Use it when your system already has the miles. The miles are yours: we price what you send, in whole miles (at least 1 a state). |
| route.stops | array | No | Not supported yet. A request with stops is refused with UNSUPPORTED rather than priced wrong. |
| vehicle.vehicle_type | code | Yes | For example tractor_trailer. See vehicle types. |
| vehicle.trailer_type | code | Semis | For example step_deck. See trailer types. |
| vehicle.trailer_length | measure | Semis | The trailer length. At least 10 ft. |
| vehicle.power_unit_axles | integer | Semis | Axles on the tractor or truck. |
| vehicle.trailer_axles | integer | Semis | Axles on the trailer. |
| vehicle.total_axles | integer | Single units | Every vehicle type other than tractor_trailer and truck_trailer. |
| vehicle.combined_length | measure | Single units | The vehicle's overall length. At least 10 ft. |
| load.gross_weight_lbs | integer | Yes | Gross weight in pounds, including the load. |
| load.length | measure | Sometimes | Length, width and height are required when the load could be oversize (for example an open trailer or an osow request). A missing one is listed in details.missing. |
| load.width | measure | Sometimes | Decides whether a state needs an oversize permit. |
| load.height | measure | Sometimes | Overall height from the road, at least 24 in. Legal height differs by state, so this can change the answer at a state line. |
| load.category | code | No | See load categories. |
| load.description | string | No | Up to 500 characters, for example "Excavator". |
| external_ref | string | No | Your own reference, up to 64 characters. Echoed back. |
| metadata | object | No | Up to 10 keys of 1 to 40 characters. Values are strings of up to 200 characters, numbers, booleans or null. Echoed back, never read by us. |
* Send route.origin and route.destination, or route.states, not both. A measure is { "value": 48, "unit": "ft" } with a unit of ft or in and at most 2 decimal places. A value far too big or too small for its field, such as a length over 500 feet or a 13-inch height, is refused as a likely unit slip. Codes also accept the display names and common aliases shown in the reference, in any case.
A place is an object in one of these forms. To choose between similar names before quoting, use GET /places.
| Field | Type | Required | Notes |
|---|---|---|---|
| city + state | string | No | { "city": "Portland", "state": "OR" }. Only a match in that state counts. Add postal_code to pick between places of the same name in that state. |
| postal_code | string | No | { "postal_code": "97201" }. Only a place with that ZIP code counts. If none has it, the quote is refused with PLACE_NOT_FOUND. |
| lat + lng + state | number | No | { "lat": 45.52, "lng": -122.68, "state": "OR" }. Used as given, once we have checked the point with Mapbox. Coordinates far outside the United States are refused with INVALID_INPUT. A point that isn't inside that state, or isn't in any US state, is refused with PLACE_MISMATCH. |
| query | string | No | { "query": "Portland, OR" }. Free text. A state code or ZIP code at the end narrows it. If it matches places in more than one state and nothing narrows it, the quote is refused with the candidates. |
curl https://trucktabs.com/api/v1/quotes \
-H "Authorization: Bearer $TRUCKTABS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d @quote.json{
"permit_types": ["trip", "fuel"],
"route": {
"origin": { "city": "Portland", "state": "OR", "postal_code": "97201" },
"destination": { "city": "Boise", "state": "ID" }
},
"vehicle": {
"vehicle_type": "tractor_trailer",
"trailer_type": "step_deck",
"trailer_length": { "value": 48, "unit": "ft" },
"power_unit_axles": 3,
"trailer_axles": 2
},
"load": {
"category": "construction_farm_equipment",
"gross_weight_lbs": 92000,
"length": { "value": 38, "unit": "ft" },
"width": { "value": 10, "unit": "ft" },
"height": { "value": 13, "unit": "ft" },
"description": "Excavator"
},
"external_ref": "LOAD-284113",
"metadata": { "shipment_id": "284113" }
}Amounts, descriptions and miles in these examples are illustrative, not current rates.
{
"id": "5b0f6c1e-8a7d-4c1e-9f3a-2d6b7c8e9f01",
"reference": "48213",
"status": "quoted",
"currency": "USD",
"subtotal": 424,
"processing_fee": 21.2,
"total": 445.2,
"states": [
{
"state": "OR",
"state_name": "Oregon",
"miles": 211,
"permits": ["trip", "fuel", "osow"],
"amount": 159,
"osow_auto_applied": true,
"osow_not_needed": false,
"lines": [
{ "kind": "state_fee", "permit": "trip", "description": "Oregon Trip Permit", "amount": 43 },
{ "kind": "state_fee", "permit": "fuel", "description": "Oregon Fuel Permit", "amount": 56 },
{ "kind": "state_fee", "permit": "osow", "description": "Oregon OS/OW Permit", "amount": 60 }
]
},
{
"state": "ID",
"state_name": "Idaho",
"miles": 219,
"permits": ["trip", "fuel", "osow"],
"amount": 105,
"osow_auto_applied": true,
"osow_not_needed": false,
"lines": [ … ]
}
],
"fees": [
{ "kind": "service_fee", "description": "TruckTabs service fee — OR, ID", "amount": 160 },
{ "kind": "processing_fee", "description": "Processing fee (5%)", "amount": 21.2 }
],
"oversize_notice": {
"title": "Oversize/overweight permits added",
"message": "This load is over the legal limits in Oregon and Idaho, so an OS/OW permit is included in each."
},
"advisories": [],
"route": {
"origin": { "label": "Portland, Oregon 97201", "city": "Portland", "state": "OR", "postal_code": "97201", "lat": 45.5152, "lng": -122.6784 },
"destination": { "label": "Boise, Idaho", "city": "Boise", "state": "ID", "postal_code": null, "lat": 43.615, "lng": -116.2023 },
"mileage_source": "route"
},
"repriced": false,
"external_ref": "LOAD-284113",
"metadata": { "shipment_id": "284113" },
"created_at": "2026-09-15T17:42:09.311Z",
"resume_url": "https://trucktabs.com/permits?resume=…"
}A quote our team must look at first comes back as needs_review. That happens for unusual dimensions, very large amounts, or a state we can't price automatically. It has no total, and every amount in the breakdown is null. The carrier can still open resume_url, and nothing is charged until the team confirms the price.
{
"id": "…",
"reference": "48214",
"status": "needs_review",
"currency": "USD",
"estimated_total": 1873.4,
"review_message": "Orders this size get a second look before we charge the card. Submit it and we'll confirm the total with you.",
"states": [
{
"state": "OR",
"amount": null,
"lines": [ { "kind": "state_fee", "permit": "osow", "description": "Oregon OS/OW Permit", "amount": null }, … ],
…
}
],
"fees": [ { "kind": "service_fee", "description": "TruckTabs service fee — OR, ID", "amount": null }, … ],
…
}A legal_load means you asked only for osow and the load is within every state's legal limits, so there is nothing to buy.
{
"id": "…",
"reference": "48215",
"status": "legal_load",
"currency": "USD",
"total": 0,
"states": [
{ "state": "OR", "permits": [], "amount": 0, "osow_not_needed": true, "lines": [], … }
],
"fees": [],
…
}| Field | Type | Required | Notes |
|---|---|---|---|
| id | string | Always | The quote id, for GET /quotes/{id}. |
| reference | string | Always | Our order number. Short enough for a charge description, and what our team will ask for. |
| status | string | Always | quoted, needs_review or legal_load. On a later read, also ordered or canceled. |
| currency | string | Always | USD. |
| subtotal | number | quoted | State permit fees and service fees. |
| processing_fee | number | quoted | Charged once per order. |
| total | number | quoted, legal_load | What the carrier pays. Never present on needs_review. 0 on legal_load. |
| estimated_total | number | needs_review | Present only when every state priced. An estimate: the team confirms the price before anything is charged. |
| review_message | string | needs_review | Why a person needs to look at it, in a sentence you can show the carrier. |
| states[] | array | Always | Per state: state, state_name, miles, permits, amount (its permit fees, the sum of its lines), osow_auto_applied, osow_not_needed and lines. |
| fees[] | array | Always | Order-level lines: service fees and the processing fee. The states' amounts plus these add up to total. |
| amounts on needs_review | No | Every amount in states, lines and fees is null, so nothing adds up to a price the team hasn't confirmed. | |
| oversize_notice | object | No | title and message when we added oversize/overweight permits you didn't ask for; otherwise null. |
| advisories[] | array | Always | Plain sentences worth showing the carrier. |
| route | object | Always | The places we priced, and mileage_source: route, straight_line (no drivable route was found; confirmed by hand) or provided (you sent route.states). |
| repriced | boolean | Always | false when created. On a later read, true if the carrier changed the trip since. See Get a quote. |
| resume_url | string | No | A link where the carrier reviews the quote, adds their details and pays. It works like a password to this order: give it only to the carrier. Null once the order is placed or canceled. |
| external_ref, metadata | No | What you sent. | |
| created_at | string | Always | ISO 8601, UTC. |
The response also has a Location header pointing at the quote.
| Status | Code | When |
|---|---|---|
| 422 | INVALID_INPUT | A value is wrong (details.invalid) or missing (details.missing). Both lists are complete. This includes a value too big or small for its field, which is usually a unit slip. |
| 422 | UNSUPPORTED | Something we don't quote yet, such as route.stops. |
| 422 | PLACE_AMBIGUOUS | A place matches more than one state. details.candidates lists them; send the one you mean with its state, or its lat, lng and state. |
| 422 | PLACE_NOT_FOUND | We couldn't find a place, or no place has the postal_code you sent. details.field says which. |
| 422 | PLACE_MISMATCH | Coordinates you sent aren't in the state you sent with them. details.field says which. |
| 422 | NO_STATES | The route doesn't cross any US state we permit. |
| 422 | INCOMPLETE | The quote couldn't be priced with what was sent. The message says what to add. |
| 409 | IDEMPOTENCY_MISMATCH | The Idempotency-Key already created a quote from a different body. |
| 409 | IDEMPOTENCY_IN_PROGRESS | The first request with this key is still running. Retry after a moment. |
| 429 | RATE_LIMITED | Too many writes or quotes this minute. Wait Retry-After seconds. |
| 429 | QUOTE_LIMIT_REACHED | Your daily allowance is used. Every quote that reaches pricing counts. It resets at midnight UTC. |
| 502 / 503 | ROUTING_FAILED, ROUTING_UNAVAILABLE | We couldn't look up places or miles. Retry, or send route.states with miles. |
| 500 / 503 | INTERNAL, QUOTE_FAILED, SAVE_FAILED, UNAVAILABLE | Our problem. Retry with the same Idempotency-Key and you get one quote back. A failure during pricing can leave an unfinished draft on our side, which counts toward the daily allowance. If it persists, send us the request_id. |
{
"error": {
"code": "PLACE_AMBIGUOUS",
"message": "The origin matches places in more than one state. Add the state.",
"details": {
"field": "route.origin",
"candidates": [
{ "label": "Portland, Oregon", "city": "Portland", "state": "OR", "postal_code": null, "lat": 45.5152, "lng": -122.6784 },
{ "label": "Portland, Maine", "city": "Portland", "state": "ME", "postal_code": null, "lat": 43.6591, "lng": -70.2568 }
]
}
},
"request_id": "req_Qm3v8Kx1Tn5bW2pL9sR4"
}GEThttps://trucktabs.com/api/v1/quotes/{id}
Returns a quote your account created, in the same shape as when it was created, with status brought up to date. Nothing is priced again. A quote that belongs to another account is 404 NOT_FOUND.
ordered: the carrier completed the order, or our team took it on. ordered_at is set and resume_url is null.canceled: the order was canceled. canceled_at is set and resume_url is null.resume_url.The carrier can change the trip after opening resume_url, and our team can take an order over. If either moved the price or put the order on hold, repriced is true. The per-state breakdown is still the one you were quoted, with every amount set to null. total is the order's current price, and it is left out while the order is held for review.
curl https://trucktabs.com/api/v1/quotes/5b0f6c1e-8a7d-4c1e-9f3a-2d6b7c8e9f01 \
-H "Authorization: Bearer $TRUCKTABS_API_KEY"