DHL does not have an official Acumatica connector, so a tracking integration means calling DHL's own APIs — the MyDHL API for shipment creation and label generation, or the DHL Shipment Tracking API for status updates — from a PXGraphExtension on the Sales Orders (SO301000) or Shipments (SO302000) screens. The shape of the integration is the same regardless of carrier: capture a tracking number when the shipment is confirmed, poll or webhook for status, and reflect that status back onto the shipment or order without making every screen load wait on an external HTTP call.
Where the tracking number lives
Acumatica's Shipments screen already has a native WayBillNbr field intended for exactly this — DHL's tracking number goes there, not into a new custom field, so existing shipment-tracking UI and reports pick it up for free. Where a customization is actually needed is the code that populates it: an override on shipment confirmation that calls DHL's API to register the shipment and get back a tracking number, or, more commonly, a nightly or on-demand job that reads tracking numbers already assigned by a warehouse system and writes them into Acumatica via the contract-based REST API.
public class SOShipmentEntry_DHLExt : PXGraphExtension
{
[PXOverride]
public virtual void ConfirmShipment(SOShipment shipment,
Action baseMethod)
{
baseMethod(shipment);
if (string.IsNullOrEmpty(shipment.WayBillNbr))
{
var dhlResult = DHLTrackingService.RegisterShipment(shipment);
var row = Base.Document.Current;
row.WayBillNbr = dhlResult.TrackingNumber;
row.ShipVia = "DHL";
Base.Document.Update(row);
}
}
}
Polling vs. webhooks for status updates
DHL's tracking API supports both a pull model (query by tracking number) and, for enterprise accounts, webhook push notifications on status change. A scheduled processing screen (built on PXProcessing) that polls open shipments every 15-30 minutes is simpler to build and debug than a webhook receiver, and is the right default unless shipment volume is high enough that polling every open shipment becomes its own performance problem. Webhooks avoid the polling overhead but require a publicly reachable endpoint and its own authentication and retry handling — worth it past a few hundred shipments a day, overkill below that.
DHL's APIs are rate-limited per account. A poll job that queries every open shipment on every run, rather than only shipments that haven't reached a terminal status ("Delivered", "Exception"), will burn through your rate limit as shipment volume grows and start silently failing to update anything. Filter the poll query to non-terminal shipments only, and back off with exponential retry on a 429 response.
Mapping DHL's status codes to something Acumatica users understand
DHL's tracking events use their own status vocabulary (`PU`, `SC`, `AR`, `WC`, `OK` in the older XML API, more descriptive strings in the MyDHL API), which is meaningless to a warehouse or customer service user looking at the shipment screen. The integration should translate DHL's raw status into a small, stable set of values on a Usr-prefixed field — "In Transit," "Out for Delivery," "Delivered," "Exception" — so the UI stays comprehensible even if DHL changes their underlying event vocabulary between API versions.
Surfacing status without building a portal
Many implementations stop at internal visibility, but the field that unlocks self-service is exposing the tracking number and status through whatever customer-facing surface already exists — a Customer Portal screen, an emailed shipment confirmation with a DHL tracking link, or a business event that fires a notification when status changes to "Delivered." Because the tracking number and status live on native or Usr fields, any of these downstream consumers can read them without knowing anything about DHL's API.
What happens when DHL's API is down
A carrier integration will see intermittent failures — that's the nature of calling a third-party API on a schedule. The processing screen should log failures per shipment rather than aborting the whole batch, and retry only the failed shipments on the next run instead of re-querying everything. Shipment confirmation itself should never block on the DHL call succeeding; register the shipment locally first, then treat tracking-number assignment as an asynchronous follow-up so a DHL outage doesn't stop your warehouse from shipping.
Wrapping up
None of this requires a marketplace connector — a scheduled processing screen, a Usr-prefixed status field, and a translation layer between DHL's vocabulary and something a warehouse user recognizes covers the real integration. The parts that separate a fragile version from one that survives a busy shipping season are rate-limit-aware polling, per-shipment failure isolation, and never letting shipment confirmation block on an external API call.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.