Tracking
Two ways to follow a shipment: poll the tracking endpoint, or let the
platform push status changes to your endpoint. Push is the better
default — no polling loops, updates arrive as they happen.
The two channels use different status vocabularies — see Polling statuses and Webhook statuses. Don't share one status mapping between them.
Polling — the tracking endpoint
Query by the carrier waybill number (returned by order_send):
Code
Each event carries both a normalized status (consistent across carriers) and the carrier's original status. Build your logic on the normalized one; show the original to support staff. Events are returned newest first.
Without the SDK: POST tracking/<waybill_number>/ — see the
API v2 reference.
Polling statuses
| Status | Meaning |
|---|---|
NEW | Order created, the parcel is not with the carrier yet |
PICKUP | Posted / picked up by the courier |
IN_TRANSIT | On the way — includes out for delivery and waiting at a pickup point |
DELIVERED | Delivered |
DELIVERED_NO_SYSTEM | Delivered, confirmed outside the carrier's system |
EXCEPTION | Something needs attention — failed delivery attempt, notice left, unrecognized carrier status |
RETURNED_TO_SHIPPER | Returned to the sender (including parcels not collected in time) |
CANCELLED | Cancelled |
CORRECTION | Complaint / correction case — shown as cancelled in the panel |
UNKNOWN | Status could not be determined |
Push tracking webhooks
Tell the platform where to send status changes, in one of two ways:
- Per order — send
push_tracking_urlwith the order. With the SDK:OrderRequest::create()->...->setPushTrackingUrl('https://example.com/apaczka/tracking'). - Per WebAPI app — set a default tracking webhook URL in the WebAPI
settings of the customer panel. It applies to every order created with
that app's credentials; a per-order
push_tracking_urltakes precedence.
The platform then POSTs a signed JSON notification to that URL on every
status change. The notification is signed with the app_id / app_secret
of the WebAPI app that created the order — always verify the signature
before processing
(why). With the
SDK:
Code
Payload
Code
orderNumber— the Apaczka orderid(as returned byorder_send), not the waybill number. Use it to match the notification to your order.statuses[].status— the normalized status, see Webhook statuses.statuses[].trackingOperatorStatuses— the carrier's original events behind that status (status,description,place,updatedAt).
Verifying the signature without the SDK
The signature is HMAC-SHA256 over {app_id}::{json}: — the same scheme as
request signing, with the route and expiry left
empty — where {json} is the response object re-encoded with unescaped
unicode, slashes and line terminators:
Code
The encoding flags matter: without them, Polish characters and slashes are escaped differently and the signature never matches.
Webhook statuses
Webhooks use their own status set. The right-hand column is the closest polling status.
| Webhook status | Meaning | Polling equivalent |
|---|---|---|
NEW | Order registered | NEW |
READY_TO_SEND | Ready to be sent | NEW |
ADVISING | — | NEW |
POSTED | Posted / handed over to the carrier | PICKUP |
ON_THE_WAY | On the way to the recipient | IN_TRANSIT |
OUT_FOR_DELIVERY | Handed to the courier for delivery | IN_TRANSIT |
READY_TO_PICKUP | Ready for collection at a pickup point | IN_TRANSIT |
DELIVERED | Delivered | DELIVERED |
WAITING_FOR_PAYOUT | Delivered, cash on delivery awaiting payout | DELIVERED |
SENT | Cash on delivery paid out | DELIVERED |
AVIZO | Delivery notice left (awizo) | EXCEPTION |
REMINDER_SENT | Reminder sent to the recipient | EXCEPTION |
OTHER | Carrier status not recognized | EXCEPTION |
UNKNOWN | Status unknown | EXCEPTION |
PICKUP_EXPIRED | Not collected in time | RETURNED_TO_SHIPPER |
RETURNED | Returned to the sender | RETURNED_TO_SHIPPER |
CANCELED | Cancelled | CANCELLED |
CLAIMED | Complaint filed | CORRECTION |
Watch the spelling: the webhook sends CANCELED (one L), polling returns
CANCELLED. And SENT means a COD payout, not that the parcel was sent.
Things to know
- Respond with HTTP 200. Until your endpoint returns 200 the platform keeps redelivering the notification; after a 200 the next one arrives with the next status change. Make your handler idempotent.
- Push tracking is registered only for supported carriers;
statusesmay be an empty array — acknowledge it with 200 and move on. - Timestamps are
Y-m-d\TH:i:swithout an offset, in Europe/Warsaw time.

