MDM Express API for Node.js and PHP

MDM Express stores your products and ships them. With dz-delivery, the mdm provider uses its v2 API (parcels, geography, offices) with the same code as every other carrier.

Install

TypeScript · npm
npm install @dz-delivery/core
PHP · Composer
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).

MDM Express credentials

OptionValueNotes
apiKeyAPI key created in the MDM dashboardSent as x-api-key
storeIdYour MDM store (STR-…)Required to create a parcel

MDM Express in TypeScript / Node.js

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

const mdm = createClient('mdm', {
  apiKey: process.env.MDM_API_KEY!,
  storeId: process.env.MDM_STORE_ID!,  // STR-…
});

try {
  const quote = await mdm.getFees({ toWilayaId: 16, toCommuneId: 'Bab Ezzouar' });

  const parcel = await mdm.createParcel({
    recipientName: 'Mohamed Amine',
    phone: '0550123456',
    address: 'Cité 221 lots, n°98',
    wilayaId: 16,
    communeName: 'Bab Ezzouar',
    // products stocked at MDM: their catalog id (PRD-…)
    productList: [{ name: 'T-shirt', quantity: 1, productId: 'PRD-B5C63A' }],
    price: 2500,
  });

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

  // Delivered parcels, filtered by MDM
  const delivered = await mdm.listParcels({ status: 'delivered', pageSize: 50 });
} catch (err) {
  if (isShippingError(err)) console.error(err.code, err.message);
}

MDM Express in PHP / Laravel

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

$mdm = ClientFactory::create('mdm', [
    'apiKey'  => getenv('MDM_API_KEY'),
    'storeId' => getenv('MDM_STORE_ID'),
]);

try {
    $parcel = $mdm->createParcel([
        'recipientName' => 'Mohamed Amine',
        'phone'         => '0550123456',
        'address'       => 'Cité 221 lots, n°98',
        'wilayaId'      => 16,
        'communeName'   => 'Bab Ezzouar',
        'productList'   => [['name' => 'T-shirt', 'quantity' => 1, 'productId' => 'PRD-B5C63A']],
        'price'         => 2500,
    ]);

    $result = $mdm->track($parcel->trackingNumber);
} catch (ShippingError $e) {
    echo "{$e->code}: {$e->getMessage()}";
}

Full PHP guide (Laravel, errors, testing): PHP guide.

Supported methods

MethodSupportNotes
createParcelyesMDM catalog products (productId or sku = PRD-…) and storeId.
trackyesUnified status + history.
getFeesyesExact rate per commune (home or office) and return fee.
getWilayas / getCommunesyesMDM commune ids (DZA161601).
getStopDesksyesOffices of MDM’s partner carriers.
listParcelsyesstatus and updatedSince filters applied by MDM.
cancelParcelNOT_SUPPORTEDNo cancellation through the API: use the MDM dashboard.
healthCheckyesChecks the key (real call).

MDM Express statuses → unified statuses

The SDK maps MDM status slugs (read live from GET /api/v2/shipping/parcels/metadata, October 2026) to unified statuses. The status filter of listParcels uses the same table: every MDM slug of the requested status is filtered by MDM.

MDM status (slug)Unified status
out-of-stockpending
confirmed, preparing, packaged, ready-for-dispatchcreated
received-by-mdm, dispatched, received, in-transit, ready-for-delivery, out-for-delivery, postponed, delivery-attempt-failed, exchange-pending, refund-pendingin_transit
delivered, delivered-partially, exchange-collecteddelivered
delivery-failed, returning, return-ready, return-received, return-grouped, returned, exchange-failed, refund-collected, refunded, refunded-partiallyreturned
lostcancelled (terminal, neither delivered nor returned)

Full list of unified statuses and what they mean: SDK statuses.

Good to know about the MDM Express API

  • Tested live (October 2026, read-only): wilayas, communes, offices, fees, list, tracking, errors.
  • Fulfillment: MDM ships products stocked in its own warehouse. Every productList line must carry its MDM catalog id; an unknown product → VALIDATION_ERROR on productList.
  • price is what the recipient pays: MDM adds no delivery fee on top.
  • MDM has no “order reference” field: orderId is written to the notes (Ref: …). The MDM search API has no filter for it, so the SDK filters orderId on each page it reads: use listParcels({ orderId, allPages: true }) ('allPages' => true in PHP) to search every page, not just the first one.
  • The baseUrl must use HTTPS.

Detailed native mapping (endpoints, fields, statuses): PROVIDERS.md.

MDM Express FAQ

Where do I find my MDM API key and storeId?

In the MDM dashboard: the API key in the API settings, the storeId (STR-…) in your store.

Can I ship a product that is not stocked at MDM?

No: MDM rejects products outside its catalog. Add the product to MDM first, then use its PRD-… id.

How do I cancel an MDM parcel?

The API has no cancellation: cancelParcel returns NOT_SUPPORTED. Cancel from the MDM dashboard.

Other carriers

Same interface, same normalized statuses (pending, in_transit, delivered…).