smart-dato / dhl-parcel-returns-sdk
Laravel SDK for the DHL Parcel DE Returns API
Package info
github.com/smart-dato/dhl-parcel-returns-sdk
pkg:composer/smart-dato/dhl-parcel-returns-sdk
Fund package maintenance!
Requires
- php: ^8.4
- illuminate/contracts: ^11.0||^12.0||^13.0
- saloonphp/saloon: ^4.0
- spatie/laravel-data: ^4.20
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^11.0.0||^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
README
A Laravel package for the DHL Parcel DE Returns API. Create return labels on demand and look up return receiver locations. Built on Saloon and Spatie Laravel Data.
Installation
composer require smart-dato/dhl-parcel-returns-sdk
Publish the config file:
php artisan vendor:publish --tag="dhl-parcel-returns-sdk-config"
Add your credentials to .env:
# OAuth2 (recommended — Basic Auth is deprecated by DHL): DHL_PARCEL_RETURNS_API_KEY=your-client-id DHL_PARCEL_RETURNS_CLIENT_SECRET=your-client-secret DHL_PARCEL_RETURNS_USERNAME=your-business-customer-username DHL_PARCEL_RETURNS_PASSWORD=your-business-customer-password # Or legacy API key only: # DHL_PARCEL_RETURNS_API_KEY=your-api-key # Or legacy Basic Auth: # DHL_PARCEL_RETURNS_USERNAME=your-username # DHL_PARCEL_RETURNS_PASSWORD=your-password # Enable sandbox for testing: # DHL_PARCEL_RETURNS_SANDBOX=true
OAuth2 mode is enabled automatically when DHL_PARCEL_RETURNS_CLIENT_SECRET is set
together with the API key, username and password. The SDK then exchanges the
credentials for a Bearer token against the DHL ROPC token endpoint and caches
the token in memory until it expires.
Usage
Create a return label
use SmartDato\DhlParcelReturns\Data\Orders\ContactAddressData; use SmartDato\DhlParcelReturns\Data\Orders\ReturnOrderData; use SmartDato\DhlParcelReturns\Data\Orders\ValueData; use SmartDato\DhlParcelReturns\Data\Orders\WeightData; use SmartDato\DhlParcelReturns\Enums\Currency; use SmartDato\DhlParcelReturns\Enums\LabelType; use SmartDato\DhlParcelReturns\Enums\WeightUom; use SmartDato\DhlParcelReturns\Facades\DhlParcelReturns; $confirmation = DhlParcelReturns::orders()->create( data: new ReturnOrderData( receiverId: 'deu', shipper: new ContactAddressData( name1: 'Max Mustermann', addressStreet: 'Charles-de-Gaulle Str.', addressHouse: '20', postalCode: '53113', city: 'Bonn', email: 'max@mustermann.de', ), customerReference: 'Order #12345', itemWeight: new WeightData(WeightUom::Kilograms, 1), itemValue: new ValueData(value: 10, currency: Currency::Eur), ), labelType: LabelType::Both, ); $confirmation->shipmentNo; // "999991587211" $confirmation->label->b64; // base64-encoded shipment label $confirmation->qrLabel?->b64; // base64-encoded QR label (when requested) $confirmation->qrLink; // deep link to import the QR code into the Post & DHL app $confirmation->routingCode; // "40327653113+99000933090010"
International returns with customs (CN23)
use SmartDato\DhlParcelReturns\Data\Orders\CommodityData; use SmartDato\DhlParcelReturns\Data\Orders\CustomsDetailsData; use SmartDato\DhlParcelReturns\Enums\CountryOfOrigin; $confirmation = DhlParcelReturns::orders()->create( data: new ReturnOrderData( receiverId: 'che', shipper: $shipper, itemWeight: new WeightData(WeightUom::Grams, 1200), itemValue: new ValueData(value: 1012.99), customsDetails: new CustomsDetailsData( items: [ new CommodityData( itemDescription: 'T-Shirt', packagedQuantity: 1, itemWeight: new WeightData(WeightUom::Grams, 500), itemValue: new ValueData(value: 1000), countryOfOrigin: CountryOfOrigin::FRA, hsCode: '61099090', ), ], ), ), );
Look up return locations
use SmartDato\DhlParcelReturns\Enums\Country; use SmartDato\DhlParcelReturns\Facades\DhlParcelReturns; $receivers = DhlParcelReturns::locations()->get( country: Country::Deu, postalCode: '53113', maxResult: 10, ); foreach ($receivers as $receiver) { $receiver->receiverId; $receiver->billingNumber; $receiver->receiverAddress->city; }
All filters are optional — call ->get() with no arguments to list every receiver
configured for your account.
API version (healthcheck)
$version = DhlParcelReturns::general()->version(); $version->version; // "v1.0.0" $version->env; // "production"
This endpoint requires no authentication.
Using without the Facade
You can create a DhlParcelReturns instance directly using DhlParcelReturns::make().
This is useful when you prefer not to use the facade, need different credentials per
request, or want to support multi-tenant setups:
use SmartDato\DhlParcelReturns\DhlParcelReturns; // With OAuth2 (recommended) $dhl = DhlParcelReturns::make([ 'api_key' => 'your-client-id', 'client_secret' => 'your-client-secret', 'username' => 'your-business-customer-username', 'password' => 'your-business-customer-password', 'sandbox' => true, ]); // Or with legacy API key $dhl = DhlParcelReturns::make([ 'api_key' => 'your-api-key', 'sandbox' => true, ]); $confirmation = $dhl->orders()->create($data);
You can also optionally pass a custom base_url if needed:
$dhl = DhlParcelReturns::make([ 'api_key' => 'your-api-key', 'base_url' => 'https://api-eu.dhl.com/parcel/de/shipping/returns/v1', ]);
Label types
| Enum | Returns |
|---|---|
LabelType::ShipmentLabel |
Shipment label only |
LabelType::QrLabel |
QR label only |
LabelType::Both |
Both documents (default) |
Error handling
Any non-2xx response throws a SmartDato\DhlParcelReturns\Exceptions\DhlParcelReturnsApiException.
It parses the DHL RFC 7807 error body, exposing the title/detail as the message and
the HTTP status as the code:
use SmartDato\DhlParcelReturns\Exceptions\DhlParcelReturnsApiException; try { DhlParcelReturns::orders()->create($data); } catch (DhlParcelReturnsApiException $e) { $e->getMessage(); // "Unprocessable: ..." $e->getCode(); // 422 $e->detail; // RFC 7807 detail $e->instance; // RFC 7807 instance URI }
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.