Australia Post for omnisense/omnibus: prices, shipments with their PDF labels, tracking and cancellations, through Australia Post's Shipping and Tracking API (HTTP basic authentication with the API key and password, the charge account in a header). The gateway calls:
| Operation | Request |
|---|---|
| rate | POST /shipping/v1/prices/items |
| ship | POST /shipping/v1/shipments, then POST /shipping/v1/labels and GET the label's URL |
| track | GET /shipping/v1/track?tracking_ids={number} |
| cancel | GET /shipping/v1/shipments?tracking_ids={number}, then DELETE /shipping/v1/shipments?shipment_ids={id} |
on https://digitalapi.auspost.com.au (live) or https://digitalapi.auspost.com.au/test (the test
environment, sandbox: true). Every call sends Account-Number and has a 20-second timeout.
Installation
composer require omnibus/auspost
Requires PHP 8.2, omnisense/omnibus (2.x) and symfony/http-client (6.4, 7 or 8); given no
HTTP client, the factory makes one with HttpClient::create(). In a Symfony application with
Omnibus\Bridge\Symfony\OmnibusBundle, the factory is registered as soon as the package is
installed.
Credentials
- An Australia Post business account with a charge account (10 digits).
- The Shipping and Tracking API at developers.auspost.com.au gives the API key and password (test credentials first).
Options
| Option | Type | Default | Required | |
|---|---|---|---|---|
api_key |
string | - | yes | the API key (basic authentication user) |
password |
string | - | yes | its password |
account_number |
string | - | yes | the charge account, sent as Account-Number |
sandbox |
bool | false |
no | true: the test environment |
rates |
list | - | no | prices from configuration instead of /prices/items (the rates option): with it, /prices/items is not called |
Shipment options (Shipment::$options):
| Option | Read by | Default | |
|---|---|---|---|
sender_state |
rate, ship | - | the sender's state (VIC, NSW...) |
recipient_state |
rate, ship | - | the recipient's state |
authority_to_leave |
ship | false |
the parcel may be left without a signature |
layout |
ship | A4-1pp |
the label sheet: A4-1pp, A4-4pp, THERMAL-LABEL-A6-1PP (always a PDF) |
label_group |
ship | by product | the label group: Parcel Post, Express Post, International... (for a contract product the table does not know) |
description |
ship | Merchandise |
the customs description, outside Australia |
classification |
ship | SOLD |
the customs classification type, outside Australia |
The address model has no state: it comes from the two options.
Capabilities
| Request | Supported |
|---|---|
Rating |
yes (/prices/items), or configured rates with rates |
Shipping |
yes |
Tracking |
yes |
Pickup |
no: parcel lockers and post offices are given as recipient addresses |
GetSlip |
yes: the label asked for again, through the tracking id's shipment |
Cancel |
yes, before the shipment is lodged |
Paperless |
no |
Behaviour
Addresses and parcels. A party is its name and business name (40 characters each), its
street lines, the city as suburb, the state option, postcode, country, phone and email. A parcel
is an item with its dimensions in centimetres (those given) and its weight in kilograms rounded to
two decimals (at least 0.1).
Products. The service is Australia Post's product id; labels come from
Omnibus\Auspost\Mapping::PRODUCTS when Australia Post gives no product type:
| Product id | Product |
|---|---|
PP |
Parcel Post (the default in Australia) |
EXP |
Express Post |
PTI8 |
International Standard (the default elsewhere) |
ECM8 |
International Express |
AIR8 |
International Economy Air |
Rate. POST /prices/items with both parties and the items, one per parcel. Australia Post
prices each item on its own: a product's rate is the sum of its prices over the parcels, and a
product that does not carry every parcel is left out. Each price: its product_id, its
product_type (else the table) as label, calculated_price (else calculated_price_ex_gst) in
AUD; days is null. Shipment::$service does not filter them. Rates come cheapest first;
toPickupPoint is false.
Ship. POST /shipments with one shipment: the reference (50 characters), tracking emails when
the recipient has an email, both parties, one item per parcel with the product
(Shipment::$service, else PP in Australia and PTI8 elsewhere), the parcel's reference
(else the shipment's), authority_to_leave, no partial delivery, and outside Australia the
customs contents (the description, quantity 1, the parcel's value or 1.00, its weight, the
sender's country as origin) and the classification. The tracking number is the first item's
article_id (else its consignment_id). Then POST /labels, waiting for the label's URL, PDF
format, the group International abroad, Express Post for an Express product (EXP, or one
the table names so), Parcel Post otherwise, or the label_group option for a contract product,
the layout, unbranded, no offsets; when the label is AVAILABLE, its URL is fetched into
content. The label's url is kept either way. When the label request fails, the booking still
succeeds without a label: slip() asks for it again. The format is application/pdf; trackingUrl is
https://auspost.com.au/mypost/track/#/details/<number>. A response without a shipment id or a
number is a CarrierException (Australia Post booked no shipment.).
Track. GET /track for the number; the locale is not sent. The events of the first trackable
item (else of the result): their date, description and location; no event code is kept. Events
are sorted oldest first. The status is read from the result's status (else the latest event's
description); each event's from its description, with these words tried in order:
| The text contains | TrackingStatus |
|---|---|
delivered |
DELIVERED |
on board, out for delivery, with driver |
OUT_FOR_DELIVERY |
awaiting collection, ready for pickup |
AVAILABLE_FOR_PICKUP |
return |
RETURNED |
unsuccessful, delayed, unable |
EXCEPTION |
created, sealed, pending |
PENDING |
transit, received, processed, initiated |
IN_TRANSIT |
| anything else | UNKNOWN |
Slip. The shipment is found by the tracking number (GET /shipments?tracking_ids=; none: a
CarrierException, Australia Post knows no shipment for <number>.), then POST /labels as when
shipping, the group from the shipment's first item's product and its destination, layout
A4-1pp: the label's url, and its content once AVAILABLE (no URL: Australia Post gave no label for <number>.).
Cancel. The shipment is found by the tracking number (GET /shipments?tracking_ids=); none
found gives false. Then DELETE /shipments?shipment_ids=<id>: true when it does not fail.
Australia Post deletes only shipments not yet lodged in an order.
Example
<?php
require __DIR__.'/vendor/autoload.php';
use Omnibus\Auspost\AuspostGatewayFactory;
use Omnibus\Model\Address;
use Omnibus\Model\Parcel;
use Omnibus\Model\Shipment;
use Symfony\Component\HttpClient\HttpClient;
$auspost = (new AuspostGatewayFactory(HttpClient::create()))->create([
'api_key' => getenv('AUSPOST_API_KEY'),
'password' => getenv('AUSPOST_PASSWORD'),
'account_number' => getenv('AUSPOST_ACCOUNT'),
'sandbox' => true,
]);
$shipment = new Shipment(
new Address('Glitch Art', ['1 Collins St'], '3000', 'Melbourne', 'AU', phone: '0391234567'),
new Address('Ada Lovelace', ['1 Macquarie St'], '2000', 'Sydney', 'AU', email: 'ada@example.org'),
[new Parcel(1500, 30, 20, 10, reference: 'BOX-1')],
service: 'PP',
reference: 'CMD-1042',
options: ['sender_state' => 'VIC', 'recipient_state' => 'NSW', 'authority_to_leave' => true, 'layout' => 'A4-1pp'],
);
foreach ($auspost->rate($shipment) as $rate) {
printf("%-4s %-14s %6.2f %s\n", $rate->service, $rate->label, $rate->amount / 100, $rate->currency);
}
$label = $auspost->ship($shipment);
if (null !== $label->content) {
file_put_contents($label->trackingNumber.'.pdf', $label->content);
}
echo $label->trackingNumber, ' ', $label->trackingUrl, "\n";
$tracking = $auspost->track($label->trackingNumber);
echo $tracking->status->value, ' ', $tracking->latest()?->location, "\n";
var_dump($auspost->cancel($label->trackingNumber));
In Symfony:
omnibus:
gateways:
auspost:
factory: auspost
options:
api_key: '%env(AUSPOST_API_KEY)%'
password: '%env(AUSPOST_PASSWORD)%'
account_number: '%env(AUSPOST_ACCOUNT)%'
sandbox: '%env(bool:AUSPOST_SANDBOX)%'
Errors
Every failure is an Omnibus\Exception\CarrierException whose carrier is auspost:
- an HTTP status of 400 or more, or an answer with
errors: the first error'smessage(elseerror_message, elseHTTP <status>), itscode(elseerror_code) incarrierCode; - a body that is neither JSON nor a document:
Australia Post answered HTTP <status> with a body that is not JSON.; a network error:Australia Post request failed: ...; Australia Post booked no shipment.when no shipment id or number comes back.
A failed label request after the shipment is created is not raised (above). A missing api_key,
password or account_number is an InvalidConfigException when the gateway is built; Pickup and
Paperless raise RequestNotSupportedException before any call.
No failure carries the API key and password: a network error's message has them masked as *** (the
key parameters of a URL too), its previous is a copy of the HTTP client's exception (the same class
and code), and no trace of the chain keeps its arguments, where the request's options stood (No
secret in a
failure).
Verified, and not
Tested offline: Tests/AuspostGatewayTest.php (prices cheapest first in AUD, the
Account-Number header, the recipient's state, the weight in kilograms; two parcels priced as
the sum of their prices, a product that carries only one of them left out; a shipment created with
product PP and tracking emails, its label requested by shipment id and fetched; tracking with its
location; the cancellation through the shipment id) and Tests/AuspostContractTest.php, the
family's conformance suite on recorded answers. The example above was run in the core's harness on
those recorded answers.
Not verified: the README says the package is built from Australia Post's published API documentation and was not yet run against the test environment; that needs the credentials above. Unchecked against a real account: the label groups by product.
Responsibility
An independent, unofficial client, not affiliated with Australia Post (the Australian Postal Corporation). Whoever runs it complies with Australia Post's terms (API Licence Terms of Use): see the README's Responsibility section.