How to Create DHL Express Shipments from Adobe Commerce (Magento 2) Orders
Ship Adobe Commerce (Magento 2) orders with DHL Express without a shipping extension: create the DHL shipment and label through the MyDHL API, save the label, and add the tracking number to the Magento shipment so the customer is notified.
What This Integration Does
Most Magento 2 DHL setups rely on an extension that has to match your Magento version and checkout. This Spojit workflow connects the two over their APIs instead. When an order is ready to ship, it builds a MyDHL API shipment request from the order's shipping address, weight and value, sends it with the DHL Express connector, saves the returned PDF label to your File Store (or prints it from there), and creates the shipment in Magento with the DHL waybill number as tracking. Magento then emails the customer their tracking details.
The workflow runs on a schedule over orders in processing status and creates the Magento shipment as its last step, which moves the order out of processing. An order is therefore shipped once; if the DHL call fails, nothing is written to Magento and the order is picked up again on the next run.
Prerequisites
- A DHL Express connection in Spojit with your MyDHL API credentials and DHL Express account number. Use DHL's test environment while you build.
- An Adobe Commerce REST connection with access to Sales (orders, shipments).
- Product weights in Magento, in the unit your store is configured for (kilograms for metric).
- Your shipper details (company, address, phone) and the DHL product code you use, such as
Pfor Express Worldwide orNfor Domestic Express.
Step 1: Schedule Trigger
Add a Trigger node with type Schedule, for example */20 8-16 * * 1-5 (every 20 minutes during warehouse hours on weekdays).
Step 2: Find Orders Ready to Ship
Add an Adobe Commerce REST step with list-orders, status processing, pageSize 50. Name the output orders. Add a Loop in ForEach mode over the orders (the list is under the output's data.items), with On iteration error set to Continue with the next item. Inside, add a Condition on the order's shipping method if only some orders go by DHL (for example {{ item.shipping_description }} contains DHL).
Step 3: Build the MyDHL Shipment Request
Add a Code Runner step with execute-javascript and input {{ item }}. It reads the shipping address and adds up the weight:
const o = data;
const a = o.extension_attributes.shipping_assignments[0].shipping.address;
const weight = o.items.filter(i => !i.parent_item_id)
.reduce((w, i) => w + (i.weight || 0) * i.qty_ordered, 0);
return {
plannedShippingDateAndTime: new Date().toISOString().slice(0, 19) + " GMT+00:00",
pickup: { isRequested: false },
productCode: a.country_id === "AU" ? "N" : "P",
accounts: [{ typeCode: "shipper", number: "YOUR_DHL_ACCOUNT" }],
customerDetails: {
shipperDetails: {
postalAddress: { postalCode: "2000", cityName: "Sydney", countryCode: "AU", addressLine1: "1 Example Street" },
contactInformation: { phone: "+61200000000", companyName: "Acme Pty Ltd", fullName: "Dispatch" }
},
receiverDetails: {
postalAddress: { postalCode: a.postcode, cityName: a.city, countryCode: a.country_id, addressLine1: a.street[0], addressLine2: a.street[1] },
contactInformation: { phone: a.telephone, companyName: a.company || (a.firstname + " " + a.lastname), fullName: a.firstname + " " + a.lastname, email: o.customer_email }
}
},
content: {
packages: [{ weight: Math.max(0.1, Math.round(weight * 100) / 100), dimensions: { length: 30, width: 20, height: 15 } }],
isCustomsDeclarable: a.country_id !== "AU",
declaredValue: o.subtotal,
declaredValueCurrency: o.order_currency_code,
description: "Order " + o.increment_id,
incoterm: "DAP",
unitOfMeasurement: "metric"
}
};
Name the output dhl_request; the request is in {{ dhl_request.result }}. Replace the shipper details, account number and default box size with yours. International shipments that are customs declarable also need line item details for the commercial invoice; add them under content.exportDeclaration following DHL's ShipmentRequest schema.
Step 4: Create the DHL Shipment
Add a DHL Express step with create-shipment and payload {{ dhl_request.result }}. Name it shipment. Like the other connectors, the DHL step wraps DHL's reply as { success, data }, so DHL's fields are under {{ shipment.data }}. DHL returns shipmentTrackingNumber (the waybill), trackingUrl, and documents, where the entry with typeCode label holds the label as Base64 PDF in content.
Step 5: Save the Label
Add a File Store node with Save a file: name dhl-label-{{ item.increment_id }}.pdf, content {{ shipment.data.documents.0.content }}, content type application/pdf. The warehouse prints labels from the File Store. To send it to a person instead, attach it to an email with Resend send-email.
Step 6: Create the Magento Shipment with Tracking
Add an Adobe Commerce REST step with create-shipment:
orderId:{{ item.entity_id }}- Tracking:
track_number{{ shipment.data.shipmentTrackingNumber }},titleDHL Express,carrier_codecustom notify:true, so Magento sends the customer its shipment email with the tracking number.
Leaving the items out ships all items on the order. Creating the shipment moves the order to complete (if it is invoiced) so the next run does not pick it up again.
Tips
- Quote before you ship: call
get-rateswith the same addresses and weight first if you need to choose between DHL products or check the cost on large orders. - Pickups: book one daily pickup with
create-pickupfrom a separate scheduled workflow instead of requesting a pickup on every shipment. - Box sizes: DHL charges on the greater of actual and volumetric weight. Store a box size per product (a Magento attribute) and pass real dimensions to avoid billing surprises.
- Track and notify: pair this with a tracking workflow that calls
track-shipmentand alerts you about exceptions.
Common Pitfalls
- Missing phone numbers: DHL requires a receiver phone number. Make the telephone field required at checkout, or fill a default and flag the order.
- Street lines: Magento stores the street as an array; send the first line as
addressLine1and the second, if any, asaddressLine2. Long lines over DHL's character limits are rejected. - Weight units: if your store uses pounds, convert to kilograms (or send
unitOfMeasurementimperialwith dimensions in inches). - Test versus production: labels from DHL's test environment are not valid for shipping. Switch the connection to production credentials before go-live.
Testing
With the DHL connection on the test environment, place a test order in a Magento staging store and run the workflow manually. Check that the label PDF opens from the File Store, the Magento order has a shipment with the waybill number, and the shipment email reached your test address. Then switch to production credentials.