PHPackages                             smart-dato/dpd-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. smart-dato/dpd-sdk

ActiveLibrary[API Development](/categories/api)

smart-dato/dpd-sdk
==================

A Laravel package for integrating with the DPD shipping service API.

0.0.7(3mo ago)0735↓48.3%[2 PRs](https://github.com/smart-dato/dpd-sdk/pulls)MITPHPPHP ^8.4CI passing

Since Nov 25Pushed 3mo agoCompare

[ Source](https://github.com/smart-dato/dpd-sdk)[ Packagist](https://packagist.org/packages/smart-dato/dpd-sdk)[ Docs](https://github.com/smart-dato/dpd-sdk)[ GitHub Sponsors](https://github.com/SmartDato)[ RSS](/packages/smart-dato-dpd-sdk/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (14)Versions (9)Used By (0)

DPD SDK for Laravel
===================

[](#dpd-sdk-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/067843f2e7a03794dd5825e17e9904f230565a6a61406e599abc2652b00bb936/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736d6172742d6461746f2f6470642d73646b2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/smart-dato/dpd-sdk)[![GitHub Tests Action Status](https://camo.githubusercontent.com/b301f2e6135e4916d29cb8ebf9463a7ce03f161a76ebcb05dfd8a58fc7948e52/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f736d6172742d6461746f2f6470642d73646b2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/smart-dato/dpd-sdk/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/493a410a9f61eb21213292faf1cbe6661ceed5de51cd82481894f23e4a63a9e9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f736d6172742d6461746f2f6470642d73646b2f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/smart-dato/dpd-sdk/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/28d0d114fa135985836343bcc26d0bebd49dbc39a37dff1486251c1d01b7c4c1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f736d6172742d6461746f2f6470642d73646b2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/smart-dato/dpd-sdk)

A Laravel package for integrating with DPD's SOAP API. Create shipments, generate labels, and track parcels with a fluent, Laravel-style interface.

Features
--------

[](#features)

- 🚀 **Fluent API** - Laravel-style builders for creating shipments
- 🔐 **Automatic Authentication** - Token management with 24-hour caching
- 🌍 **Multi-Environment** - Support for both staging and production endpoints
- 🏢 **Multi-Tenant Ready** - Runtime configuration override for different accounts
- 📦 **Full SOAP Support** - LoginService, ShipmentService, and ParcelLifeCycleService
- ✅ **Type-Safe** - Modern PHP 8.4 with readonly DTOs and enums
- 🧪 **Well Tested** - Comprehensive test suite with Pest PHP

Requirements
------------

[](#requirements)

- PHP 8.4 or higher
- Laravel 11.0 or 12.0
- ext-soap PHP extension

Installation
------------

[](#installation)

Install the package via composer:

```
composer require smart-dato/dpd-sdk
```

Publish the config file:

```
php artisan vendor:publish --tag="dpd-sdk-config"
```

Add your DPD credentials to your `.env` file:

```
DPD_ENVIRONMENT=staging
DPD_DELIS_ID=your_delis_id
DPD_PASSWORD=your_password
DPD_CACHE_STORE=redis
```

Usage
-----

[](#usage)

### Creating a Shipment (Facade)

[](#creating-a-shipment-facade)

Use the facade for simple, application-wide configuration:

```
use SmartDato\Dpd\Facades\Dpd;

$shipment = Dpd::shipment()
    ->sendingDepot('0000')
    ->sender(fn($sender) => $sender
        ->name('John Doe')
        ->company('Acme Corp')
        ->street('Main Street')
        ->houseNumber('123')
        ->zipCode('12345')
        ->city('Berlin')
        ->country('DE')
    )
    ->recipient(fn($recipient) => $recipient
        ->name('Jane Smith')
        ->street('Second Avenue')
        ->houseNumber('456')
        ->zipCode('54321')
        ->city('Hamburg')
        ->country('DE')
        ->email('jane@example.com')
        ->phone('+49123456789')
    )
    ->parcel(fn($parcel) => $parcel
        ->weight(2.5)
        ->content('Books')
        ->reference('ORDER-12345')
    )
    ->labelFormat('PDF')
    ->create();

// Access response data
echo "Parcel Number: {$shipment->parcelNumber}\n";
echo "MPS ID: {$shipment->mpsId}\n";
echo "Tracking URL: {$shipment->trackingUrl}\n";

// Save label to file
file_put_contents('label.pdf', $shipment->label->content);
```

### Runtime Configuration Override (Multi-Tenant)

[](#runtime-configuration-override-multi-tenant)

For multi-tenant applications or dynamic credentials:

```
use SmartDato\Dpd\Dpd;

// Tenant A with their own credentials
$dpdA = new Dpd([
    'environment' => 'production',
    'credentials' => [
        'delis_id' => $tenantA->dpd_delis_id,
        'password' => $tenantA->dpd_password,
    ],
]);

$shipment = $dpdA->shipment()
    ->sendingDepot('0000')
    ->sender(/* ... */)
    ->recipient(/* ... */)
    ->parcel(/* ... */)
    ->create();

// Tenant B with different credentials
$dpdB = new Dpd([
    'credentials' => [
        'delis_id' => $tenantB->dpd_delis_id,
        'password' => $tenantB->dpd_password,
    ],
]);
```

### Tracking Parcels

[](#tracking-parcels)

```
use SmartDato\Dpd\Facades\Dpd;

$events = Dpd::track('1234567890');

foreach ($events as $event) {
    echo "{$event->timestamp->format('Y-m-d H:i:s')} - {$event->status} at {$event->location}\n";
}
```

### Multiple Parcels per Shipment

[](#multiple-parcels-per-shipment)

```
$shipment = Dpd::shipment()
    ->sendingDepot('0000')
    ->sender(/* ... */)
    ->recipient(/* ... */)
    ->parcel(fn($parcel) => $parcel
        ->weight(2.5)
        ->content('Books')
        ->reference('BOX-1')
    )
    ->parcel(fn($parcel) => $parcel
        ->weight(3.0)
        ->content('Electronics')
        ->reference('BOX-2')
    )
    ->create();
```

### Custom Label Formats

[](#custom-label-formats)

```
// PDF Label (A4)
$shipment = Dpd::shipment()
    // ...
    ->labelFormat('PDF')
    ->paperFormat('A4')
    ->create();

// ZPL Label for thermal printers (barcode is automatically extracted)
$shipment = Dpd::shipment()
    // ...
    ->labelFormat('ZPL')
    ->create();

// Access barcode from ZPL label
echo "Barcode: {$shipment->label->barcode}\n"; // Only available for ZPL labels
file_put_contents('label.zpl', $shipment->label->content);
```

### Customer Reference Numbers and MPS ID

[](#customer-reference-numbers-and-mps-id)

Add custom reference numbers to track your shipments and group related shipments together:

```
$shipment = Dpd::shipment()
    ->sendingDepot('0000')
    ->mpsId('MPS-ORDER-12345') // Multi Parcel Shipment ID to group shipments
    ->customerReferenceNumber1('ORDER-12345') // e.g., Order number
    ->customerReferenceNumber2('CUSTOMER-98765') // e.g., Customer ID
    ->customerReferenceNumber3('WAREHOUSE-A') // e.g., Warehouse location
    ->customerReferenceNumber4('BATCH-001') // e.g., Batch number
    ->sender(/* ... */)
    ->recipient(/* ... */)
    ->parcel(/* ... */)
    ->create();

// The MPS ID is returned in the response
echo "MPS ID: {$shipment->mpsId}\n";
```

**Use cases:**

- **MPS ID**: Group multiple shipments together (useful for split orders or multi-box shipments)
- **Reference Number 1**: Order number or invoice number
- **Reference Number 2**: Customer ID or account number
- **Reference Number 3**: Warehouse location or department
- **Reference Number 4**: Batch number or shipping wave

Configuration
-------------

[](#configuration)

The config file (`config/dpd-sdk.php`) provides extensive customization options:

```
return [
    // Environment: 'staging' or 'production'
    'environment' => env('DPD_ENVIRONMENT', 'staging'),

    // DPD API Credentials
    'credentials' => [
        'delis_id' => env('DPD_DELIS_ID'),
        'password' => env('DPD_PASSWORD'),
    ],

    // Authentication Token Caching (24 hours)
    'cache' => [
        'store' => env('DPD_CACHE_STORE', null), // null = default
        'prefix' => 'dpd_auth',
        'ttl' => 86400,
    ],

    // SOAP Client Options
    'soap' => [
        'trace' => env('DPD_SOAP_TRACE', true),
        'connection_timeout' => 30,
        // ...
    ],

    // Rate Limits
    'rate_limits' => [
        'labels_per_minute' => 30,
        'calls_per_minute' => 60,
    ],

    // Default Label Options
    'defaults' => [
        'label_format' => 'PDF',
        'print_options' => [
            'printer_language' => 'PDF',
            'paper_format' => 'A4',
        ],
    ],

    // Logging for Debugging
    'logging' => [
        'enabled' => env('DPD_LOGGING_ENABLED', false),
        'channel' => env('DPD_LOGGING_CHANNEL', 'stack'),
    ],
];
```

Error Handling
--------------

[](#error-handling)

The SDK throws specific exceptions for different error scenarios:

```
use SmartDato\Dpd\Facades\Dpd;
use SmartDato\Dpd\Exceptions\AuthenticationException;
use SmartDato\Dpd\Exceptions\RateLimitException;
use SmartDato\Dpd\Exceptions\ValidationException;
use SmartDato\Dpd\Exceptions\SoapException;

try {
    $shipment = Dpd::shipment()
        ->sender(/* ... */)
        ->recipient(/* ... */)
        ->parcel(/* ... */)
        ->create();
} catch (AuthenticationException $e) {
    // Invalid credentials
    logger()->error('DPD authentication failed', ['error' => $e->getMessage()]);
} catch (RateLimitException $e) {
    // Too many requests
    logger()->warning('DPD rate limit exceeded', ['error' => $e->getMessage()]);
} catch (ValidationException $e) {
    // Invalid shipment data
    return back()->withErrors(['shipment' => $e->getMessage()]);
} catch (SoapException $e) {
    // SOAP/network error
    logger()->error('DPD SOAP error', ['error' => $e->getMessage()]);
}
```

### DPD API Error Responses

[](#dpd-api-error-responses)

The SDK automatically detects and formats errors returned by the DPD API. When the API returns error information in the response (instead of SOAP faults), you'll get clear error messages with error codes:

```
try {
    $shipment = Dpd::shipment()
        ->sendingDepot('0000')
        ->sender(/* ... */)
        ->recipient(/* ... */)
        ->create();
} catch (\RuntimeException $e) {
    // Example error message:
    // "DPD API Error: [ERR123] Invalid sender address; [ERR456] Missing required field"
    echo $e->getMessage();
}
```

Common DPD error codes:

- **Invalid address data** - Check sender/recipient address fields (name, street, zip code, city, country)
- **Missing required fields** - Ensure all mandatory fields are provided
- **Invalid depot code** - Verify the sending depot code (must be exactly 4 digits)
- **Authentication issues** - Check your DPD credentials (delis\_id and password)

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Run tests with coverage:

```
composer test-coverage
```

Run static analysis:

```
composer analyse
```

Fix code style:

```
composer format
```

Architecture
------------

[](#architecture)

The SDK is built with a layered architecture:

1. **SOAP Clients** - Low-level SOAP wrappers (`BaseSoapClient`, `LoginServiceClient`, etc.)
2. **Token Management** - Automatic authentication with 24-hour token caching
3. **Services** - High-level business logic (`ShipmentService`, `TrackingService`)
4. **Builders** - Fluent API for creating shipments (`ShipmentBuilder`, `AddressBuilder`, `ParcelBuilder`)
5. **DTOs** - Type-safe data transfer objects (`ShipmentResponse`, `TrackingEvent`, etc.)

See [CLAUDE.md](CLAUDE.md) for detailed architecture documentation.

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [SmartDato](https://github.com/smart-dato)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance82

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Recently: every ~19 days

Total

7

Last Release

92d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c3006db55caec62526937fa2d941da32fc5e69e2ca86a52e87c8046da5958d82?d=identicon)[smart-dato](/maintainers/smart-dato)

---

Top Contributors

[![tschigo](https://avatars.githubusercontent.com/u/344100?v=4)](https://github.com/tschigo "tschigo (10 commits)")[![michael-tscholl](https://avatars.githubusercontent.com/u/178569346?v=4)](https://github.com/michael-tscholl "michael-tscholl (9 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravelSmartDatodpd-sdk

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/smart-dato-dpd-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/smart-dato-dpd-sdk/health.svg)](https://phpackages.com/packages/smart-dato-dpd-sdk)
```

###  Alternatives

[scalar/laravel

Render your OpenAPI-based API reference

6183.9k2](/packages/scalar-laravel)[ryangjchandler/bearer

Minimalistic token-based authentication for Laravel API endpoints.

8129.8k](/packages/ryangjchandler-bearer)[combindma/laravel-facebook-pixel

Meta pixel integration for Laravel

4956.9k](/packages/combindma-laravel-facebook-pixel)[stechstudio/laravel-hubspot

A Laravel SDK for the HubSpot CRM Api

2971.0k](/packages/stechstudio-laravel-hubspot)[njoguamos/laravel-plausible

A laravel package for interacting with plausible analytics api.

208.8k](/packages/njoguamos-laravel-plausible)[likeabas/filament-chatgpt-agent

Integrate with OpenAI ChatGPT

235.3k](/packages/likeabas-filament-chatgpt-agent)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
