Passer au contenu principal

Livraison

Lisez et modifiez les tarifs de livraison par wilaya et la livraison gratuite, liez, testez et synchronisez les transporteurs, et listez wilayas et communes.

Écrit par Support

Ces endpoints couvrent ce que le dashboard garde dans ses pages de livraison : le tarif de livraison à domicile et au bureau de chaque wilaya, les règles de livraison gratuite et les transporteurs liés à la boutique. Ils servent aussi les listes de wilayas et de communes dont un formulaire de commande a besoin, ainsi que les communes et les stop desks que dessert le transporteur de la boutique.

Les prix sont en DZD. POST /v1/orders calcule la livraison à partir de ces tarifs et ignore tout coût de livraison envoyé dans le corps : une vitrine personnalisée lit donc les tarifs pour afficher une estimation et laisse la commande calculer le montant. Voir Thèmes & vitrines personnalisés.

Avant de commencer

  • La clé a besoin des portées de livraison. Les clés créées depuis le dashboard (Paramètres → API, /dashboard/api) ont les deux. Les portées sont figées à la création de la clé : une clé plus ancienne qui ne les a pas répond 403 forbidden. Créez une nouvelle clé depuis le dashboard.

  • Une boutique qui vend des produits numériques n'a pas de réglages de livraison : toute écriture de cette page y répond 422 shipping_not_available.

  • Chaque écriture demande un en-tête Idempotency-Key. Voir Idempotence.

  • Tester et lier un transporteur appellent ses serveurs pendant la requête, et une synchronisation des tarifs les appelle en arrière-plan. Ces trois appels et POST /v1/orders/{id}/send-to-delivery partagent un budget transporteur par boutique, en plus des limites de taux.

  • Les écritures de tarifs et de réglages peuvent être annulées. La liaison, la déliaison et le changement de transporteur par défaut ne le peuvent pas. La section sur l'annulation, en fin de page, explique comment faire.

  • Les lectures de livraison ne sont pas mises en cache par la passerelle : un GET envoyé juste après une écriture renvoie les nouvelles valeurs.

Portée

Description

shipping:read

Lire les tarifs et réglages de livraison, les transporteurs liés, la couverture des transporteurs et les listes de wilayas et de communes.

shipping:write

Modifier les tarifs et réglages de livraison, et lier, tester, délier ou synchroniser les transporteurs.

GET /v1/wilayas

Les wilayas que la boutique dessert, selon son mode de wilayas : 1 à 58 en mode compatible transporteurs, 1 à 69 en mode 69 wilayas. Les noms sont en arabe, en français et en anglais. Toute la liste arrive en une réponse, sans pagination.

Auth : clé plateforme avec shipping:read.

Requête

curl 'https://api.dzbuild.app/v1/wilayas' \
  -H "Authorization: Bearer $DZ_KEY"

Réponse 200

Deux des 58 wilayas sont montrées. mode_note est une phrase en anglais sur le mode.

{
  "data": {
    "wilaya_mode": "58",
    "mode_note": "Courier-compatible mode: wilayas 1-58 only.",
    "count": 58,
    "wilayas": [
      { "id": 1, "name_ar": "أدرار", "name_fr": "Adrar", "name_en": "Adrar" },
      { "id": 16, "name_ar": "الجزائر", "name_fr": "Alger", "name_en": "Algiers" }
    ]
  }
}

GET /v1/wilayas/{id}/communes

Les communes d'une wilaya, triées par nom français. Toute wilaya de 1 à 69 reçoit une réponse, quel que soit le mode de wilayas de la boutique. Toute la liste arrive en une réponse.

Auth : clé plateforme avec shipping:read.

C'est la liste de communes de la plateforme. Elle ne dit pas quelles communes un transporteur dessert : c'est le rôle de GET /v1/shipping/coverage.

Requête

curl 'https://api.dzbuild.app/v1/wilayas/16/communes' \
  -H "Authorization: Bearer $DZ_KEY"

Réponse 200

Deux des 57 communes de la wilaya 16 sont montrées.

{
  "data": {
    "wilaya_id": 16,
    "count": 57,
    "communes": [
      { "id": 564, "wilaya_id": 16, "name_ar": "عين بنيان", "name_fr": "Ain Benian" },
      { "id": 558, "wilaya_id": 16, "name_ar": "عين طاية", "name_fr": "Ain Taya" }
    ]
  }
}

Un id qui n'est pas composé de chiffres répond 400 bad_request. Une wilaya qui n'existe pas répond 404 not_found.

GET /v1/shipping/rates

Le tarif de livraison de chaque wilaya qui a un tarif dans la boutique, indexé par id de wilaya. Une wilaya sans tarif est absente de rates.

Auth : clé plateforme avec shipping:read.

Requête

curl 'https://api.dzbuild.app/v1/shipping/rates' \
  -H "Authorization: Bearer $DZ_KEY"

Réponse 200

Une seule wilaya est montrée.

{
  "data": {
    "wilaya_mode": "58",
    "currency": "DZD",
    "limits": {
      "max_price": 100000,
      "max_delivery_days": 60
    },
    "count": 58,
    "rates": {
      "16": {
        "home_price": 400,
        "home_enabled": true,
        "desk_price": 300,
        "desk_enabled": true,
        "days": 1,
        "is_active": true,
        "synced_provider": null,
        "synced_at": null
      }
    }
  }
}

Champ

Signification

wilaya_mode

58 ou 69, la même valeur que dans GET /v1/shipping/settings.

limits

Le prix le plus haut et la valeur days la plus haute qu'accepte POST /v1/shipping/rates.

count

Nombre de wilayas dans rates.

home_price, desk_price

Prix de la livraison à domicile et de la livraison au bureau, en DZD.

home_enabled, desk_enabled

Si la boutique propose ce type de livraison dans cette wilaya.

days

Délai de livraison en jours.

synced_provider, synced_at

Le transporteur dont la grille de tarifs a écrit ce tarif en dernier, et quand (YYYY-MM-DD HH:MM:SS). null si aucune synchronisation ne l'a écrit.

POST /v1/shipping/rates

Crée ou modifie les tarifs des wilayas envoyées. Les autres wilayas ne sont pas touchées.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key.

Corps

rates est un objet indexé par id de wilaya, écrit en chiffres seuls ("16", pas "016"), avec 1 à 69 wilayas. Chaque valeur porte les champs à modifier, et chaque champ est optionnel.

Champ

Type

Notes

home_price

number

En DZD, arrondi à deux décimales, de 0 à 100000. Une chaîne numérique est acceptée.

home_enabled

bool

true ou false. 0, 1, "0" et "1" sont aussi acceptés.

desk_price

number

Mêmes règles que home_price.

desk_enabled

bool

Mêmes règles que home_enabled.

days

int

Un nombre entier de jours, de 0 à 60.

Un champ omis, ou envoyé à null, garde sa valeur enregistrée. Une wilaya qui n'avait pas de tarif part d'un prix de 0, des deux types de livraison activés et de 3 jours.

Requête

curl -X POST 'https://api.dzbuild.app/v1/shipping/rates' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: rates-2026-10-06-1" \
  -d '{"rates": {"16": {"home_price": 450, "desk_price": 350}, "31": {"desk_enabled": false}}}'

Réponse 200

rates ne contient que les wilayas écrites, telles qu'enregistrées après l'écriture.

{
  "data": {
    "updated": 2,
    "wilaya_ids": [16, 31],
    "rates": {
      "16": { "home_price": 450, "home_enabled": true, "desk_price": 350, "desk_enabled": true, "days": 1 },
      "31": { "home_price": 500, "home_enabled": true, "desk_price": 350, "desk_enabled": false, "days": 2 }
    }
  }
}

Les valeurs précédentes sont conservées : l'écriture peut donc être annulée. La réponse ne porte pas de change_id : voir la section sur l'annulation.

GET /v1/shipping/settings

Les règles de livraison gratuite et le mode de wilayas.

Auth : clé plateforme avec shipping:read.

Requête

curl 'https://api.dzbuild.app/v1/shipping/settings' \
  -H "Authorization: Bearer $DZ_KEY"

Réponse 200

La réponse porte aussi un objet notes avec deux phrases en anglais qui rappellent la règle du seuil et celle du mode de wilayas. L'exemple ne le montre pas.

{
  "data": {
    "free_shipping": false,
    "free_shipping_threshold": 8000,
    "free_shipping_threshold_active": true,
    "wilaya_mode": "58"
  }
}

Champ

Signification

free_shipping

true quand la livraison est gratuite pour toutes les commandes.

free_shipping_threshold

Sous-total de commande en DZD à partir duquel la livraison est gratuite. 0 ou null veut dire pas de seuil.

free_shipping_threshold_active

true seulement quand le seuil est supérieur à 0.

wilaya_mode

"58" : les 58 wilayas avec lesquelles travaillent les transporteurs. "69" : les 69 wilayas, un mode réglé depuis le dashboard.

PATCH /v1/shipping/settings

Modifie un ou plusieurs des trois réglages. Envoyez-en au moins un ; les autres champs sont ignorés.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key.

Corps

Champ

Type

Notes

free_shipping

bool

true ou false. 0, 1, "0" et "1" sont aussi acceptés.

free_shipping_threshold

number ou null

En DZD, arrondi à deux décimales, de 0 à 99999999.99. 0 ou null désactive le seuil.

wilaya_mode

string

Seulement "58", qui ramène une boutique en mode 69 wilayas à 58 wilayas. Le passage à 69 wilayas se fait depuis la page Tarifs de livraison du dashboard (/dashboard/shipping) et répond ici 422 wilaya_mode_69_unsupported.

Requête

curl -X PATCH 'https://api.dzbuild.app/v1/shipping/settings' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: settings-2026-10-06-1" \
  -d '{"free_shipping_threshold": 8000}'

Réponse 200

Les réglages après l'écriture, sans notes. Les valeurs précédentes sont conservées : le changement peut donc être annulé.

GET /v1/shipping/providers

Tous les transporteurs pris en charge par la plateforme, liés à la boutique ou non, avec ce que chacun demande quand vous le liez. Les valeurs des identifiants ne sont jamais renvoyées : has_id et has_token disent seulement si une valeur est enregistrée. Toute la liste arrive en une réponse.

Auth : clé plateforme avec shipping:read.

Requête

curl 'https://api.dzbuild.app/v1/shipping/providers' \
  -H "Authorization: Bearer $DZ_KEY"

Réponse 200

Un seul transporteur est montré. La réponse porte aussi une phrase note, omise ici.

{
  "data": {
    "count": 103,
    "providers": [
      {
        "provider": "yalidine",
        "family": "yalidine",
        "credentials": {
          "api_id": { "label": "API ID", "required": true },
          "api_token": { "label": "API Token", "required": true },
          "_note": "Send an empty string to keep the currently stored value. Credentials are never returned by this API."
        },
        "extra_fields": {
          "delivery_tier": {
            "label": "Service tier",
            "required": false,
            "values": ["express"],
            "note": "Only \"express\" is valid here: this courier rejects the economic parameter outright and every order push would fail."
          }
        },
        "supports_rate_sync": true,
        "linked": true,
        "source": "store_delivery_providers",
        "is_enabled": true,
        "is_default": true,
        "is_send_default": true,
        "has_id": true,
        "has_token": true,
        "delivery_tier": "express",
        "economic_available": null,
        "credentials_failed_at": null,
        "synced_tier": "express",
        "stock_account": null,
        "auto_validate": null,
        "custom_name": null,
        "linked_at": "2026-09-14 10:12:00",
        "updated_at": "2026-09-14 10:12:00"
      }
    ]
  }
}

Champ

Signification

family

yalidine, procolis, ecotrack ou standalone.

credentials

Ce que api_id et api_token veulent dire pour ce transporteur, avec ses propres termes. api_token est absent pour un transporteur qui prend une seule valeur.

extra_fields

Les autres champs que ce transporteur accepte quand vous le liez, indexés par nom. Un tableau vide quand il n'y en a pas.

supports_rate_sync

Si POST /v1/shipping/rates/sync fonctionne avec ce transporteur.

linked

Si la boutique a ce transporteur.

source

store_delivery_providers pour un transporteur lié depuis la liste des transporteurs (cette API ou le dashboard), store_row pour un transporteur configuré à l'ancienne, directement dans les réglages de la boutique, null s'il n'est pas lié.

is_enabled

Si la liaison est activée.

is_default

Si c'est le transporteur par défaut de la boutique.

is_send_default

Le transporteur qu'utilise POST /v1/orders/{id}/send-to-delivery quand l'appel n'en nomme aucun.

delivery_tier, synced_tier, economic_available

Niveau de service de la famille Yalidine : celui choisi, celui utilisé par la dernière synchronisation des tarifs, et si le compte proposait le niveau économique lors de cette synchronisation.

stock_account, auto_validate, custom_name

Les champs supplémentaires enregistrés pour ce transporteur, null s'ils ne sont pas définis.

credentials_failed_at

Heure ISO 8601, définie quand le transporteur a refusé à plusieurs reprises les identifiants enregistrés. Les envois vers ce transporteur sont refusés tant qu'elle est définie. Lier de nouveau le transporteur l'efface.

linked_at, updated_at

YYYY-MM-DD HH:MM:SS. null pour un transporteur configuré dans les réglages de la boutique.

Ce que contiennent api_id et api_token

provider

api_id

api_token

yalidine, yalitec, guepex, easyandspeed, economiqua, wecan

API ID

API Token

zrexpress, abexexpress, leopardexpress, colilog, flashdelivery

Token

Key

zrexpressnew

API Key (secret key)

Tenant ID

noest

API Token

User GUID

colivraison

Public Key

Bearer Token

ecomdelivery

API Key

API Token

neardelivery

ApiKey

ApiSecret

maystro

API Token

aucun

zimou

Bearer Token

aucun

elogistia

API Key

aucun

mdm

x-api-key

aucun

customecotrack et tous les transporteurs de la famille ecotrack

Bearer Token

aucun

Champs supplémentaires, tous optionnels sauf indication contraire :

  • delivery_tier, famille Yalidine : express. guepex accepte aussi economic.

  • stock_account, famille ecotrack : préparer les commandes depuis le stock du transporteur.

  • auto_validate, noest : valider les commandes automatiquement chez le transporteur.

  • api_url et custom_name, customecotrack, tous deux requis pour lier : l'adresse Ecotrack https du transporteur (un hôte qui se termine par .ecotrack.dz, ou platform.dhd-dz.com ou app.conexlog-dz.com) et le nom à afficher pour lui, jusqu'à 100 caractères.

POST /v1/shipping/providers/test

Envoie des identifiants au transporteur et indique s'il les a acceptés. Rien n'est enregistré. Un api_id ou un api_token vide ou absent reprend la valeur enregistrée pour ce transporteur : vous pouvez donc retester un transporteur lié sans détenir ses identifiants.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key. Compte dans le budget transporteur.

Corps

Champ

Type

Requis

Notes

provider

string

oui

Un slug de GET /v1/shipping/providers.

api_id

string

sauf si enregistré

Premier identifiant.

api_token

string

sauf si enregistré

Second identifiant, pour les transporteurs qui en prennent deux.

api_url

string

customecotrack seulement

L'adresse Ecotrack du transporteur. Quand les identifiants enregistrés sont réutilisés, elle doit correspondre à l'adresse enregistrée.

delivery_tier

string

non

express ou economic. economic n'est accepté que pour guepex.

Requête

curl -X POST 'https://api.dzbuild.app/v1/shipping/providers/test' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: test-yalidine-1" \
  -d '{"provider": "yalidine", "api_id": "YOUR_API_ID", "api_token": "YOUR_API_TOKEN"}'

Réponse 200

Un transporteur qui refuse les identifiants répond aussi 200, avec ok: false et le message de la vérification chez le transporteur. resolved_provider n'est défini que pour zrexpressnew : la plateforme ZR Express qui a accepté la paire.

{
  "data": {
    "provider": "yalidine",
    "ok": true,
    "message": "تم الاتصال بنجاح",
    "resolved_provider": null,
    "saved": false
  }
}

POST /v1/shipping/providers

Lie un transporteur, ou réenregistre un transporteur lié. La plateforme teste d'abord les identifiants auprès du transporteur et n'enregistre rien s'il les refuse.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key. Compte dans le budget transporteur.

Corps

Les champs de l'appel de test, plus :

Champ

Type

Défaut

Notes

enabled

bool

true

Activer ou désactiver la liaison.

set_default

bool

false

Faire de ce transporteur celui par défaut de la boutique.

custom_name

string

aucun

customecotrack seulement, requis là. Les balises HTML sont retirées et le nom est coupé à 100 caractères.

stock_account

bool

valeur enregistrée

Famille ecotrack.

auto_validate

bool

valeur enregistrée

noest.

  • Un api_id ou un api_token vide garde la valeur enregistrée : un transporteur lié peut être réenregistré sans renvoyer ses identifiants.

  • Le premier transporteur que lie une boutique devient son transporteur par défaut. Dans la réponse, is_default vaut true seulement quand cet appel a fait du transporteur celui par défaut : un transporteur par défaut réenregistré sans set_default le reste alors que la réponse dit false. GET /v1/shipping/providers montre l'état réel.

  • zrexpress et zrexpressnew sont un seul transporteur : lier l'un remplace l'autre. Une paire zrexpressnew acceptée par l'ancienne plateforme ZR Express est enregistrée comme zrexpress, et provider dans la réponse l'indique.

Requête

curl -X POST 'https://api.dzbuild.app/v1/shipping/providers' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: link-yalidine-1" \
  -d '{"provider": "yalidine", "api_id": "YOUR_API_ID", "api_token": "YOUR_API_TOKEN", "set_default": true}'

Réponse 200

{
  "data": {
    "provider": "yalidine",
    "is_enabled": true,
    "is_default": true,
    "has_id": true,
    "has_token": true,
    "undoable": false,
    "note": "Courier credentials are never recorded, so linking cannot be undone. To revert, link the previous courier again or unlink this one."
  }
}

Un identifiant refusé répond 422 credentials_rejected avec le message du transporteur, et rien n'est enregistré.

POST /v1/shipping/providers/default

Fait d'un transporteur lié celui par défaut de la boutique. Les nouveaux envois en livraison partent vers lui.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key.

provider dans le corps nomme le transporteur. Seul un transporteur lié depuis la liste des transporteurs peut devenir celui par défaut ; un transporteur configuré dans les réglages de la boutique répond 404 provider_not_linked. Quand le transporteur choisi est désactivé, warning indique que les envois restent coupés jusqu'à ce qu'il soit réactivé.

Requête

curl -X POST 'https://api.dzbuild.app/v1/shipping/providers/default' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: default-noest-1" \
  -d '{"provider": "noest"}'

Réponse 200

{
  "data": {
    "provider": "noest",
    "is_default": true,
    "previous_default": "yalidine",
    "undoable": false,
    "warning": "New send-to-delivery pushes now go to \"noest\". "
  }
}

Confirmation avant une synchronisation des tarifs ou une déliaison

Une synchronisation écrase les prix du marchand et une déliaison retire des identifiants enregistrés : ces deux appels demandent donc une confirmation avant d'agir.

  1. Appelez sans confirmation. La réponse est 422 confirmation_required, et l'objet error ajoute confirm_token (usage unique), confirm_token_expires_in (600 secondes), action et will_change, le résumé à montrer au marchand.

  2. Une fois que le marchand approuve, refaites l'appel avec confirm_token dans le corps et une nouvelle Idempotency-Key. La première clé est liée au corps sans le jeton : la réutiliser répond 422 idempotency_key_reuse.

Un jeton fonctionne une seule fois, seulement pour la clé qui l'a reçu, et seulement tant que ce qu'il décrit n'a pas changé : la table des tarifs pour une synchronisation, et pour une déliaison le nombre de transporteurs liés et le fait que celui-ci soit ou non celui par défaut. Un jeton déjà utilisé, expiré ou qui ne correspond plus répond 422 confirmation_stale avec un nouveau jeton et un nouveau résumé.

Une clé qui n'est pas utilisée par l'assistant intégré au dashboard peut envoyer "confirm": true au lieu d'un jeton et sauter l'étape 1. Les clés utilisées par l'assistant doivent envoyer le jeton.

Voici la première réponse d'une synchronisation.

{
  "error": {
    "code": "confirmation_required",
    "message": "Syncing overwrites your own prices for every wilaya \"yalidine\" serves. Show the merchant the summary below; when they approve, re-send with the confirm_token.",
    "confirm_token": "cft_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "confirm_token_expires_in": 600,
    "action": "shipping.rates_sync:yalidine",
    "will_change": {
      "action": "Overwrite shipping rates from yalidine",
      "wilayas_at_risk": 58,
      "reversible": true,
      "note": "The prior prices are saved to the change log first, so this can be undone."
    }
  }
}

Pour une déliaison, will_change contient action, was_store_default, remaining_providers, consequence, reversible (false) et note.

POST /v1/shipping/rates/sync

Remplace les prix de la boutique par la grille de tarifs du transporteur, pour chaque wilaya de 1 à 58 que le transporteur tarifie. La synchronisation tourne en arrière-plan. Avant toute mise en file, toute la table des tarifs est conservée, et le change_id de la réponse annule la synchronisation.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key et une confirmation. Compte dans le budget transporteur.

Corps

Champ

Type

Requis

Notes

provider

string

oui

Un transporteur lié depuis la liste des transporteurs et activé. mdm et neardelivery n'ont pas de grille de tarifs.

confirm_token

string

voir plus haut

Tiré de la réponse confirmation_required.

confirm

bool

voir plus haut

true, pour les clés non utilisées par l'assistant.

Ce que change la synchronisation

  • Elle écrit home_price et desk_price et renseigne synced_provider et synced_at. Les interrupteurs et days d'une wilaya qui avait déjà un tarif restent tels quels. Une wilaya qui n'avait pas de tarif reçoit 3 jours.

  • Les transporteurs de la famille Yalidine ont besoin de la wilaya de la boutique, réglée avec wilaya_id dans PATCH /v1/store (voir Boutique). Sans elle, l'appel répond 422 store_wilaya_required.

  • Suivez le résultat avec GET /v1/shipping/rates : les tarifs écrits par la synchronisation nomment le transporteur dans synced_provider et portent un nouveau synced_at. Quand le transporteur n'envoie aucun prix, les tarifs restent tels quels.

  • Tant qu'une synchronisation du même transporteur tourne, l'appel répond 202 avec status: already_running, le sync_id de cette synchronisation et change_id: null, sans demander de confirmation.

  • Après une synchronisation réussie, le même transporteur peut être resynchronisé 5 minutes plus tard. Un appel plus tôt répond 429 sync_cooldown.

Requête

curl -X POST 'https://api.dzbuild.app/v1/shipping/rates/sync' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: sync-yalidine-2" \
  -d '{"provider": "yalidine", "confirm_token": "cft_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'

Réponse 202

{
  "data": {
    "status": "queued",
    "sync_id": "a1b2c3d4e5f6a7b8c9d0e1f2",
    "change_id": 500,
    "note": "The sync runs in the background and overwrites your prices for every wilaya this courier serves. Poll GET /v1/shipping/rates for the result; undo change_id to restore the prior prices."
  }
}

DELETE /v1/shipping/providers/{provider}

Délie un transporteur et retire ses identifiants de la boutique. C'est irréversible : pour envoyer de nouveau avec ce transporteur, liez-le de nouveau. Les colis déjà chez le transporteur restent suivis.

Auth : clé plateforme avec shipping:write. Nécessite Idempotency-Key et une confirmation.

  • provider dans le chemin est le slug du transporteur. Seul un transporteur lié depuis la liste des transporteurs peut être délié ici ; tout autre répond 404 provider_not_linked.

  • Le corps ne porte que la confirmation : confirm_token, ou confirm: true pour les clés non utilisées par l'assistant.

  • Quand le transporteur délié était celui par défaut, l'autre transporteur activé lié en premier devient celui par défaut.

  • S'il n'y en a aucun, aucun transporteur n'est par défaut et les envois en livraison s'arrêtent pour toute la boutique. La réponse porte alors new_default: null et send_to_delivery_active: false.

Requête

curl -X DELETE 'https://api.dzbuild.app/v1/shipping/providers/yalidine' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unlink-yalidine-2" \
  -d '{"confirm_token": "cft_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'

Réponse 200

{
  "data": {
    "provider": "yalidine",
    "unlinked": true,
    "undoable": false,
    "remaining_providers": 1,
    "new_default": "noest",
    "send_to_delivery_active": true,
    "warning": "The store default is now \"noest\"; new send-to-delivery pushes go there."
  }
}

GET /v1/shipping/coverage

Les wilayas, communes et stop desks que dessert un transporteur lié, d'après les données du transporteur lui-même. Un transporteur configuré dans les réglages de la boutique compte ici comme lié.

Auth : clé plateforme avec shipping:read.

Paramètres de requête

Param

Type

Défaut

Notes

provider

string

aucun

Le slug d'un transporteur lié. Sans lui, le transporteur marqué is_send_default, sinon le premier lié.

wilaya_id

int

0

0 donne un décompte par wilaya. 1 à 69 ajoute les communes de cette wilaya, ses stop desks et desk_send_allowed. Une valeur hors de 0 à 69 répond 400 bad_request.

Requête

curl 'https://api.dzbuild.app/v1/shipping/coverage?wilaya_id=16' \
  -H "Authorization: Bearer $DZ_KEY"

Réponse 200

Une commune et un stop desk sont montrés.

{
  "data": {
    "provider": "yalidine",
    "is_send_default": true,
    "knowledge_synced_at": "2026-10-05 03:12:44",
    "wilayas": [
      { "wilaya_id": 16, "name": "Alger", "communes": 57, "communes_home": 57, "communes_desk": 12, "desks": 9 }
    ],
    "wilaya_id": 16,
    "desk_send_allowed": true,
    "communes": [
      { "commune_id": 521, "name": "Alger Centre", "name_ar": "الجزائر الوسطى", "home": true, "desk": true }
    ],
    "desks": [
      { "desk_id": "160101", "name": "Agence Alger Centre", "address": "Alger Centre", "phone": null, "commune_id": 521 }
    ]
  }
}

Champ

Signification

knowledge_synced_at

La dernière fois que la plateforme a rafraîchi les communes et les stop desks de ce transporteur. null si elle ne l'a jamais fait.

wilayas

Par wilaya : le nombre de communes, combien reçoivent la livraison à domicile (communes_home) et au bureau (communes_desk), et le nombre de desks. Avec wilaya_id, seulement cette wilaya.

desk_send_allowed

Si POST /v1/orders/{id}/send-to-delivery accepte une commande au bureau vers cette wilaya avec ce transporteur. C'est la même vérification.

communes

commune_id est l'id de GET /v1/wilayas/{id}/communes, ou null quand la commune du transporteur n'a pas de correspondance, et name est alors le nom donné par le transporteur. home et desk disent quels types de livraison le transporteur propose là.

desks

Les stop desks du transporteur dans la wilaya. Le guide Thèmes & vitrines personnalisés montre comment les proposer au checkout.

Une boutique sans transporteur répond 422 no_courier_linked. Un provider que la boutique n'a pas lié répond 404 provider_not_linked.

Annuler les changements de tarifs et de réglages

POST /v1/shipping/rates, PATCH /v1/shipping/settings et une synchronisation des tarifs conservent les valeurs qu'ils remplacent : chacun peut donc être annulé avec POST /v1/changes/{id}/undo.

  • Une synchronisation répond avec son change_id. Les deux autres écritures non : trouvez le changement avec GET /v1/changes?entity=shipping.rates ou GET /v1/changes?entity=shipping.settings, du plus récent au plus ancien. Lister les changements demande store:read.

  • L'annulation demande shipping:write et une Idempotency-Key. L'annulation est elle-même un changement, undo_change_id, que vous pouvez annuler à son tour, sauf l'annulation d'une synchronisation, qui répond 422 nothing_to_restore. Voir Changements et annulation.

  • Annuler une écriture de tarifs supprime les tarifs des wilayas que cette écriture a créés. Annuler une synchronisation remet les wilayas qui avaient un tarif avant elle ; une wilaya ajoutée par la synchronisation garde son nouveau tarif.

  • L'annulation réécrit les valeurs conservées même si les tarifs ou les réglages ont changé depuis, dans le dashboard ou par l'API.

  • Un changement annulé une seconde fois répond 409 already_undone.

  • Le jeton d'une application installée ne peut ni lister ni annuler les changements : les deux répondent 403 forbidden.

curl -X POST 'https://api.dzbuild.app/v1/changes/500/undo' \
  -H "Authorization: Bearer $DZ_KEY" \
  -H "Idempotency-Key: undo-500"

{
  "data": {
    "undone": true,
    "change_id": 500,
    "entity": "shipping.rates",
    "undo_change_id": 510
  }
}

Erreurs

HTTP

Code

Cause

400

bad_request

Le corps n'est pas un objet JSON, rates manque ou n'est pas un objet, un id dans le chemin est mal formé, wilaya_id est hors de 0 à 69, ou Idempotency-Key manque ou est mal formé.

400

invalid_rates

rates est vide ou a plus de 69 wilayas, un tarif n'est pas un objet, ou un interrupteur n'est pas un booléen.

400, 422

invalid_wilaya

400 : une clé de rates n'est pas en chiffres seuls. 422 : aucune wilaya n'a cet id.

400, 422

invalid_price

400 : pas un nombre. 422 : négatif ou supérieur à 100000.

400, 422

invalid_days

400 : pas un nombre entier. 422 : hors de 0 à 60.

400

nothing_to_update

PATCH /v1/shipping/settings sans aucun de ses trois champs.

400

invalid_free_shipping

free_shipping n'est pas un booléen.

400, 422

invalid_threshold

400 : ni un nombre ni null. 422 : négatif ou supérieur à 99999999.99.

400

invalid_wilaya_mode

wilaya_mode n'est ni "58" ni "69".

422

wilaya_mode_69_unsupported

wilaya_mode vaut "69", qui se règle depuis le dashboard.

400

provider_required

provider manque.

400

credentials_required

Aucun api_id envoyé ni enregistré, ou aucun api_token pour un transporteur qui prend deux valeurs.

400

invalid_credentials_format

Des valeurs zrexpressnew qui contiennent des accolades JSON, des espaces ou des retours à la ligne, qui commencent par http, ou qui dépassent 128 caractères.

400

api_url_required, custom_name_required

customecotrack sans son adresse, ou une liaison sans son nom.

400, 422

invalid_delivery_tier

400 : ni express ni economic. 422 : economic pour un autre transporteur que guepex.

422

unsupported_provider

Le slug n'est pas dans GET /v1/shipping/providers.

422

invalid_api_url, api_url_mismatch

L'adresse customecotrack n'est pas une adresse Ecotrack https, ou diffère de celle enregistrée alors que les identifiants enregistrés sont réutilisés.

422

credentials_rejected

Le transporteur a refusé les identifiants. Rien n'a été enregistré.

422

rate_sync_unsupported

mdm et neardelivery n'ont pas de grille de tarifs.

422

provider_not_linked

Synchronisation : le transporteur n'est pas lié depuis la liste des transporteurs, ou est désactivé.

404

provider_not_linked

Défaut, déliaison ou couverture : la boutique n'a pas lié ce transporteur.

422

store_wilaya_required

Synchronisation d'un transporteur de la famille Yalidine avant que la wilaya de la boutique soit réglée.

422

confirmation_required, confirmation_stale

Voir la section sur la confirmation plus haut.

422

snapshot_too_large, snapshot_failed

Les tarifs précédents n'ont pas pu être conservés : l'écriture a été refusée plutôt que de devenir impossible à annuler.

422

no_courier_linked

Couverture pour une boutique sans transporteur.

422

shipping_not_available

Une écriture sur une boutique qui vend des produits numériques.

422

idempotency_key_reuse

La même Idempotency-Key avec un corps différent.

403

forbidden

La clé n'a pas la portée, par exemple « Missing scope: shipping:write », ou clé du marchand dont la boutique n'a pas de plan Enterprise actif.

404

not_found

Communes d'une wilaya qui n'existe pas.

404

store_not_found

La boutique de la clé n'existe plus.

429

sync_cooldown

Le même transporteur a été synchronisé il y a moins de 5 minutes. Le message indique combien de minutes il reste.

429

rate_limited, too_many_concurrent

Le budget transporteur ou la limite de requêtes de la boutique est épuisé. Voir Limites de taux.

503

sync_queue_failed

La synchronisation n'a pas pu démarrer et les tarifs n'ont pas changé. Réessayez plus tard.

500

server_error

Réessayez avec la même Idempotency-Key.

Avez-vous trouvé la réponse à votre question ?