How to Auto-Fulfill Orders with DHL Express

Automatically create DHL Express shipments when new orders come in.

What This Integration Does

DHL Express is the go-to carrier for international e-commerce because of its global network and predictable service levels. The flipside is its API: a SOAP-ish XML schema with strict required fields and a customs-content section that scares off most no-code tools. Letting a workflow build the payload from your store's order schema removes that friction and means every paid order gets a label without anyone touching a UI.

This workflow listens on a store webhook, transforms order data into the DHL shape (including HS codes and customs values for international shipments), creates the shipment, and writes the resulting waybill number back to the order so customer-facing tracking just works. It's carrier-specific by design - if you ever need multi-carrier rate shopping, layer SmartFreight or Shippit on top instead.

Prerequisites

  • A store connection (Shopify, BigCommerce, or WooCommerce) with order read and update access.
  • A DHL Express connection with your account number and an API user (XML Services or MyDHL API).
  • HS commodity codes on products being shipped internationally.
  • A pickup address and default shipper details registered against the DHL account.

Step 1: Webhook Trigger

Drop a Trigger node and set type to Webhook. Register the webhook against your store's order-paid event. Paying customers shouldn't wait for fulfillment, and unpaid orders shouldn't burn DHL credits.

Step 2: Transform - Map to DHL Shape

Add a Transform node. DHL requires shipper, recipient, parcel, and (for international) customs blocks:

{
  "shipper":   { "name": "Acme Pty", "city": "Sydney", "country_code": "AU", ... },
  "recipient": {
    "name":    "{{ trigger.body.shipping_address.name }}",
    "address": "{{ trigger.body.shipping_address.address1 }}",
    "city":    "{{ trigger.body.shipping_address.city }}",
    "country_code": "{{ trigger.body.shipping_address.country_code }}",
    "postcode":     "{{ trigger.body.shipping_address.zip }}"
  },
  "packages": [{ "weight_kg": 1.2, "length_cm": 30, "width_cm": 20, "height_cm": 10 }],
  "customs":  { "invoice_value": "{{ trigger.body.total_price }}", "currency": "AUD" }
}

Use a Condition node to skip the customs block when shipping domestically.

Step 3: Rate the Shipment (Optional)

If you charge customers the actual shipping cost rather than a flat rate, add a Connector node pointing at dhl-express with get-rates before creating the shipment. Use the cheapest service that meets your delivery promise, or default to a configured service code (e.g. "P" for Express Worldwide).

Step 4: Create the DHL Shipment

Add a Connector node on dhl-express and pick create-shipment. Pass the transformed payload plus the chosen service code. The response includes a tracking (waybill) number and a base64-encoded label PDF.

Step 5: Update the Order with Tracking

Add a Connector node on your store and write the DHL tracking number back to the order: Shopify update-order (with a fulfillment record), WooCommerce update-order, or BigCommerce raw-api-request to create a shipment. This is what gives the customer a tracking link in their account.

Step 6: Notify Warehouse and Customer

Use a Send Email node to email the label PDF to your warehouse inbox, or push it into a label-printer queue. Optionally fan out (Parallel node) to a slack send-message step into #fulfillment with the order summary and tracking link.

Tips

  • Cache DHL service codes per destination country - rate lookups are slow and rarely change.
  • For high volume, batch a daily pickup with create-pickup rather than scheduling per-shipment.
  • Store the label PDF in a long-term bucket; DHL only retains them for a short window.
  • Run a separate daily workflow that calls track-shipment on open shipments to update the store with in-transit / delivered status.

Common Pitfalls

  • Missing HS codes: international shipments without HS codes will be rejected at submission. Validate up front and route problem orders to a review queue.
  • Address format: DHL is strict on city names and postcodes. Australian postcodes need to be 4 digits including leading zeros - keep them as strings.
  • Service availability: not every DHL service runs to every country. get-rates returns only the services actually available; don't hardcode a service code without a fallback.
  • Customs value currency: must match the invoice currency on the commercial invoice. Mismatches cause customs holds, not API errors.

Testing

Run the workflow manually with a single test order to a known domestic address first to confirm the basic shape works without customs. Then test an international order to a country you frequently ship to. Confirm the waybill prints, the label scans at the depot, and the tracking number is visible on the customer's order page before enabling the production webhook.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.