Integrating Algerian couriers into your store: an engineer's checklist
Connecting ZR Express, Maystro or any Algerian delivery company is more than calling an API. Status mapping, idempotent shipment creation, wilaya data and cash-on-delivery reconciliation — what to get right before launch.
Last reviewed: September 2026. Courier APIs change; read each company's current documentation for endpoints and fields.
Most online orders in Algeria end with a courier and, very often, cash on delivery. That makes the delivery integration part of your payment system, not a shipping afterthought. I've integrated ZR Express and Maystro into production stores; this is the checklist I'd hand to anyone doing the same with any Algerian courier.
1. Put every courier behind one interface
Each company has its own API, its own status names and its own quirks. Your order code shouldn't know which one it's talking to:
interface Courier {
createShipment(order: Order): Promise<{ trackingNumber: string }>
getStatus(trackingNumber: string): Promise<CourierStatus>
cancelShipment(trackingNumber: string): Promise<void>
}
Adding a courier then means one new class, not changes across checkout, the admin and the customer's order page.
2. Map their statuses to yours
Keep your own small set of shipment states — for example created, picked_up, in_transit, out_for_delivery, delivered, failed_attempt, returning, returned, cancelled — and map every courier status to one of them. Store the courier's raw status next to yours. When a courier adds a status you've never seen, log it and alert instead of crashing, and keep the order in its last known state.
3. Create shipments safely
The dangerous moment is the API call that creates a shipment. If it times out, did it work?
- Save the shipment row before calling the courier, with a unique key per order.
- If the courier lets you pass your own reference, send that key so a retry can't create a second parcel.
- On a timeout, look the shipment up before trying again.
- Run the call in a queued job with retries and backoff, not inside the customer's request.
4. Keep geography as data
Delivery prices, availability (home delivery or pickup point) and delivery times vary by wilaya and often by commune, and differ between couriers. Store them as data you can update, not constants in code, and show the price at checkout before the customer confirms.
5. Track, but don't hammer
Use the courier's webhooks where they exist; otherwise poll open shipments on a schedule, less often as a parcel ages. Stop polling once a shipment reaches a final state. Respect rate limits — a store with thousands of open parcels can hit them fast.
6. Reconcile cash on delivery separately
"Delivered" doesn't mean you have the money. The courier collects cash, then pays you out later, minus its fees. Track three things per order:
- the amount to collect,
- whether the courier reports it as collected,
- which payout it was included in.
A weekly report of "delivered but not yet paid out" and "paid out but amount differs" catches most problems while they're still small.
7. Treat returns as a flow, not an exception
Failed attempts and returns are normal with cash on delivery. Decide up front what happens to stock, to the order status and to the customer's ability to order again, and make the returned parcel something the admin can confirm on arrival.
8. Show the customer what the courier knows
A tracking timeline on the order page — in Arabic and French — prevents a large share of "where is my order?" messages, and tells the customer when to expect a call from the delivery agent.
I build stores and delivery integrations for the Algerian market: see e-commerce development in Algeria and the guide to accepting online payments in Algeria.
لديك مشروع مشابه؟
أخبرني أين وصلت وما الذي يعيقك. رد سريع عبر واتساب وعرض سعر مجاني.