API ZR Express en Node.js et PHP

Créez, suivez, listez et annulez vos colis ZRExpress avec le SDK dz-delivery — plus les étiquettes PDF, la création en masse et la vérification des webhooks.

Installer

TypeScript · npm
npm install @dz-delivery/core
PHP · Composer
composer require dz-delivery/sdk

Node.js ≥ 18 (aucune dépendance) ou PHP ≥ 8.2 (Guzzle 7). Le même code fonctionne ensuite pour les autres transporteurs : seule la configuration du client change.

Identifiants ZRExpress

OptionHeader envoyéOù la trouver
apiKeyX-Api-KeyPortail ZRExpress (clé API secrète)
tenantX-TenantPortail ZRExpress (identifiant du tenant)

Documentation officielle : docs.zrexpress.app.

ZRExpress en TypeScript / Node.js

TypeScript
import { createClient, isShippingError } from '@dz-delivery/core';

const zr = createClient('zrexpress', {
  apiKey: process.env.ZREXPRESS_API_KEY!,
  tenant: process.env.ZREXPRESS_TENANT!,
});

const wilayas = await zr.getWilayas();               // [{ id, name, code: '16' }]
const communes = await zr.getCommunes(16);           // id ZR ou code officiel 1–58
const hubs = await zr.getStopDesks({ wilayaId: 16 }); // points relais

const quote = await zr.getFees({ toWilayaId: 16, isStopDesk: false });
// { deliveryFee: 400, stopDeskFee: 250, currency: 'DZD' }

try {
  const parcel = await zr.createParcel({
    recipientName: 'Mohamed Amine',
    phone: '0550 12 34 56',          // normalisé en +213…
    address: 'Cité 221 lots, n°98',
    wilayaName: 'Alger',
    communeName: 'Bab Ezzouar',
    productName: 'T-shirt',
    price: 2500,                     // montant encaissé, frais inclus (≤ 150 000 DZD)
    orderId: 'ORDER-1001',
  });

  const { parcel: current, events } = await zr.track(parcel.trackingNumber);

  // Synchroniser les colis du compte (pull)
  const page = await zr.listParcels({ updatedSince: '2026-10-01T00:00:00+00:00', allPages: true });

  await zr.cancelParcel(parcel.trackingNumber); // numéro de suivi ou UUID
} catch (err) {
  if (isShippingError(err)) console.error(err.code, err.message);
}

ZRExpress en PHP / Laravel

PHP
use DzDelivery\ClientFactory;
use DzDelivery\Errors\ShippingError;

$zr = ClientFactory::create('zrexpress', [
    'apiKey' => getenv('ZREXPRESS_API_KEY'),
    'tenant' => getenv('ZREXPRESS_TENANT'),
]);

$quote = $zr->getFees(['toWilayaId' => 16, 'isStopDesk' => false]);
$hubs  = $zr->getStopDesks(['wilayaId' => 16]);

try {
    $parcel = $zr->createParcel([
        'recipientName' => 'Mohamed Amine',
        'phone'         => '0550123456',
        'address'       => 'Cité 221 lots, n°98',
        'wilayaName'    => 'Alger',
        'communeName'   => 'Bab Ezzouar',
        'productName'   => 'T-shirt',
        'price'         => 2500,
        'orderId'       => 'ORDER-1001',
    ]);

    $result = $zr->track($parcel->trackingNumber);
    $page   = $zr->listParcels(['orderId' => 'ORDER-1001']);
} catch (ShippingError $e) {
    echo "{$e->code}: {$e->getMessage()}";
}

Guide PHP complet (Laravel, erreurs, tests) : guide-php.md.

Méthodes supportées

MéthodeSupportNotes
createParcelouiLe SDK relit le colis créé pour renvoyer le numéro de suivi.
trackouiStatut unifié + historique des états.
getFeesouiTarif domicile et point relais pour la wilaya.
getWilayas / getCommunesouiTerritoires ZR, code officiel ou nom acceptés.
getStopDesksouiHubs ZR avec point relais.
listParcelsouiRecherche paginée, filtres orderId, keyword, status, updatedSince.
cancelParcelouiNuméro de suivi ou UUID.
healthCheckouiVérifie les identifiants (appel réel).

Étiquettes, envoi en masse et webhooks ZRExpress

Ces fonctions propres à ZRExpress sont disponibles via createZRExpress() (TS) ou new ZRExpressProvider() (PHP).

TypeScript
import { createZRExpress, verifyZRExpressWebhook } from '@dz-delivery/core';

const zr = createZRExpress({ apiKey, tenant });

// Étiquettes PDF (max 250)
const { fileUrl } = await zr.generateLabels(['16-AAA111-ZR', '16-BBB222-ZR']);

// Création en masse (max 100, orderId obligatoire)
const { successes, failures } = await zr.createParcelsBulk([
  { ...parcelInput, orderId: 'ORD-1' },
  { ...parcelInput, orderId: 'ORD-2' },
]);

// Webhooks signés (corps brut obligatoire)
app.post('/webhooks/zrexpress', express.raw({ type: '*/*' }), (req, res) => {
  const event = verifyZRExpressWebhook(req.body, req.headers, process.env.ZREXPRESS_WEBHOOK_SECRET!);
  // event.type · event.trackingNumber · event.status (unifié)
  res.sendStatus(200);
});
PHP
use DzDelivery\Providers\ZRExpressProvider;
use DzDelivery\Providers\ZRExpress\Webhook;

$zr = new ZRExpressProvider(['apiKey' => getenv('ZREXPRESS_API_KEY'), 'tenant' => getenv('ZREXPRESS_TENANT')]);
$zr->createParcelsBulk([...]);

$raw   = file_get_contents('php://input');
$event = Webhook::verify($raw, getallheaders(), getenv('ZREXPRESS_WEBHOOK_SECRET'));

Détails : ZREXPRESS.md.

À savoir sur l’API ZRExpress

  • Montant ≤ 150 000 DZD, frais de livraison inclus (price).
  • Les téléphones sont envoyés au format international (+213…) : passez-les comme vous les avez, le SDK normalise.
  • Sans changement d’état côté portail, le colis reste « Commande reçue » (pending) jusqu’à être marqué prêt à expédier.
  • Stop desks = hubs ZR avec point relais ; filtrer par wilaya seule donne les meilleurs résultats.
  • Produits : stockType vaut none par défaut (pas de catalogue). local / warehouse demandent productId + sku.
  • En production, préférez les webhooks pour suivre les statuts ; listParcels est l’alternative en pull.

Mapping natif détaillé (endpoints, champs, statuts) : PROVIDERS.md.

FAQ ZRExpress

Où trouver l’API key et le tenant ZRExpress ?

Dans le portail ZRExpress : la clé API va dans apiKey (header X-Api-Key) et l’identifiant du tenant dans tenant (header X-Tenant).

Comment imprimer les étiquettes ZR Express ?

generateLabels([...trackings]) renvoie l’URL d’un PDF regroupé, ou un PDF par colis avec { mode: 'individual' }.

Comment recevoir les changements de statut ZRExpress ?

Configurez un webhook dans le portail, puis vérifiez la signature avec verifyZRExpressWebhook (TS) ou Webhook::verify (PHP) sur le corps brut de la requête.

Puis-je annuler un colis avec son numéro de suivi ?

Oui : cancelParcel accepte le numéro de suivi ou l’UUID ZR.

Autres transporteurs

Même interface, mêmes statuts normalisés (pending, in_transit, delivered…).