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-routeRequires 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.
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
from | object | No | Pickup location. See Location fields. |
to | object | No | Delivery location. See Location fields. |
items | array | No | The items. See Item fields. |
couriers | string[] | No | Only check these courier ids. Leave it out to check every courier in the list below. |
Location fields
Section titled “Location fields”| Field | Type | Description |
|---|---|---|
postcode | string | Four-digit postcode. |
suburb | string | Suburb name. |
state | string | State code, for example NSW. |
country | string | Two-letter country code. Defaults to AU. |
type | string | business or residential. Defaults to business. |
isResidential | boolean | Overrides type when supplied: true means residential and false means business. String values "true", "false", "1", "0" and numeric 1/0 are also accepted. |
Item fields
Section titled “Item fields”| Field | Type | Description |
|---|---|---|
description | string | Package type, for example Carton or Pallet. Defaults to Carton. |
packaging | string | Optional. Used as the package type when description is sent empty. |
weight | number | Weight of one package in kilograms. |
length, width, height | number | Dimensions of one package in centimetres. |
quantity | integer | Number of identical packages. Defaults to 1. |
Unknown fields in a location or item are rejected with 400.
Couriers checked
Section titled “Couriers checked”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.
Example request
Section titled “Example request”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);Response
Section titled “Response”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 } }}| Field | Type | Description |
|---|---|---|
couriers | object | One entry per courier checked, keyed by courier id. |
couriers.*.can_quote | boolean | false when any rule has severity: "block". |
couriers.*.rules | array | The rules that apply. Empty when nothing applies. |
rules[].code | string | A machine-readable rule code, for example items.dead_weight_limit or tailgate.threshold. |
rules[].severity | string | block (this courier cannot carry it), surcharge (an extra charge may apply) or prompt (something to tell the user). |
rules[].msg | string | A sentence you can show the user. |
rules[].surcharge_amount | number | The likely extra charge in AUD, on surcharge rules. |
rules[].meta | object | Details 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.
Errors
Section titled “Errors”| Status | Body | Cause |
|---|---|---|
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. |
Try it
Section titled “Try it”Open the API Explorer, paste your API key into the authentication box, and find Validate a route and evaluate courier rules.