PHPackages                             uften/courier - 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. uften/courier

ActiveLibrary[API Development](/categories/api)

uften/courier
=============

A modern, strictly-typed Laravel package for integrating Algerian shipping providers (Yalidine, Maystro, Procolis/ZR Express, Ecotrack) with a unified adapter-based API.

v1.0.0(1mo ago)20MITPHPPHP ^8.4CI passing

Since Mar 22Pushed 1mo agoCompare

[ Source](https://github.com/uften/courier)[ Packagist](https://packagist.org/packages/uften/courier)[ Docs](https://github.com/uften/courier)[ RSS](/packages/uften-courier/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (8)Versions (2)Used By (0)

uften/courier
=============

[](#uftencourier)

> A modern, strictly-typed Laravel package for integrating **most** Algerian shipping providers — built on PHP 8.4, backed by enums, readonly DTOs, and a clean adapter pattern.

[![PHP 8.4](https://camo.githubusercontent.com/18443333c3619e175ab342f402d8dfcb1e507af87a7f3b505ecd7bb1b83f6f1f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342d626c75653f6c6f676f3d706870)](https://php.net) [![Laravel](https://camo.githubusercontent.com/07fed3eaadfba466c0b2d6f6969daaea3c4094e909924f6f39d0d5b821e7074c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313125323025374325323031322d7265643f6c6f676f3d6c61726176656c)](https://laravel.com) [![Tests](https://camo.githubusercontent.com/8a23e0ea51b73c2bcbf82e241a53e178e840b28150eac1a795af81bf219e8103/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f756674656e2f636f75726965722f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473)](https://github.com/uften/courier/actions) [![License: MIT](https://camo.githubusercontent.com/8174925d009b42074d50ab5cc7e29fcb1aa613b0d9cb2e43097697a40cf90fa4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f77)](LICENSE.md)

---

Why uften/courier?
------------------

[](#why-uftencourier)

Every Algerian courier has a different API shape, different field names, and different tracking status strings (`"Livré"`, `"delivered"`, `"SORTIE EN LIVRAISON"` …). Integrating more than one means writing glue code over and over.

**uften/courier** solves this with three principles:

1. **Unified DTOs** — `CreateOrderData`, `OrderData`, `RateData`, `LabelData`. One shape, every provider.
2. **Canonical status enum** — `TrackingStatus` with 12 values. Each adapter normalises its raw strings or IDs into this dictionary. Your code only ever sees `TrackingStatus::DELIVERED`.
3. **Swappable adapters** — swap providers with a single enum change. Zero application-code changes.

---

Supported Providers — 29 total
------------------------------

[](#supported-providers--29-total)

### Yalidine engine

[](#yalidine-engine)

ProviderEnumBase URLYalidine`Provider::YALIDINE``api.yalidine.app`Yalitec`Provider::YALITEC``api.yalitec.me`### Maystro (standalone)

[](#maystro-standalone)

ProviderEnumBase URLMaystro Delivery`Provider::MAYSTRO``backend.maystro-delivery.com/api`### Procolis engine

[](#procolis-engine)

ProviderEnumBase URLProcolis`Provider::PROCOLIS``procolis.com/api_v1`ZR Express`Provider::ZREXPRESS``procolis.com/api_v1`### Zimou Express (delivery router)

[](#zimou-express-delivery-router)

ProviderEnumBase URLZimou Express`Provider::ZIMOU``zimou.express/api`### Ecotrack engine — 23 providers sharing one API surface

[](#ecotrack-engine--23-providers-sharing-one-api-surface)

ProviderEnumSubdomainEcotrack (generic)`Provider::ECOTRACK``ecotrack.dz`Anderson Delivery`Provider::ANDERSON``anderson.ecotrack.dz`Areex`Provider::AREEX``areex.ecotrack.dz`BA Consult`Provider::BA_CONSULT``bacexpress.ecotrack.dz`Conexlog (UPS)`Provider::CONEXLOG``app.conexlog-dz.com`Coyote Express`Provider::COYOTE_EXPRESS``coyoteexpressdz.ecotrack.dz`DHD`Provider::DHD``dhd.ecotrack.dz`Distazero`Provider::DISTAZERO``distazero.ecotrack.dz`48Hr Livraison`Provider::E48HR``48hr.ecotrack.dz`FRET.Direct`Provider::FRETDIRECT``fret.ecotrack.dz`GOLIVRI`Provider::GOLIVRI``golivri.ecotrack.dz`Mono Hub`Provider::MONO_HUB``mono.ecotrack.dz`MSM Go`Provider::MSM_GO``msmgo.ecotrack.dz`Negmar Express`Provider::NEGMAR_EXPRESS``negmar.ecotrack.dz`Packers`Provider::PACKERS``packers.ecotrack.dz`Prest`Provider::PREST``prest.ecotrack.dz`RB Livraison`Provider::RB_LIVRAISON``rblivraison.ecotrack.dz`Rex Livraison`Provider::REX_LIVRAISON``rex.ecotrack.dz`Rocket Delivery`Provider::ROCKET_DELIVERY``rocket.ecotrack.dz`Salva Delivery`Provider::SALVA_DELIVERY``salvadelivery.ecotrack.dz`Speed Delivery`Provider::SPEED_DELIVERY``speeddelivery.ecotrack.dz`TSL Express`Provider::TSL_EXPRESS``tsl.ecotrack.dz`WorldExpress`Provider::WORLDEXPRESS``worldexpress.ecotrack.dz`---

### Supported Methods

[](#supported-methods)

MethodYalidine / YalitecMaystroProcolis / ZR ExpressZimou ExpressEcotrack engine (all 23)`testCredentials()`✅✅✅✅✅`metadata()`✅✅✅✅✅`getRates()`✅ \*❌✅✅✅`getCreateOrderValidationRules()`✅✅✅✅✅`createOrder()`✅✅✅✅✅`getOrder()`✅✅✅✅ \*\*✅`cancelOrder()`➖➖➖➖➖`getLabel()`✅✅❌✅✅`createProduct()` \*\*\*❌✅❌❌❌> \* Yalidine `getRates()` requires `$fromWilayaId`.
> \*\* `getOrder()` accepts either the **Zimou integer package ID** or the **`tracking_code`** string.
> \*\*\* Maystro-only method, not part of the `ProviderAdapter` contract — type-hint `MaystroAdapter` directly.
> ➖ = planned / unknown support.

---

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

[](#requirements)

- PHP **8.4+**
- Laravel **11** or **12**

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

[](#installation)

```
composer require uften/courier
```

Publish the config:

```
php artisan vendor:publish --tag=courier-config
```

---

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

[](#configuration)

Add your credentials to `.env`:

```
# Yalidine engine
YALIDINE_API_TOKEN=your-api-id
YALIDINE_API_KEY=your-api-key
YALITEC_API_TOKEN=your-api-id
YALITEC_API_KEY=your-api-key

# Maystro
MAYSTRO_API_TOKEN=your-token

# Procolis / ZR Express
PROCOLIS_ID=your-id
PROCOLIS_TOKEN=your-token
ZREXPRESS_ID=your-id
ZREXPRESS_TOKEN=your-token

# Zimou Express
ZIMOU_API_TOKEN=your-bearer-token

# Ecotrack-engine providers (one token per carrier account)
ECOTRACK_API_TOKEN=your-token
DHD_API_TOKEN=your-token
CONEXLOG_API_TOKEN=your-token
# ... see config/courier.php for the full list
```

---

Usage
-----

[](#usage)

### Resolve a provider

[](#resolve-a-provider)

```
use Uften\Courier\Facades\Courier;
use Uften\Courier\Enums\Provider;

$zimou    = Courier::provider(Provider::ZIMOU);
$yalidine = Courier::provider(Provider::YALIDINE);
$dhd      = Courier::via('dhd');

// Runtime credentials override
$zimou = Courier::provider(Provider::ZIMOU, ['token' => 'my-token']);
```

### Create an order

[](#create-an-order)

```
use Uften\Courier\Data\CreateOrderData;
use Uften\Courier\Enums\DeliveryType;

$order = Courier::provider(Provider::ZIMOU)->createOrder(
    new CreateOrderData(
        orderId:            'MY-ORD-069',
        firstName:          'Mohammed',
        lastName:           'A. ALLAL',
        phone:              '0669096909',
        address:            '69 Rue Hattab Amar',
        toWilayaId:         '09',
        toCommune:          'Blida',
        productDescription: 'Smartphone Samsung Galaxy S25',
        price:              120000.0,
        deliveryType:       DeliveryType::HOME,
        weight: 1, // required for zimou
    )
);

echo $order->trackingNumber; // Zimou's own tracking code, e.g. "ZM-ABC123"
echo $order->raw['id']; // Zimou's own package ID
echo $order->status->value;  // "pending"
echo $order->notes;          // "Via: Yalidine | Partner tracking: YALI-99999"
```

#### Zimou: requesting "Flexible" delivery

[](#zimou-requesting-flexible-delivery)

Zimou supports three delivery tiers: **Express** (default for `HOME`), **Flexible** (cheaper, slower), and **Point relais** (`STOP_DESK`). To request Flexible, embed the hint in the `notes` field:

```
new CreateOrderData(
    // ...
    deliveryType: DeliveryType::HOME,
    notes: 'zimou_delivery_type:Flexible|Leave at door if absent',
)
```

The adapter strips the prefix and uses `"Flexible"` for the API call. The remaining text after `|` is sent as the observation note.

### Track a shipment

[](#track-a-shipment)

```
use Uften\Courier\Enums\TrackingStatus;

// By Zimou integer package ID
$order = Courier::provider(Provider::ZIMOU)->getOrder('2632165');

// Status is always canonical
if ($order->status->value === TrackingStatus::DELIVERED) { /* ... */ }
if ($order->status->isTerminal()) { /* stop polling */ }

// Access the partner carrier details (not always available)
echo $order->raw['tracking_partner_company'];        // "Yalidine"
echo $order->raw['delivery_company_tracking_code'];  // "YALI-99999"
```

### Access provider metadata (no API call needed)

[](#access-provider-metadata-no-api-call-needed)

```
$meta = Provider::ZIMOU->metadata();
echo $meta->title;       // "Zimou Express"
echo $meta->website;     // "https://zimou.express"
echo $meta->apiDocs;     // "https://zimou.express/api/docs"

// All 29 providers at once — perfect for building provider-selection UIs
$all = Courier::allMetadata(); // array
```

### Get shipping rates

[](#get-shipping-rates)

```
// Zimou returns your account's configured prices
$rates = Courier::provider(Provider::ZIMOU)->getRates();

foreach ($rates as $rate) {
    echo "{$rate->toWilayaName}: {$rate->homeDeliveryPrice} DZD (home) / {$rate->stopDeskPrice} DZD (stop desk)";
}
```

### Fetch a label

[](#fetch-a-label)

```
use Uften\Courier\Enums\LabelType;

$label = Courier::provider(Provider::ZIMOU)->getLabel('2632165');

// Zimou always returns PDF_BASE64
return response($label->decodePdf(), 200, [
    'Content-Type'        => 'application/pdf',
    'Content-Disposition' => 'inline; filename="label.pdf"',
]);
```

---

TrackingStatus Dictionary
-------------------------

[](#trackingstatus-dictionary)

CaseValueMeaning`PENDING``pending`Created, not yet collected`PICKED_UP``picked_up`Collected from sender`IN_TRANSIT``in_transit`Moving between hubs`OUT_FOR_DELIVERY``out_for_delivery`With delivery agent`DELIVERED``delivered`Successfully delivered ✓`FAILED_DELIVERY``failed_delivery`Attempt failed`RETURNING``returning`Heading back to sender`RETURNED``returned`Back at sender`CANCELLED``cancelled`Cancelled before shipment`READY_FOR_PICKUP``ready_for_pickup`At stop desk / relay`EXCEPTION``exception`Lost, damaged, blocked`UNKNOWN``unknown`Unmapped raw status---

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

[](#error-handling)

```
use Uften\Courier\Exceptions\{
    AuthenticationException,
    CourierException,
    OrderNotFoundException,
    UnsupportedOperationException
};

try {
    $order = Courier::provider(Provider::ZIMOU)->getOrder($orderId);
} catch (OrderNotFoundException $e) {       // order number not found
} catch (AuthenticationException $e) {      // bad credentials
} catch (UnsupportedOperationException $e) { // feature not supported
} catch (CourierException $e) {             // any other provider error
    // For Zimou: also thrown when the API returns {"error": 1, "message": "..."}
}
```

---

Extending: Custom Adapter at Runtime
------------------------------------

[](#extending-custom-adapter-at-runtime)

```
Courier::extend(Provider::ZIMOU, function (?array $credentials) {
    return new MyCustomZimouAdapter($credentials);
});
```

---

Testing
-------

[](#testing)

```
composer test           # Pest suite
composer test:coverage  # with Xdebug
composer format         # Laravel Pint
```

---

Disclaimer
----------

[](#disclaimer)

- Not officially affiliated with or endorsed by any shipping provider.
- Verify all providers are authorised by [ARPCE](https://www.arpce.dz/ar/service/post-sd#operators) before use.

---

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

[](#contributing)

See [CONTRIBUTING.md](CONTRIBUTING.md).

Credits
-------

[](#credits)

Thanks to [Piteur Studio](https://github.com/PiteurStudio/CourierDZ) for providing the primary endpoints for this package.

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md).

License
-------

[](#license)

MIT — see [LICENSE.md](LICENSE.md).

###  Health Score

41

—

FairBetter than 88% of packages

Maintenance97

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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

Unknown

Total

1

Last Release

48d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/a5e2650e7b4f0e6954a165fd35a3e6e0ad424c901844aff58f094dccc774838c?d=identicon)[uften](/maintainers/uften)

---

Top Contributors

[![uften](https://avatars.githubusercontent.com/u/9881878?v=4)](https://github.com/uften "uften (4 commits)")

---

Tags

phplaraveltrackingshippingdeliverycourierAlgeriaYalidineProcolisEcotrackmaystrozr-express

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/uften-courier/health.svg)

```
[![Health](https://phpackages.com/badges/uften-courier/health.svg)](https://phpackages.com/packages/uften-courier)
```

###  Alternatives

[simplestats-io/laravel-client

Client for SimpleStats!

4515.5k](/packages/simplestats-io-laravel-client)[dariusiii/tmdb-laravel

Laravel Package for TMDB ( The Movie Database ) API. Provides easy access to the wtfzdotnet/php-tmdb-api library.

1821.1k](/packages/dariusiii-tmdb-laravel)[octw/aramex

A Library to integrate with Aramex APIs

2925.2k](/packages/octw-aramex)[gufy/whmcs

WHMCS API for Laravel 5

211.7k](/packages/gufy-whmcs)

PHPackages © 2026

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