FREE API · ALGERIA · NO SIGNUP · NO KEY

Ship with every Algerian courier through one API

Create cash-on-delivery parcels, track them, and quote fees with Yalidine, ZR Express, Maystro, NOEST and 30+ Ecotrack couriers — one request shape, one status vocabulary, all 58 wilayas.

POST /v1/orders POST /v1/track POST /v1/rates
create-order.sh
$ curl -X POST https://freeship.dzbuild.com/v1/orders \
  -H 'Content-Type: application/json' -d '{
    "courier":     "yalidine",
    "credentials": { "apiId": "…", "apiToken": "…" },
    "options":     { "fromWilaya": 16 },
    "order": {
      "recipient": {
        "fullName":    "Amine Bouzid",
        "phone":       "0551234567",
        "wilayaCode":  16,
        "communeName": "Bab Ezzouar"
      },
      "deliveryType": "home",
      "productList":  "Sneakers Air x1",
      "codAmount":    4500
    }
  }'

→ 201 { "trackingNumber": "yal-ABC123", "status": "created" }

How it works

Every request carries three things: which courier to use, your own credentials for that courier, and the order itself. The parcel is created on your courier account; credentials are used for that one call and never stored. Switching courier is a one-line change — the request shape and the response shape stay the same.

Who is this for? Anyone building for Algeria: a store, a landing page, an ERP, a Google Sheet with 200 orders. It exists because every Algerian courier has a different API and most of them are undocumented. We integrated them once, properly, at DZBuild — this is that work as a free service.

Endpoints

Base URL https://freeship.dzbuild.com · all bodies JSON.

POST/v1/orders Create a shipment with any supported courier POST/v1/track Current status + full event history for a tracking number POST/v1/rates Delivery + return fee for a route GET/v1/couriers Supported couriers, required credential fields, capabilities GET/v1/wilayas The 58 wilayas — code, French + Arabic names, deep-south flag GET/health Liveness

Create a parcel

The hero example above is complete and real — run it with your Yalidine credentials and a parcel lands on your account, label included. The fields that matter:

FieldNotes
courierREQUIREDyalidine · zrexpress · maystro · noest · ecotrack
credentialsREQUIREDYour courier account's API credentials — see couriers
order.recipient.fullNameREQUIRED2–120 chars
order.recipient.phoneREQUIREDValid Algerian mobile (05/06/07…) — else 422 invalid_phone
order.recipient.wilayaCodeREQUIRED1–58, see GET /v1/wilayas
order.recipient.communeNameREQUIREDThe courier's exact French spelling. Wrong commune = the #1 create error
order.deliveryTypeREQUIREDhome or stopdesk (+ stopDeskId for Yalidine/NOEST desks)
order.productListREQUIREDPrinted on the label; long lists truncated safely per courier
order.codAmountREQUIREDCash to collect, integer DZD. 0 = prepaid
options.fromWilayaYALIDINEYour origin wilaya — required to create and to quote
order.referenceOPTIONALYour order id; omitted → generated (FS-…)
All optional fields
FieldNotes
order.recipient.phoneAltSecond phone — couriers call it after a failed first contact
order.recipient.addressLineStreet address; optional for stop-desk
order.weightKgParcel weight
order.declaredValueEnables insurance where supported (Yalidine)
order.freeShippingCustomer not charged shipping — otherwise Yalidine adds its fee to the COD
order.isExchangeExchange / swap parcel
order.hasOpenPackageCustomer may open before paying (NOEST)
order.notesRemark for the driver
options.baseUrlEcotrack tenant URL, or a Yalidine-family network host
options.timeoutMsUpstream courier timeout

Track a parcel

On demand — call it on page load, from a cron, wherever. rawStatus always carries the courier's original wording.

track.sh
$ curl -X POST https://freeship.dzbuild.com/v1/track \
  -H 'Content-Type: application/json' -d '{
    "courier": "yalidine",
    "credentials": { "apiId": "…", "apiToken": "…" },
    "trackingNumber": "yal-ABC123"
  }'

→ 200 {
  "status": "out_for_delivery",
  "events": [
    { "status": "picked_up",        "rawStatus": "Ramassé",            "timestamp": "2026-07-08T09:00:00Z" },
    { "status": "out_for_delivery", "rawStatus": "Sorti en livraison", "timestamp": "2026-07-09T08:30:00Z" }
  ]
}

One status vocabulary

Every courier's dialect — French sentences, Arabic labels, bare numbers — maps onto one closed set. Build your UI against it once.

created pending_pickup picked_up in_transit at_hub out_for_delivery delivered
side states: delivery_attemptedon_holdreturn_in_transitreturnedcancelledlostunknown

delivered, returned, cancelled, lost are terminal. unknown means the courier emitted new wording — show rawStatus and keep polling. French + Arabic UI labels for all fourteen are in the status guide.

Quote a fee

rates.sh
$ curl -X POST https://freeship.dzbuild.com/v1/rates \
  -H 'Content-Type: application/json' -d '{
    "courier": "yalidine",
    "credentials": { "apiId": "…", "apiToken": "…" },
    "query": { "fromWilaya": 16, "toWilaya": 31, "deliveryType": "home" }
  }'

→ 200 { "deliveryFee": 600, "returnFee": 250, "total": 600, "currency": "DZD" }

Note the returnFee — your COD unit economics depend on it as much as on the delivery fee. query.toCommune refines per-commune pricing; query.tier accepts express (default) or economic. Deep-south wilayas (isDeepSouth in /v1/wilayas) carry surcharges everywhere — quote, don't hardcode.

Couriers

Credentials come from your own account on each courier's dashboard. GET /v1/couriers returns this list live, with capabilities.

CouriercouriercredentialsNotes
YalidineyalidineapiId, apiTokenoptions.fromWilaya required. Labels at creation. Densest stop-desk network
Yalitec · Guepex · Easy & SpeedyalidineapiId, apiTokenSame platform — add options.baseUrl for that network
ZR Express (Procolis)zrexpresstoken, keyExchanges supported. Labels from the dashboard
MaystromaystroapiKeyCommune IDs resolved for you. Same name+phone twice a day is rejected by Maystro
NOESTnoestapiToken, guidOrder validation handled — created means pickup-ready. Desk codes like 16A
Ecotrack (DHD, Conexlog, MSM Go, +30)ecotracktokenoptions.baseUrl = your tenant, e.g. https://platform.dhd-dz.com

Choosing between them, per-courier behavior, COD mechanics: the dzship field guides cover what the comparison tables don't.

Errors

One envelope everywhere: { "error": { "code", "message", "fields?" } }

HTTPCodeWhat to do
400VALIDATION_ERRORFix the fields listed in error.fields
422invalid_phoneNot a valid Algerian mobile — correct the number
422 / 502NOT_SUPPORTED / COURIER_ERRORThe courier rejected it — read message (bad credentials, unknown commune, missing stop desk…)
429rate_limitedWait Retry-After seconds, then retry
503overloadedMomentary capacity protection — retry shortly

Fair use

Hard server-side limits keep the API fast and free for everyone.

LimitValue
Orders / hour / IP30
Orders / day / IP100
Orders / day / recipient phone10
Tracking calls / minute / IP30
Tracking calls / day / IP2 000
Rate quotes / minute / IP20

Design around them: track on page-view rather than tight loops, and cache /v1/wilayas and /v1/couriers — they rarely change.

BUILDING A WHOLE STORE?

dzship is the shipping. DZBuild is the rest.

Arabic/French storefronts, landing pages, COD order management with confirmation workflows, 80+ couriers pre-wired, stock, analytics — and a dashboard your client can actually use.

Open dzbuild.com →