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
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).
Maystro credentials
| Option | Header sent | Where to find it |
|---|---|---|
apiToken | Authorization: Token <apiToken> | Your store token in the Maystro app |
Official documentation: Maystro Delivery API.
Maystro with TypeScript / Node.js
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
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
| Method | Support | Notes |
|---|---|---|
createParcel | yes | Returned status: pending. |
track | yes | Order + status history. Order id or tracking number. |
getFees | yes | Home and stop desk rates. |
getWilayas / getCommunes | yes | The wilaya id is the official code. |
getStopDesks | yes | Stop desks and pickup points; communeId required. |
listParcels | yes | 20 orders per page; status, orderId, keyword and date filters applied by the SDK. |
cancelParcel | yes | Cancels the order (status 50). Order id or tracking number. |
healthCheck | yes | Checks the token (real API call). |
getLabels (extra) | yes | Shipping labels as a PDF, one page per order. On MaystroProvider. |
Print shipping labels (PDF)
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
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.
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 }
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.
| Code | Maystro status | Unified status | Notes |
|---|---|---|---|
4 | CREATED | pending | Registered, not yet handed over; pickup not requested. |
11 | PENDING | pending | On hold before preparation. |
12 | OUT_OF_STOCK | pending | Premium stores: cannot be prepared yet. |
5 | PICK_UP_REQUESTED | created | Ready to be picked up by Maystro. |
6 | IN_PROCESS | created | Being processed / prepared by Maystro, not moving yet. |
8 | WAITING_TRANSIT | in_transit | In a hub, waiting for transfer. |
9 | IN_TRANSIT_TO_BE_SHIPPED | in_transit | |
15 | READY_TO_SHIP | in_transit | Held by Maystro (picked up for Starter, in the warehouse for Premium), ready for a driver. |
22 | ASSIGNED | in_transit | Assigned to a driver. |
31 | SHIPPED | in_transit | Out for delivery. |
32 | ALERTED | in_transit | Delivery issue / failed attempt. |
42 | POSTPONED | in_transit | |
41 | DELIVERED | delivered | |
50 | ABORTED | cancelled | Maystro itself also calls it “CANCELLED”. If the parcel had already shipped, the 51 / 10 / 52 statuses that follow map to returned. |
10 | IN_TRANSIT_TO_BE_RETURNED | returned | |
51 | READY_TO_RETURN | returned | Alias READY_TO_BE_RETURNED. |
52 | TAKEN_BY_STORE | returned | Return handed back to the store. |
53 | NOT_RECEIVED | returned | Return 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
trackandcancelParcelaccept the order id (parcel.id) or the tracking number (the Maystrodisplay_id, one extra request).listParcels: Maystro returns 20 orders per page with no filtering; the SDK filters each page (status, orderId, keyword,updatedSince).getStopDesksrequires acommuneId; the returnedidis what you pass asstopDeskIdwhen 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…).