DHL Paket API Migration: SOAP v3 to REST V2

A step-by-step runbook for migrating DHL Parcel DE Shipping integrations from retired SOAP v3 to REST V2, with OAuth2 setup and field mapping.

DHL Paket API Migration: SOAP v3 to REST V2

Why This Migration Can't Wait

If you run multi-tenant DHL connectivity for European shippers, some of your tenants may have been silently failing since 1 June 2026. DHL confirmed that the legacy version 3 of the SOAP Business Customer Shipping API would no longer be supported as of May 31, 2026, after which no shipments can be created and no shipping labels can be generated via that interface. The production DNS cutover followed shortly after: the DNS switch for the production environment (api-eu.dhl.com) was scheduled between 22-29 June 2026.

This is the DHL Parcel DE Shipping API migration every German-adjacent shipping platform has been putting off. If you're reading this in mid-August, you're not early. You're either mid-cutover, or you have tenants whose shipment creation has been quietly broken for weeks and nobody noticed because the failure mode doesn't always look like an outage. It looks like a support ticket from one shipper saying "labels stopped printing," while the other 999 tenants on your platform are fine.

This runbook assumes you operate a multi-tenant carrier middleware platform, not a single shop integration. That changes the shape of the problem: you're not migrating one set of credentials, you're migrating N tenants, each with their own DHL Business Customer Portal account, their own product mix, and possibly their own customs edge cases.

What You Need Before Starting

Five things, gathered per tenant, before you touch a line of integration code.

  • Business Customer Portal credentials per tenant. These don't disappear under OAuth2 — they become the "user" half of a two-level authentication model. The user is identified via HTTP Basic Authentication with credentials configured in the DHL Business Customer Portal, passed to the SDK via an authentication storage interface.
  • A registered application in the DHL API Developer Portal. This gets you the application-level identity. The DHL Parcel DE Shipping API requires a two-level authentication where the application submits a Consumer Key Header ("API Key") that must be created in the DHL API Developer Portal.
  • Sandbox access against api-sandbox.dhl.com, using DHL's published sandbox test credentials, before any tenant goes near production.
  • A per-tenant inventory of legacy product codes and fields, specifically anything still requesting Warenpost, and any customs payloads where currency fields might not line up.
  • A rollback plan that assumes you'll need it, not one you write after something breaks.

One thing that trips people up: the DHL Parcel DE Shipping API and the DHL Parcel DE Returns API are separate products with separate migration timelines, and if you use a software solution to order shipments you need to contact the manufacturer to switch to a new version before the end-of-life date at the end of May 2026 for returns too. Don't assume fixing shipping fixes returns.

Step-by-Step Migration

This is the sequence we'd run across a tenant base of any meaningful size. Each step assumes the previous one is verified, not just "probably done."

  1. Register an application in the DHL Developer Portal and generate your API key. This key is shared across all tenants on your platform — it identifies your application, not any individual shipper. Every request to the DHL Parcel DE Shipping V2 API needs this key in the dhl-api-key header regardless of which tenant is shipping.
  2. Exchange each tenant's Business Customer Portal credentials for an OAuth2 access token. The auth service uses an implementation of OAuth2 Password Grant (RFC 6749), with all URIs relative to https://api-sandbox.dhl.com/parcel/de/account/auth/ropc/v1 in sandbox (swap to the production host once verified). Don't build this as a one-off script — treat it as a per-tenant credential exchange your platform re-runs whenever a token expires. The endpoint obtains an access token based on the credentials submitted or based on the refresh token, so cache the refresh path, not just the initial exchange.
  3. Store the resulting opaque token per tenant and attach it as a Bearer token alongside the dhl-api-key header on every call. After successful usage you'll have an opaque access token to be used for API calls afterwards, and this token will have an expiration time. Build token refresh into your adapter layer now, not as a follow-up ticket — expired tokens under load are exactly the kind of thing that turns into a 2am page.
  4. Stop sending Basic Auth. It still works for now in some V2 deployments, but DHL has been explicit: DHL will no longer offer Basic Auth in future API versions, and it is strongly recommended to use OAuth2. If your adapter still defaults to Basic Auth as a fallback path, remove it. A fallback that silently degrades security posture isn't a fallback, it's a liability you haven't found yet.
  5. Replace Warenpost with DHL Kleinpaket in every tenant's product configuration. DHL introduced the replacement product over a year before the SOAP shutdown: on 01.01.2025 the new product DHL Kleinpaket was introduced, replacing the previous product Warenpost. Until now, DHL has been quietly protecting you from this: a warning message appears when the old product "Warenpost" is automatically corrected to the new product "DHL Kleinpaket." Don't rely on that auto-correction surviving indefinitely — grep every tenant's saved shipment templates for the old code and fix it at the source.
  6. Enforce currency-matching on customs payloads before you submit, not after DHL rejects the request. This is the trip point nobody expects, because it never bit anyone on SOAP the same way. For a parcel to a country subject to customs duties, the currency of the postal charges and the currency of all item positions must match, as these values are added together for customs clearance. Add this as a pre-flight validation rule in your shipment builder for every tenant shipping outside the EU customs union. A rejected request here means no label, full stop — there's no partial success to recover from.
  7. Use the validation switch before you burn a real order. The validation switch available for POST /orders will tell you if you are missing required elements, mistyped an attribute name, and more. Wire this into your CI pipeline per tenant template so schema drift gets caught before a shipper's warehouse floor does.
  8. Run every tenant's shipment templates against sandbox before flipping anyone to production. Sandbox uses the same two-level model as production, just against api-sandbox.dhl.com. Confirm each tenant can complete a full order-and-label round trip, and check the response for warnings, not just errors — in some cases the web service response may include a warning message in addition to the shipping label, for example when the label format is adjusted automatically. A 200 with a buried warning is still a signal worth logging.
  9. Cut tenants over incrementally, one cohort at a time, behind a feature flag. Keep the dormant SOAP client wired for the shortest possible rollback window — DHL's SOAP v3 shutdown is real and dated, so this isn't a permanent safety net, just insurance for the first 48 hours of each cohort's cutover.

How You Know It Worked

Verification is not "the demo call returned 200." For a multi-tenant platform, success means every tenant independently proves three things.

CheckWhat "pass" looks likeWhat "fail" looks like
AuthenticationToken exchange returns a valid Bearer token with no 401/403 on first /orders callIntermittent 401s, or tenant still configured for Basic Auth
Product codesZero Warenpost (V62WP) codes in outbound payloads across all tenant templatesAuto-correction warning appears in the response, meaning the old code is still being sent
Customs shipmentsCurrency of postal charges matches currency of item positions on every cross-border test orderOrder rejected outright, no label generated

Run this checklist per tenant, not once across the platform. A pattern we've seen repeatedly in multi-tenant migrations: the first ten tenants pass clean because they're the simple domestic-only accounts your team tested against. Tenant eleven is the one shipping DDP to Switzerland with a customs template nobody's touched in two years, and that's where the currency mismatch shows up.

Failure Mode: Silent 401s From Basic Auth Deprecation

The pattern: a tenant's shipment creation looks fine for weeks after cutover, then starts throwing intermittent 401s with no code change on your side. The cause is almost always that the tenant's adapter config never actually switched off Basic Auth — it kept working because DHL hadn't finished phasing out the old auth path for that account tier, and then it stopped.

DHL has stated it will no longer offer Basic Auth in future API versions. That's not a gradual degradation you can retry your way out of. It's an authentication-layer failure, not a transient network blip, and treating it like one wastes an on-call engineer's night. If your circuit breaker sees a 401 storm on a carrier adapter, don't back off and retry — page a human. Idempotency keys protect you against duplicate labels on a retried request; they do nothing for a request that was never going to succeed because the credential type is wrong.

The fix is structural, not reactive: treat auth-mode as a per-tenant configuration flag with an explicit value (basic or oauth2), run a synthetic monitor against the token endpoint hourly per tenant, and alert on any tenant still resolving to basic after your cutover date. If you can't answer "which auth mode is tenant 247 using right now" without grepping logs, you don't have observability on this migration, you have hope.

Rolling This Into a Carrier Abstraction Layer

This entire runbook exists because DHL changed its transport protocol, its auth model, and one of its product codes in the same migration window, and every platform integrating directly against DHL's API had to absorb that churn tenant by tenant. That's exactly the argument for not integrating directly against a single carrier's API surface at all.

A carrier abstraction layer means your internal shipment schema — the envelope your platform actually operates on — doesn't know or care whether DHL is speaking SOAP or REST underneath. When DHL retires an API version, you update one adapter behind the abstraction, not every tenant-facing integration point. Multi-carrier platforms like Cargoson, alongside nShift, Sendcloud, and ShipEngine, exist precisely to absorb this kind of SOAP-to-REST churn behind a stable internal contract, so their customers don't run this exact runbook themselves every time a carrier reworks its API.

The engineering takeaway, whether you build this abstraction yourself or buy it: version your internal envelope independently of any single carrier's API version. DHL will change again. So will DPD, GLS, and every other carrier on your routing table. The question isn't whether the next migration happens — it's whether your architecture makes it a one-adapter change or another all-hands scramble against a hard deadline.