Maystro Delivery API for Node.js and PHP

Create Maystro orders, calculate fees and list pickup points with the dz-delivery SDK. Track, list and cancel orders through the API, or receive status updates by webhook.

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).

Maystro credentials

OptionHeader sentWhere to find it
apiTokenAuthorization: Token <apiToken>Your store token in the Maystro app

Official documentation: Maystro Delivery API.

Maystro with TypeScript / Node.js

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

const maystro = createClient('maystro', {
  apiToken: process.env.MAYSTRO_API_TOKEN!,
});

try {
  const wilayas = await maystro.getWilayas();
  const communes = await maystro.getCommunes(16);

  // Stop desks / pickup points: Maystro requires communeId
  const desks = await maystro.getStopDesks({ wilayaId: 16, communeId: communes[0].id });

  const quote = await maystro.getFees({ toWilayaId: 16, toCommuneId: communes[0].id });

  const parcel = await maystro.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',
  });
  // use parcel.trackingNumber (or parcel.id) for track / cancelParcel
  const { events } = await maystro.track(parcel.trackingNumber);
} catch (err) {
  if (isShippingError(err)) console.error(err.code, err.message);
}

Maystro with PHP / Laravel

PHP
use DzDelivery\ClientFactory;

$maystro = ClientFactory::create('maystro', [
    'apiToken' => getenv('MAYSTRO_API_TOKEN'),
]);

$communes = $maystro->getCommunes(16);
$desks    = $maystro->getStopDesks(['wilayaId' => 16, 'communeId' => $communes[0]->id]);
$quote    = $maystro->getFees(['toWilayaId' => 16, 'toCommuneId' => $communes[0]->id]);

$parcel = $maystro->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',
]);
$tracked = $maystro->track($parcel->trackingNumber); // or $parcel->id

Installation, Laravel, errors and testing: see the full PHP guide.

Supported methods

MethodSupportNotes
createParcelyesReturned status: pending.
trackyesOrder + status history. Order id or tracking number.
getFeesyesHome and stop desk rates.
getWilayas / getCommunesyesThe wilaya id is the official code.
getStopDesksyesStop desks and pickup points; communeId required.
listParcelsyes20 orders per page; status, orderId, keyword and date filters applied by the SDK.
cancelParcelyesCancels the order (status 50). Order id or tracking number.
healthCheckyesChecks the token (real API call).
getLabels (extra)yesShipping labels as a PDF, one page per order. On MaystroProvider.

Print shipping labels (PDF)

TypeScript
import { MaystroProvider } from '@dz-delivery/core';
import { writeFileSync } from 'node:fs';

const maystro = new MaystroProvider({ apiToken: process.env.MAYSTRO_API_TOKEN! });
const { data, labelCount } = await maystro.getLabels(['172316976800001']); // tracking numbers or parcel.id
writeFileSync('labels.pdf', data); // one page per order found
PHP
use DzDelivery\Models\ClientOptions;
use DzDelivery\Providers\MaystroProvider;

$maystro = new MaystroProvider(ClientOptions::fromArray(['apiToken' => getenv('MAYSTRO_API_TOKEN')]));
$labels  = $maystro->getLabels(['172316976800001']); // tracking numbers or $parcel->id
return response($labels->data, 200, ['Content-Type' => 'application/pdf']); // Laravel

Track Maystro parcels with webhooks

Set up an HTTPS URL in the Maystro app (Settings → Webhooks). The OrderStatusChanged event carries payload.id (the order id) and payload.status (a numeric code), which the SDK converts to a unified status.

TypeScript
import { mapMaystroStatus } from '@dz-delivery/core';

// check the URL secret first (not signed), then: event = JSON decoded from message.data (base64)
if (event.event === 'OrderStatusChanged') {
  const status = mapMaystroStatus(event.payload.status); // 41 → 'delivered'
  // update the order whose carrier_id = event.payload.id
}
PHP
use DzDelivery\Support\StatusMapper;

// $event = JSON decoded from message.data, after checking the URL secret
if (($event['event'] ?? null) === 'OrderStatusChanged') {
    $status = StatusMapper::maystro($event['payload']['status'] ?? null); // 41 → 'delivered'
}

Full example (base64 decoding, securing the URL): PHP guide, Maystro webhooks section.

Maystro statuses → unified statuses

Maystro uses numeric codes, including in webhooks (payload.status). mapMaystroStatus / StatusMapper::maystro() accept the code (41, "41") or the name (DELIVERED, ready to return), ignoring case and separators.

CodeMaystro statusUnified statusNotes
4CREATEDpendingRegistered, not yet handed over; pickup not requested.
11PENDINGpendingOn hold before preparation.
12OUT_OF_STOCKpendingPremium stores: cannot be prepared yet.
5PICK_UP_REQUESTEDcreatedReady to be picked up by Maystro.
6IN_PROCESScreatedBeing processed / prepared by Maystro, not moving yet.
8WAITING_TRANSITin_transitIn a hub, waiting for transfer.
9IN_TRANSIT_TO_BE_SHIPPEDin_transit
15READY_TO_SHIPin_transitHeld by Maystro (picked up for Starter, in the warehouse for Premium), ready for a driver.
22ASSIGNEDin_transitAssigned to a driver.
31SHIPPEDin_transitOut for delivery.
32ALERTEDin_transitDelivery issue / failed attempt.
42POSTPONEDin_transit
41DELIVEREDdelivered
50ABORTEDcancelledMaystro itself also calls it “CANCELLED”. If the parcel had already shipped, the 51 / 10 / 52 statuses that follow map to returned.
10IN_TRANSIT_TO_BE_RETURNEDreturned
51READY_TO_RETURNreturnedAlias READY_TO_BE_RETURNED.
52TAKEN_BY_STOREreturnedReturn handed back to the store.
53NOT_RECEIVEDreturnedReturn reported as not received by the store.
Other—unknown

The name aliases CANCELLED / CANCELED also map to cancelled. What each unified status means: full list of unified statuses.

Good to know about the Maystro API

  • track and cancelParcel accept the order id (parcel.id) or the tracking number (the Maystro display_id, one extra request).
  • listParcels: Maystro returns 20 orders per page with no filtering; the SDK filters each page (status, orderId, keyword, updatedSince).
  • getStopDesks requires a communeId; the returned id is what you pass as stopDeskId when creating a parcel.
  • Fees come from the Maystro pricing API, with an automatic fallback to the legacy delivery-options API.
  • Maystro webhooks are not signed: protect the URL (for example with a long secret in the query string).

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

Maystro FAQ

How do I track a Maystro parcel through the API?

With track(): the SDK reads the order and its history (history_order) and returns unified statuses. To get notified without polling the API, use webhooks: the SDK provides mapMaystroStatus / StatusMapper::maystro() to convert them to unified statuses.

Where do I find the Maystro API token?

It is your store token in the Maystro app; pass it as-is in apiToken.

How do I calculate Maystro fees?

getFees({ toWilayaId, toCommuneId }) returns the home rate (deliveryFee) and the stop desk rate (stopDeskFee) in DZD.

Other carriers

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