POSTXPOSTX/Developer Docs
v1
Public REST API โ€” v1

POSTX Shipping API

Programmatically create and manage next-day pallet and parcel consignments, retrieve shipping labels, and track deliveries in real time. This document covers next-day services only โ€” same-day is on the roadmap, see .

๐Ÿš€

Quick to integrate

A single POST creates a consignment and returns a print-ready shipping label in seconds.

๐Ÿ”’

Bearer token secured

Most endpoints require a JWT bearer token. Public tracking is the exception.

๐Ÿ“ฆ

Pallets & Parcels

Support for national and local next-day pallets, parcels, ADR (dangerous goods), and oversized loads.

Base URL

All API requests are made to the following base URL. Resource paths shown throughout this document (for example /consignments) are relative to it.

Base URL
https://api.postx.ai/v1/shipping

Quickstart

Three steps to make your first consignment booking.

  1. 1

    Get your credentials

    Contact POSTX to receive your Client ID and Client Secret. Keep these private โ€” they grant full API access to your account.

  2. 2

    Obtain an access token

    Exchange your credentials for a JWT token using the token endpoint below.

  3. 3

    Create your first consignment

    Use the token in the Authorization header to POST a consignment. You will receive a reference ID and a Base64 shipping label.


Authentication

The POSTX API uses a Basic credential exchange. You Base64-encode your Client ID and Client Secret and pass them as a Basic Authorization header; the response is a JWT access token, which you then pass on every subsequent request as a Bearer token.

โ„น๏ธThis is not a full RFC 6749 OAuth 2.0 client credentials flow โ€” there is no grant_type parameter and no form-encoded body. Off-the-shelf OAuth 2.0 libraries will not work against it without a custom adapter.

1 โ€” Get an Access Token

POST
/oauth/token

Exchange client credentials for a JWT access token.

Encode your clientId:clientSecret in Base64 and pass it as a Basic Authorization header:

bash
curl -X POST https://api.postx.ai/v1/shipping/oauth/token \
  -H "Authorization: Basic $(echo -n 'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET' | base64)" \
  -H "Content-Type: application/json"

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 86400
}

expires_in is in seconds. 86400 seconds = 24 hours โ€” access tokens are valid for 24 hours.

2 โ€” Use the Token

Include the token in every subsequent API request:

bash
curl -X POST https://api.postx.ai/v1/shipping/consignments \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
โš ๏ธTokens expire after 24 hours. Your integration should detect a 401 Unauthorized response and re-authenticate automatically.

Consignments

A consignment is a complete shipping job โ€” it includes pickup location, delivery location, timing, and one or more physical items (shipments). Upon creation, you receive a unique reference ID and a printable shipping label.

โ„น๏ธPaths below are relative to the base URL: https://api.postx.ai/v1/shipping.
POST
/consignments

Create a new consignment and receive a shipping label.

PUT
/consignments/:reference

Update an existing consignment (cancels original, creates new).

DELETE
/consignments/:reference

Cancel a consignment. A cancellation charge may apply.

GET
/consignments/capacity

Check available delivery capacity for a given date.

GET
/tracking/:reference

Get a live tracking URL for a consignment. Public โ€” no auth required.


Create Consignment

POST
/consignments

Create a new consignment. Returns a reference ID and a Base64-encoded PDF label.

Request body

FieldTypeDescription
collectionDateTimerequireddatetimeWhen to collect from the sender. Must not be in the past. See the note below the table for the expected format.
collectionAddressrequiredAddressFull pickup address including postcode.
collectionContactrequiredContactName, email, phone, and company of the sender.
collectionInstructionsstringOptional instructions for the driver at pickup.
collectionServiceTyperequiredenumCollection service type. See Service Types section.
collectionServicePricerequirednumberPrice charged for the collection leg (in pence).
deliveryDateTimerequireddatetimeWhen to deliver to the recipient. Must be after collectionDateTime.
deliveryAddressrequiredAddressFull delivery address including postcode.
deliveryContactrequiredContactName, email, phone, and company of the recipient.
deliveryInstructionsstringOptional instructions for the driver at delivery.
deliveryServiceTyperequiredenumDelivery service type window. See Service Types section.
deliveryServicePricerequirednumberPrice charged for the delivery leg (in pence).
shipmentsrequiredShipment[]Array of one or more items in this consignment. At least one is required.
carrierstringOptional carrier override. Defaults to POSTX.
โ„น๏ธcollectionDateTime and deliveryDateTime are Europe/London local time, e.g. 2026-09-01T09:00:00. Whether an explicit UTC offset is also accepted has not been confirmed โ€” send naive local time as shown in the examples until POSTX confirms otherwise.
โš ๏ธThere are no universal weekday or noon cut-off rules. Permitted booking days and cut-off times are set per account at contract and vary between customers. Book any time within your agreed windows โ€” check your contract, or once available, see .

Address object

FieldTypeDescription
addressLine1requiredstringFirst line of the address.
addressLine2stringSecond line (optional).
townrequiredstringTown or city.
countryrequiredstringFull country name, e.g. "United Kingdom".
countryCoderequiredstringLiteral "UK" is expected here. This is not the ISO 3166-1 alpha-2 code (which is "GB") โ€” send "UK" exactly as shown in the examples.
postcoderequiredstringUK postcode. Used to geocode the address.

Shipment object

FieldTypeDescription
referencerequiredstring | numberYour internal reference for this item.
productrequiredProductTypeThe product SKU. See Products section.
quantityrequiredintegerNumber of units.
weightPerProductrequirednumberWeight per unit in kilograms.
descriptionrequiredstringDescription of the goods.
adrrequiredbooleanTrue if the shipment contains dangerous goods (ADR). See the callout below.
valuePerProductrequirednumberDeclared value per unit in pence. Whether this drives insurance cover, a liability cap, or is informational only has not been confirmed โ€” contact dev@postx.ai before relying on it.
pricePerProductrequirednumberPrice per unit in pence, multiplied by quantity to get the line total. See Pricing.
overweightPricePerProductrequirednumberOverweight surcharge per unit in pence, multiplied by quantity. 0 if not applicable.
heightPerProductrequirednumberHeight per unit in metres.
widthPerProductrequirednumberWidth per unit in metres.
lengthPerProductrequirednumberLength per unit in metres.
โš ๏ธDangerous goods (adr: true) โ€” what happens next, whether pre-approval is required, and what UN number, class or packing group paperwork is needed outside the API has not been confirmed. Contact dev@postx.ai before booking ADR shipments.

Pricing

Price is determined by two things: the rate card attached to your account, and the service type you book. The rate card determines which service types are available to your account; the service type determines the price. All amounts on this page are in pence, GBP, net of VAT.

Four price fields are sent on every request: pricePerProduct and overweightPricePerProduct per shipment, plus collectionServicePrice and deliveryServicePrice at the consignment level.

Two pricing modes exist, and they can be mixed within a single consignment:

  • POSTX rate card โ€” leave the line for POSTX to price from your agreed rate card. A price you send as a POSTX-rated line is checked against the rate card and corrected if it does not match.
  • Customer external price โ€” send your own hard-coded price for external comparison. This is recorded as given and is not corrected.
โš ๏ธThe API does not yet expose which mode a price line is in, or return a priced breakdown showing any correction POSTX made. Both are on the roadmap โ€” see .

Worked example โ€” a two-unit line at 7500 pence per unit, plus service leg prices:

text
pricePerProduct:            7500   (pence, per unit)
quantity:                       2
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Line total:                 15000   (7500 ร— 2)

+ collectionServicePrice:     500
+ deliveryServicePrice:       800
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Consignment total:          16300   (pence, net of VAT)

Example request

json
{
  "collectionDateTime": "2026-09-01T09:00:00",
  "collectionAddress": {
    "addressLine1": "10 Industrial Park",
    "addressLine2": "Unit 4",
    "town": "Birmingham",
    "country": "United Kingdom",
    "countryCode": "UK",
    "postcode": "B1 1AA"
  },
  "collectionContact": {
    "name": "Jane Smith",
    "email": "jane@acme.com",
    "contactNumber": "07700900000",
    "company": "Acme Ltd"
  },
  "collectionInstructions": "Ring bell on arrival",
  "collectionServiceType": "PALLET_NEXT_DAY_COLLECTION_STANDARD_ETA",
  "collectionServicePrice": 500,
  "deliveryDateTime": "2026-09-02T10:00:00",
  "deliveryAddress": {
    "addressLine1": "5 High Street",
    "addressLine2": "",
    "town": "London",
    "country": "United Kingdom",
    "countryCode": "UK",
    "postcode": "EC1A 1BB"
  },
  "deliveryContact": {
    "name": "John Doe",
    "email": "john@recipient.com",
    "contactNumber": "07700911111",
    "company": "Recipient Co"
  },
  "deliveryInstructions": "Pump truck required",
  "deliveryServiceType": "PALLET_NEXT_DAY_DELIVERY_AM",
  "deliveryServicePrice": 800,
  "shipments": [
    {
      "reference": 1032964,
      "product": "PALLET_NEXT_DAY_NATIONAL",
      "quantity": 2,
      "weightPerProduct": 221,
      "description": "Industrial equipment",
      "adr": false,
      "valuePerProduct": 350000,
      "pricePerProduct": 7500,
      "overweightPricePerProduct": 0,
      "heightPerProduct": 1.2,
      "widthPerProduct": 1.0,
      "lengthPerProduct": 1.0
    }
  ]
}

Response

json
{
  "id": "AB12-XY34",
  "label": "JVBERi0xLjMKJeLjz9MKNSAwIG9iagol..."
}
โ„น๏ธThe label field is a Base64-encoded multi-page PDF. Decode it to get a print-ready shipping label โ€” one page per item in your shipment.
โš ๏ธPersist the Base64 label on receipt. There is currently no endpoint to retrieve it later โ€” see .

Update Consignment

PUT
/consignments/:reference

Update a consignment. The original is cancelled and a new one is created with the updated details.

The request body is identical to . The original consignment is automatically cancelled (no cancellation charge is applied) and a new consignment is created. A new shipping label is returned.

โš ๏ธYou cannot update a consignment that has already been routed to a driver (409 Conflict) or already cancelled (409 Conflict).
โš ๏ธPUT returns a new reference and a new label โ€” the original reference is no longer valid. Any label already printed against the original reference must be destroyed and reprinted using the new one. Tracking the old reference afterwards will show it as cancelled.

Response

json
{
  "id": "CD34-ZA56",
  "label": "JVBERi0xLjMKJeLjz9MKNSAwIG9iagol..."
}

Cancel Consignment

DELETE
/consignments/:reference

Cancel a consignment by its reference ID. A cancellation charge may apply.

Pass the consignment reference in the URL path:

bash
curl -X DELETE https://api.postx.ai/v1/shipping/consignments/AB12-XY34 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
โš ๏ธA cancellation charge may apply. The window runs 24 hours from the collection date. The charge itself is set per contract โ€” check your agreement for the exact amount.

Response

json
{
  "cancelled": "2026-09-01T08:45:00.000Z",
  "status": "CANCELLED"
}

Tracking

GET
/tracking/:reference

Retrieve a live tracking URL for a consignment. No authentication required.

This endpoint is publicly accessible โ€” no auth token is required. It returns a tracking URL that can be shared directly with recipients.

bash
curl https://api.postx.ai/v1/shipping/tracking/AB12-XY34

Response

json
{
  "trackingUrl": "https://tracking.kosmo.delivery/tracking/KSM-ABC123"
}
โ„น๏ธIf no tracking URL is available yet (driver not yet dispatched), trackingUrl will be null. This is the documented, expected case.
โš ๏ธWhat an unknown or invalid reference returns, and rate limiting for this public endpoint, are not yet documented. Treat both as unconfirmed until POSTX publishes them โ€” see .

Capacity

GET
/consignments/capacity

Check if delivery capacity is available for a given date and item type.

Query parameters

ParamTypeDescription
daterequiredISO 8601Delivery date to check. E.g. "2026-09-02".
typerequiredenum"pallets" or "parcels".
bash
curl "https://api.postx.ai/v1/shipping/consignments/capacity?date=2026-09-02&type=pallets" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response

json
{
  "data": [
    { "slot": "AM", "available": 12, "total": 20 },
    { "slot": "PM", "available": 3,  "total": 20 }
  ]
}
โš ๏ธCapacity is reported at AM/PM granularity only. Timed delivery windows (0800_0900, 0900_1000, 1000_1100, CUSTOM_ETA) are not capacity-checked before booking.

Service Types

Service types control the collection and delivery time windows. All values below are next-day. Same-day service types do not exist yet โ€” see .

Collection service types

PALLET_NEXT_DAY_COLLECTION_STANDARD_ETAStandard pallet collection ETA.
PARCEL_NEXT_DAY_COLLECTION_STANDARD_ETAStandard parcel collection ETA.

Delivery service types

PALLET_NEXT_DAY_DELIVERY_STANDARD_ETAStandard pallet delivery.
PALLET_NEXT_DAY_DELIVERY_AMPallet delivery in the AM window.
PALLET_NEXT_DAY_DELIVERY_PMPallet delivery in the PM window.
PALLET_NEXT_DAY_DELIVERY_0800_0900Pallet delivery between 08:00โ€“09:00.
PALLET_NEXT_DAY_DELIVERY_0900_1000Pallet delivery between 09:00โ€“10:00.
PALLET_NEXT_DAY_DELIVERY_1000_1100Pallet delivery between 10:00โ€“11:00.
PALLET_NEXT_DAY_DELIVERY_CUSTOM_ETACustom delivery ETA (pallet).
PARCEL_NEXT_DAY_DELIVERY_STANDARD_ETAStandard parcel delivery.
PARCEL_NEXT_DAY_DELIVERY_AMParcel delivery in the AM window.
PARCEL_NEXT_DAY_DELIVERY_PMParcel delivery in the PM window.

Products & Pallets

The product field on each shipment specifies the type of item being transported. Weight brackets for parcels are automatically resolved server-side. Next-day products only โ€” same-day products do not exist yet, see .

ProductCategoryNotes
PALLET_NEXT_DAY_NATIONALPalletNational next-day pallet delivery.
PALLET_NEXT_DAY_LOCALPalletLocal next-day pallet delivery.
PALLET_NEXT_DAY_OVERSIZEPalletOversize pallet (non-standard dimensions).
PALLET_NEXT_DAY_RAIL_BUNDLEPalletRail bundle pallet.
PARCEL_NEXT_DAY_NATIONALParcelNational next-day parcel. Weight bracket resolved automatically.
PARCEL_NEXT_DAY_LOCALParcelLocal next-day parcel. Weight bracket resolved automatically.

Pricing

Price is determined by the rate card and the service type. The rate card sets which service types are available to your account; the service type sets the price. See the full explanation, field breakdown and worked example in .

๐Ÿ’ท

Amounts are pence, GBP, net of VAT

Every price field on this API โ€” product, overweight surcharge, and both service legs โ€” is an integer number of pence, exclusive of VAT.

๐Ÿ”€

POSTX-rated and external prices can mix

One consignment can contain some lines rated from your POSTX rate card and some lines carrying your own external price for comparison โ€” the two are not mutually exclusive.

โœ…

A POSTX-rated price is corrected on mismatch

A price sent as a POSTX rate is checked against your account rate card and corrected if it does not match. An external comparison price is accepted as given and never corrected.


Business Rules

The API enforces the following rules on every consignment:

โžก๏ธ

Collection before delivery

collectionDateTime must be strictly before deliveryDateTime.

๐Ÿ“ฆ

At least one shipment required

Every consignment must include at least one shipment in the shipments array.

๐Ÿ—“๏ธ

Booking days and cut-off times are per account

Permitted booking days, cut-off times, and the cancellation window are set per account at contract, not globally. There are no fixed weekday or noon cut-off rules that apply to every account โ€” check your contract, or once available, GET /rate-cards (see Coming soon).


Error Reference

All errors follow a consistent JSON structure:

json
{
  "statusCode": 400,
  "message": "collectionDateTime must not be in the past.",
  "error": "Bad Request"
}
โ„น๏ธmessage is currently free text โ€” there is no stable, machine-readable error code yet (planned, see ). Do not string-match on the exact sentence beyond what is published below.
HTTP CodeMeaningCommon Causes
400Bad Request
  • collectionDateTime must not be in the past.
  • deliveryDateTime must be after collectionDateTime.
  • shipments must contain at least 1 element.
  • No capacity available for the requested date and product.
  • A booking-day or cut-off violation, worded against your account's configured values โ€” the exact message is not yet published for every rule.
401UnauthorizedMissing or expired JWT token. Re-authenticate to get a new token.
409ConflictConsignment already routed to a driver, or already cancelled.
500Server ErrorUnexpected error. Retry with exponential backoff โ€” note there is currently no idempotency key, so a retried create can double-book. See .

Coming Soon

None of the items below exist in the API today. They are listed here โ€” not left as a silent gap โ€” so integrators can plan around them instead of assuming the API is unfinished or hunting for something that has not been built yet.

F1

GET /consignments/:reference

Returns status, cancellation charge flag, priced breakdown and label. State reconciliation, billing verification and label recovery โ€” the highest-value item in this list after the rate card.

F2

POST /rate

The create payload without commitment, returning the same priced breakdown. Lets you price a job for your own end customer before booking it.

F3

Signed webhooks

collected, in transit, delivered, failed and cancelled events. Today the only status channel is the human-facing tracking URL.

F4

Label reprint, plus ZPL output

Labels are currently PDF only, delivered once on create, with no recovery path if lost.

F5

GET /consignments (list)

Pagination and filtering. There is currently no way to list or search your consignments at all.

F6

Self-serve sandbox

Test credentials without a commercial conversation first. Evaluation currently requires talking to POSTX before a single call can be made.

F7

GET /rate-cards

Your rate cards โ€” the service types each covers, the products it prices, cut-off times, permitted booking days and cancellation terms. The rate card is the root object of this API and today has no representation in it. Most of the per-account behaviour referenced elsewhere on this page traces back to that one gap.

Same-day

Same-day is not yet implemented as a service type, despite appearing on older versions of this page. When it ships, it will be booked by service type (not a separate product SKU) and the SAME_DAY collection and delivery enum values will mirror the next-day ones shown in โ€” the only differences will be price, and collection and delivery falling on the same day.

POSTX Developer Documentation ยท v1 ยท dev@postx.ai

ยฉ 2026 POSTX. All rights reserved.