Skip to content

Validate a route

Check a shipment against each courier’s rules before you quote, for example to warn a user that a heavy carton rules out some couriers or needs a tail lift.

POST /api/v5/locations/validate-route

Requires your API key in the api-key header. Send the body as JSON with Content-Type: application/json. It does not quote, price or create a booking.

This is a quick rules check, not a quote. It covers a fixed set of couriers and applies the same carton weight limits and runtime enforcement mode as quoting. It does not apply your account’s settings or every other quote restriction. A courier with can_quote: true can still be left out of a quote, so treat quote_errors as the final answer.

FieldTypeRequiredDescription
fromobjectNoPickup location. See Location fields.
toobjectNoDelivery location. See Location fields.
itemsarrayNoThe items. See Item fields.
couriersstring[]NoOnly check these courier ids. Leave it out to check every courier in the list below.
FieldTypeDescription
postcodestringFour-digit postcode.
suburbstringSuburb name.
statestringState code, for example NSW.
countrystringTwo-letter country code. Defaults to AU.
typestringbusiness or residential. Defaults to business.
isResidentialbooleanOverrides type when supplied: true means residential and false means business. String values "true", "false", "1", "0" and numeric 1/0 are also accepted.
FieldTypeDescription
descriptionstringPackage type, for example Carton or Pallet. Defaults to Carton.
packagingstringOptional. Used as the package type when description is sent empty.
weightnumberWeight of one package in kilograms.
length, width, heightnumberDimensions of one package in centimetres.
quantityintegerNumber of identical packages. Defaults to 1.

Unknown fields in a location or item are rejected with 400.

allied, couriers_please, fastway, aramex, xpress, domestic_freight_express, northline, team_global_express, team_global_express_priority, team_global_express_specialised, toll, tnt_road_express, sampson_express, hunter_road_freight, hunter_economy_road, parca, parca_plus_metro and go_people. Ids you send in couriers that are not in this list are ignored.

Terminal window
curl -X POST https://api.transdirect.com.au/api/v5/locations/validate-route \
-H "api-key: $TD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": { "postcode": "2000", "suburb": "SYDNEY", "state": "NSW", "type": "business" },
"to": { "postcode": "3000", "suburb": "MELBOURNE", "state": "VIC", "type": "residential" },
"items": [
{ "description": "Carton", "weight": 32, "length": 60, "width": 40, "height": 40, "quantity": 1 }
],
"couriers": ["allied", "couriers_please", "tnt_road_express"]
}'
import { client, postApiV5LocationsValidateRoute } from '@transdirect/api-sdk';
client.setConfig({ headers: { 'api-key': process.env.TD_API_KEY! } });
const { data, error } = await postApiV5LocationsValidateRoute({
body: {
from: { postcode: '2000', suburb: 'SYDNEY', state: 'NSW', type: 'business' },
to: { postcode: '3000', suburb: 'MELBOURNE', state: 'VIC', type: 'residential' },
items: [{ description: 'Carton', weight: 32, length: 60, width: 40, height: 40, quantity: 1 }],
couriers: ['allied', 'couriers_please', 'tnt_road_express'],
},
});
if (!data) throw new Error(JSON.stringify(error));
const blocked = Object.entries(data.couriers).filter(([, result]) => !result.can_quote);

200 OK. A 32 kg carton going to a home address with carton limits in enforce mode:

{
"couriers": {
"allied": {
"rules": [
{
"code": "tailgate.threshold",
"severity": "surcharge",
"msg": "Tailgate may be required (heaviest item 32kg).",
"surcharge_amount": 75,
"meta": { "total_weight": 32, "heaviest_item_weight": 32, "threshold_kg": 25 }
}
],
"can_quote": true
},
"couriers_please": {
"rules": [
{
"code": "items.dead_weight_limit",
"severity": "block",
"msg": "Item dead weight must be under 26kg.",
"meta": { "max": 26 }
},
{
"code": "tailgate.unsupported",
"severity": "prompt",
"msg": "This courier does not offer tailgate / tail lift service.",
"meta": { "total_weight": 32 }
}
],
"can_quote": false
},
"tnt_road_express": {
"rules": [
{
"code": "tailgate.threshold",
"severity": "surcharge",
"msg": "Tailgate may be required (heaviest item 32kg).",
"surcharge_amount": 52.8,
"meta": { "total_weight": 32, "heaviest_item_weight": 32, "threshold_kg": 25 }
},
{
"code": "items.not_serviced",
"severity": "block",
"msg": "Carton exceeds this courier's carton weight limit. Send it as a pallet, skid or crate to get a quote.",
"meta": {}
}
],
"can_quote": false
}
}
}
FieldTypeDescription
couriersobjectOne entry per courier checked, keyed by courier id.
couriers.*.can_quotebooleanfalse when any rule has severity: "block".
couriers.*.rulesarrayThe rules that apply. Empty when nothing applies.
rules[].codestringA machine-readable rule code, for example items.dead_weight_limit or tailgate.threshold.
rules[].severitystringblock (this courier cannot carry it), surcharge (an extra charge may apply) or prompt (something to tell the user).
rules[].msgstringA sentence you can show the user.
rules[].surcharge_amountnumberThe likely extra charge in AUD, on surcharge rules.
rules[].metaobjectDetails such as the limit that was broken.

TNT reports can_quote: false because the 32 kg carton exceeds its residential carton limit. Carton removals use items.not_serviced; Pallet, Skid and Crate items are exempt. Modes hold_only and off disable mode-dependent removals, while courier limits enforced in every mode still apply. A real quote remains the final serviceability check.

StatusBodyCause
400{"success":false,"error":{"name":"ZodError","message":"..."}}The body does not match the schema, for example an unknown field in from or an item.
401{"error":"missing_api_key"} or {"error":"invalid_api_key"}No key, or a key that is not active.
429{"error":"rate_limited"}More than 600 requests a minute on this key. Wait for the retry-after seconds.

Open the API Explorer, paste your API key into the authentication box, and find Validate a route and evaluate courier rules.