Ecotrack API — DHD, Anderson, World Express… for Node.js and PHP
Ecotrack is the platform behind DHD, Anderson, World Express and dozens of other Algerian couriers. With dz-delivery, a single ecotrack provider covers them all.
Install
npm install @dz-delivery/core
composer require dz-delivery/sdk
Node.js ≥ 18 (zero dependencies) or PHP ≥ 8.2 (Guzzle 7). Every carrier implements the same interface, so the same code works with the others once the client is configured; some operations are not available on every carrier and throw NOT_SUPPORTED (see the capability matrix).
Ecotrack credentials
| Option | Value | Notes |
|---|---|---|
token | API token from the courier’s dashboard | Sent as Authorization: Bearer <token> |
courier | Built-in key (dhd, anderson, …) | Exactly one of courier / baseUrl |
baseUrl | Tenant HTTPS URL, e.g. https://xyz.ecotrack.dz | For any other Ecotrack courier |
autoValidate | false by default | true: validates the order right after it is created |
Ecotrack with TypeScript / Node.js
import { createClient, isShippingError } from '@dz-delivery/core'; const dhd = createClient('ecotrack', { token: process.env.ECOTRACK_TOKEN!, courier: 'dhd', // or baseUrl: 'https://<tenant>.ecotrack.dz' autoValidate: true, // hand the order over to the courier right away }); try { const wilayas = await dhd.getWilayas(); // wilayas served by this courier const desks = await dhd.getStopDesks({ wilayaId: 16 }); const quote = await dhd.getFees({ toWilayaId: 16 }); const parcel = await dhd.createParcel({ recipientName: 'Mohamed Amine', phone: '0550123456', address: 'Cité 221 lots, n°98', wilayaId: 16, communeName: 'Bab Ezzouar', productName: 'T-shirt', price: 2500, orderId: 'ORDER-1001', }); const { parcel: current, events } = await dhd.track(parcel.trackingNumber); } catch (err) { if (isShippingError(err)) console.error(err.code, err.message); }
Ecotrack with PHP / Laravel
use DzDelivery\ClientFactory; use DzDelivery\Errors\ShippingError; $dhd = ClientFactory::create('ecotrack', [ 'token' => getenv('ECOTRACK_TOKEN'), 'courier' => 'dhd', // or 'baseUrl' => 'https://<tenant>.ecotrack.dz' 'autoValidate' => true, ]); try { $quote = $dhd->getFees(['toWilayaId' => 16]); $parcel = $dhd->createParcel([ 'recipientName' => 'Mohamed Amine', 'phone' => '0550123456', 'address' => 'Cité 221 lots, n°98', 'wilayaId' => 16, 'communeName' => 'Bab Ezzouar', 'productName' => 'T-shirt', 'price' => 2500, 'orderId' => 'ORDER-1001', ]); $result = $dhd->track($parcel->trackingNumber); } catch (ShippingError $e) { echo "{$e->code}: {$e->getMessage()}"; }
Installation, Laravel, errors and testing: see the full PHP guide.
Supported methods
| Method | Support | Notes |
|---|---|---|
createParcel | yes | Stays pending until validated (see autoValidate). |
track | yes | Unified status + history. |
getFees | yes | Rates per wilaya. |
getWilayas / getCommunes | yes | Only the wilayas served by the tenant. |
getStopDesks | yes | Communes with a stop desk (id = Ecotrack postal code). |
listParcels | NOT_SUPPORTED | Not implemented in the SDK yet. |
cancelParcel | yes | Only before the order is validated. |
healthCheck | yes | Checks the token (real API call). |
Built-in Ecotrack couriers
These courier keys work out of the box. For any other Ecotrack courier, pass its URL as baseUrl (HTTPS only).
| Courier | courier | Domain |
|---|---|---|
| DHD | dhd | platform.dhd-dz.com |
| Anderson Delivery | anderson | anderson-ecommerce.ecotrack.dz |
| World Express | worldexpress | world-express.ecotrack.dz |
| 48Hr Express | 48hrexpress | 48hr.ecotrack.dz |
| EcoRapid | ecorapid | ecorapide-express.ecotrack.dz |
| Conexlog | conexlog | app.conexlog-dz.com |
| MSM Go | msmgo | msmgo.ecotrack.dz |
| Packers | packers | packers.ecotrack.dz |
| Rocket Delivery | rocketdelivery | rocketdelivery.ecotrack.dz |
Ecotrack statuses → unified statuses
The SDK only maps Ecotrack’s stable keys (activity keys and order status keys), case-insensitively. The French display labels vary from one courier to another and map to unknown.
| Ecotrack key | Unified status |
|---|---|
prete_a_expedier, prete_a_preparer | pending |
order_information_received_by_carrier, en_preparation_stock, en_ramassage | created |
picked, accepted_by_carrier, dispatched_to_driver, attempt_delivery, vers_hub, en_hub, vers_wilaya, en_preparation, en_livraison, suspendu | in_transit |
livred, encaissed, payed, livre_non_encaisse, encaisse_non_paye, paiements_prets, paye_et_archive | delivered |
return_asked, return_in_transit, return_received, retour_chez_livreur, retour_transit_entrepot, retour_en_traitement, retour_recu, retour_archive | returned |
annule | cancelled |
Any other value (including notification_on_order and French labels) | unknown |
What each unified status means: full list of unified statuses.
Good to know about the Ecotrack API
- Validation: without
autoValidate: true, orders stay on hold until they are validated in the courier’s dashboard. cancelParcelonly works before validation; after that the API returnsVALIDATION_ERROR.- The
idof communes and stop desks is the Ecotrack postal code (“station code”): use it as-is forstopDeskId. - A
baseUrlending in/api/v1is accepted (the suffix is stripped automatically).
Detailed native mapping (endpoints, fields, statuses): PROVIDERS.md.
Ecotrack FAQ
How do I integrate the DHD API?
DHD runs on Ecotrack: create an ecotrack client with your DHD token and courier: 'dhd'.
My courier uses Ecotrack but is not in the list?
Pass its tenant URL as baseUrl (e.g. https://mycourier.ecotrack.dz); the API is identical.
Why do my Ecotrack parcels stay on hold?
Ecotrack creates orders unvalidated. Turn on autoValidate: true or validate them from the courier’s dashboard.
Other carriers
Same interface, same unified statuses (pending, in_transit, delivered…).