Skip to main content

Shipping

Read and set delivery prices per wilaya and the free-shipping rules, link, test and sync couriers, check courier coverage, and list wilayas and communes.

Written by Support

These endpoints cover what the dashboard keeps on its shipping pages: the home and desk delivery price of each wilaya, the free-shipping rules, and the couriers linked to the store. They also serve the wilaya and commune lists a checkout form needs, and the communes and stop desks the store's courier serves.

Prices are in DZD. POST /v1/orders prices delivery from these rates and ignores any shipping cost sent in the body, so a custom storefront reads the rates to show an estimate and lets the order compute the charge. See Custom themes & storefronts.

Before you start

  • The key needs the shipping scopes. Keys created from the dashboard (Settings → API, /dashboard/api) have both. Scopes are frozen when a key is created, so an older key that lacks them answers 403 forbidden: create a new key from the dashboard.

  • A store that sells digital products has no shipping setup: every write on this page answers 422 shipping_not_available there.

  • Every write needs an Idempotency-Key header. See Idempotency.

  • Testing and linking a courier call the courier's servers during the request, and a rate sync calls them in the background. These three calls and POST /v1/orders/{id}/send-to-delivery share a per-store courier budget on top of the rate limits.

  • Rate and settings writes can be undone. Linking, unlinking and changing the default courier cannot. The undo section at the end of this page explains how.

  • Shipping reads are not cached at the edge: a GET sent right after a write returns the new values.

Scope

Description

shipping:read

Read shipping rates and settings, linked couriers, courier coverage and the wilaya and commune lists.

shipping:write

Change shipping rates and settings, and link, test, unlink or sync couriers.

GET /v1/wilayas

The wilayas the store delivers to, following its wilaya mode: 1 to 58 in the courier-compatible mode, 1 to 69 in 69-wilaya mode. Names come in Arabic, French and English. The whole list comes in one answer, without pagination.

Auth: platform key with shipping:read.

Request

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

Response 200

Two of the 58 wilayas are shown. mode_note is one English sentence about the 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

The communes of one wilaya, sorted by French name. Any wilaya from 1 to 69 is answered, whatever the store's wilaya mode. The whole list comes in one answer.

Auth: platform key with shipping:read.

This is the platform's own commune list. It does not say which communes a courier serves: GET /v1/shipping/coverage does.

Request

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

Response 200

Two of the 57 communes of wilaya 16 are shown.

{
  "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" }
    ]
  }
}

An id that is not all digits answers 400 bad_request. A wilaya that does not exist answers 404 not_found.

GET /v1/shipping/rates

The delivery price of every wilaya the store has a rate for, keyed by wilaya id. A wilaya without a rate is absent from rates.

Auth: platform key with shipping:read.

Request

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

Response 200

One wilaya is shown.

{
  "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
      }
    }
  }
}

Field

Meaning

wilaya_mode

58 or 69, the same value as in GET /v1/shipping/settings.

limits

The highest price and the highest days that POST /v1/shipping/rates accepts.

count

Number of wilayas in rates.

home_price, desk_price

Price of home delivery and of desk delivery, in DZD.

home_enabled, desk_enabled

Whether the store offers that delivery type in this wilaya.

days

Delivery time in days.

synced_provider, synced_at

The courier whose price list last wrote this rate, and when (YYYY-MM-DD HH:MM:SS). null when no courier sync wrote it.

POST /v1/shipping/rates

Creates or changes the rates of the wilayas you send. The other wilayas are not touched.

Auth: platform key with shipping:write. Requires Idempotency-Key.

Body

rates is an object keyed by wilaya id, written as plain digits ("16", not "016"), with 1 to 69 wilayas. Each value holds the fields to set, and every field is optional.

Field

Type

Notes

home_price

number

DZD, rounded to two decimals, 0 to 100000. A numeric string is accepted.

home_enabled

bool

true or false. 0, 1, "0" and "1" are accepted too.

desk_price

number

Same rules as home_price.

desk_enabled

bool

Same rules as home_enabled.

days

int

A whole number of days, 0 to 60.

A field you leave out, or send as null, keeps its stored value. A wilaya that had no rate starts from price 0, both delivery types on and 3 days.

Request

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}}}'

Response 200

rates holds the written wilayas only, as stored after the write.

{
  "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 }
    }
  }
}

The prior values are saved, so the write can be undone. The answer does not carry a change_id: see the undo section.

GET /v1/shipping/settings

The free-shipping rules and the wilaya mode.

Auth: platform key with shipping:read.

Request

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

Response 200

The answer also carries a notes object with two English sentences that restate the threshold rule and the wilaya mode rule. The example leaves it out.

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

Field

Meaning

free_shipping

true when delivery is free on every order.

free_shipping_threshold

Order subtotal in DZD from which delivery is free. 0 or null means no threshold.

free_shipping_threshold_active

true only when the threshold is above 0.

wilaya_mode

"58": the 58 wilayas couriers work with. "69": all 69 wilayas, a mode set from the dashboard.

PATCH /v1/shipping/settings

Changes one or more of the three settings. Send at least one; other fields are ignored.

Auth: platform key with shipping:write. Requires Idempotency-Key.

Body

Field

Type

Notes

free_shipping

bool

true or false. 0, 1, "0" and "1" are accepted too.

free_shipping_threshold

number or null

DZD, rounded to two decimals, 0 to 99999999.99. 0 or null turns the threshold off.

wilaya_mode

string

Only "58", which moves a store in 69-wilaya mode back to 58 wilayas. Switching to 69 wilayas is done from the shipping rates page of the dashboard (/dashboard/shipping) and answers 422 wilaya_mode_69_unsupported here.

Request

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}'

Response 200

The settings after the write, without notes. The prior values are saved, so the change can be undone.

GET /v1/shipping/providers

Every courier the platform supports, linked to the store or not, with what each one asks for when you link it. Credential values are never returned: has_id and has_token only say whether one is stored. The whole list comes in one answer.

Auth: platform key with shipping:read.

Request

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

Response 200

One courier is shown. The answer also carries a note sentence, left out here.

{
  "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"
      }
    ]
  }
}

Field

Meaning

family

yalidine, procolis, ecotrack or standalone.

credentials

What api_id and api_token mean for this courier, in the courier's own words. api_token is absent for a courier that takes one value.

extra_fields

The other fields this courier accepts when you link it, keyed by name. An empty array when there are none.

supports_rate_sync

Whether POST /v1/shipping/rates/sync works with this courier.

linked

Whether the store has this courier.

source

store_delivery_providers for a courier linked from the courier list (this API or the dashboard), store_row for a courier set up the older way, directly in the store settings, null when not linked.

is_enabled

Whether the link is turned on.

is_default

Whether this is the store's default courier.

is_send_default

The courier POST /v1/orders/{id}/send-to-delivery uses when the call names none.

delivery_tier, synced_tier, economic_available

Yalidine-family service tier: the one chosen, the one the last rate sync used, and whether the account offered the economic tier at that sync.

stock_account, auto_validate, custom_name

The extra fields stored for this courier, null when not set.

credentials_failed_at

ISO 8601 time, set when the courier kept refusing the stored credentials. Sends to this courier are refused while it is set. Linking the courier again clears it.

linked_at, updated_at

YYYY-MM-DD HH:MM:SS. null for a courier set in the store settings.

What api_id and api_token hold

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

none

zimou

Bearer Token

none

elogistia

API Key

none

mdm

x-api-key

none

customecotrack and every courier of the ecotrack family

Bearer Token

none

Extra fields, all optional unless stated:

  • delivery_tier, Yalidine family: express. guepex also takes economic.

  • stock_account, ecotrack family: fulfil orders from the courier's stock.

  • auto_validate, noest: validate orders automatically at the courier.

  • api_url and custom_name, customecotrack, both required to link: the courier's https Ecotrack address (a host ending in .ecotrack.dz, or platform.dhd-dz.com or app.conexlog-dz.com) and the name to show for it, up to 100 characters.

POST /v1/shipping/providers/test

Sends credentials to the courier and reports whether it accepted them. Nothing is saved. An empty or missing api_id or api_token uses the value stored for this courier, so you can re-test a linked courier without holding its credentials.

Auth: platform key with shipping:write. Requires Idempotency-Key. Counts against the courier budget.

Body

Field

Type

Required

Notes

provider

string

yes

A slug from GET /v1/shipping/providers.

api_id

string

unless stored

First credential.

api_token

string

unless stored

Second credential, for couriers that take two.

api_url

string

customecotrack only

The courier's Ecotrack address. When the stored credentials are reused, it must match the stored address.

delivery_tier

string

no

express or economic. economic is accepted for guepex only.

Request

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"}'

Response 200

A courier that refuses the credentials also answers 200, with ok: false and the courier check's message. resolved_provider is set for zrexpressnew only: the ZR Express platform that accepted the pair.

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

POST /v1/shipping/providers

Links a courier, or re-saves a linked one. The platform tests the credentials with the courier first and saves nothing when the courier refuses them.

Auth: platform key with shipping:write. Requires Idempotency-Key. Counts against the courier budget.

Body

The fields of the test call, plus:

Field

Type

Default

Notes

enabled

bool

true

Turn the link on or off.

set_default

bool

false

Make this courier the store's default.

custom_name

string

none

customecotrack only, required there. HTML tags are removed and the name is cut to 100 characters.

stock_account

bool

stored value

ecotrack family.

auto_validate

bool

stored value

noest.

  • An empty api_id or api_token keeps the stored value, so a linked courier can be re-saved without sending its credentials again.

  • The first courier a store links becomes its default. In the answer, is_default is true only when this call made the courier the default, so a default courier re-saved without set_default stays the default while the answer says false. GET /v1/shipping/providers shows the real state.

  • zrexpress and zrexpressnew are one courier: linking one replaces the other. A zrexpressnew pair accepted by the older ZR Express platform is saved as zrexpress, and provider in the answer says so.

Request

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}'

Response 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."
  }
}

A refused credential answers 422 credentials_rejected with the courier's message, and nothing is saved.

POST /v1/shipping/providers/default

Makes a linked courier the store's default. New sends to delivery go to it.

Auth: platform key with shipping:write. Requires Idempotency-Key.

provider in the body names the courier. Only a courier linked from the courier list can be made the default; a courier set in the store settings answers 404 provider_not_linked. When the chosen courier is turned off, warning says that sends stay off until it is turned on again.

Request

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"}'

Response 200

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

Confirmation for a rate sync or an unlink

A rate sync overwrites the merchant's own prices and an unlink removes stored credentials, so both calls ask for a confirmation before they act.

  1. Call without a confirmation. The answer is 422 confirmation_required, and the error object adds confirm_token (single use), confirm_token_expires_in (600 seconds), action and will_change, the summary to show the merchant.

  2. Once the merchant approves, repeat the call with confirm_token in the body and a new Idempotency-Key. The first key is bound to the body without the token, so reusing it answers 422 idempotency_key_reuse.

A token works once, only for the key that received it, and only while what it describes is unchanged: the rate table for a sync, and for an unlink the number of linked couriers and whether this one is the default. A token that was used, expired or no longer matches answers 422 confirmation_stale with a fresh token and summary.

A key that is not used by the in-dashboard assistant may send "confirm": true instead of a token and skip step 1. Keys used by the assistant must send the token.

A sync's first answer looks like this.

{
  "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."
    }
  }
}

For an unlink, will_change holds action, was_store_default, remaining_providers, consequence, reversible (false) and note.

POST /v1/shipping/rates/sync

Replaces the store's prices with the courier's own price list, for each wilaya from 1 to 58 the courier prices. The sync runs in the background. Before anything is queued, the whole rate table is saved, and change_id in the answer undoes the sync.

Auth: platform key with shipping:write. Requires Idempotency-Key and a confirmation. Counts against the courier budget.

Body

Field

Type

Required

Notes

provider

string

yes

A courier linked from the courier list and turned on. mdm and neardelivery have no price list.

confirm_token

string

see above

From the confirmation_required answer.

confirm

bool

see above

true, for keys not used by the assistant.

What the sync changes

  • It writes home_price and desk_price and sets synced_provider and synced_at. The on/off switches and days of a wilaya that already had a rate stay as they were. A wilaya that had no rate gets 3 days.

  • Yalidine-family couriers need the store's wilaya, set with wilaya_id in PATCH /v1/store (see Store). Without it the call answers 422 store_wilaya_required.

  • Follow the result with GET /v1/shipping/rates: the rates the sync wrote name the courier in synced_provider and carry a new synced_at. When the courier sends no prices, the rates stay as they were.

  • While a sync of the same courier is running, the call answers 202 with status: already_running, that sync's sync_id and change_id: null, without asking for a confirmation.

  • After a sync succeeds, the same courier can be synced again 5 minutes later. An earlier call answers 429 sync_cooldown.

Request

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"}'

Response 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}

Unlinks a courier and removes its credentials from the store. This cannot be undone: to send with that courier again, link it again. Parcels already at the courier keep being tracked.

Auth: platform key with shipping:write. Requires Idempotency-Key and a confirmation.

  • provider in the path is the courier's slug. Only a courier linked from the courier list can be unlinked here; any other answers 404 provider_not_linked.

  • The body carries only the confirmation: confirm_token, or confirm: true for keys not used by the assistant.

  • When the unlinked courier was the default, the other courier that is turned on and was linked first becomes the default.

  • When there is none, no courier is the default and sends to delivery stop for the whole store. The answer then has new_default: null and send_to_delivery_active: false.

Request

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"}'

Response 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

Which wilayas, communes and stop desks a linked courier serves, from the courier's own data. A courier set in the store settings counts as linked here.

Auth: platform key with shipping:read.

Query parameters

Param

Type

Default

Notes

provider

string

none

A linked courier's slug. Without it, the courier marked is_send_default, or else the first linked one.

wilaya_id

int

0

0 gives a count per wilaya. 1 to 69 adds that wilaya's communes, stop desks and desk_send_allowed. A value outside 0 to 69 answers 400 bad_request.

Request

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

Response 200

One commune and one desk are shown.

{
  "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 }
    ]
  }
}

Field

Meaning

knowledge_synced_at

When the platform last refreshed this courier's communes and desks. null when it never did.

wilayas

Per wilaya: the number of communes, how many of them get home delivery (communes_home) and desk delivery (communes_desk), and the number of desks. With wilaya_id, only that wilaya.

desk_send_allowed

Whether POST /v1/orders/{id}/send-to-delivery accepts a desk order to this wilaya with this courier. It is the same check.

communes

commune_id is the id from GET /v1/wilayas/{id}/communes, or null when the courier's commune has no match, and name is then the courier's own name. home and desk say which delivery types the courier offers there.

desks

The courier's stop desks in the wilaya. The Custom themes & storefronts guide shows how to offer them at checkout.

A store with no courier answers 422 no_courier_linked. A provider the store has not linked answers 404 provider_not_linked.

Undo rate and settings changes

POST /v1/shipping/rates, PATCH /v1/shipping/settings and a rate sync save the values they replace, so each can be undone with POST /v1/changes/{id}/undo.

  • A rate sync answers with its change_id. The other two writes do not: find the change with GET /v1/changes?entity=shipping.rates or GET /v1/changes?entity=shipping.settings, newest first. Listing changes needs store:read.

  • The undo needs shipping:write and an Idempotency-Key. The undo is itself a change, undo_change_id, which you can undo in turn, except the undo of a sync, which answers 422 nothing_to_restore. See Changes and undo.

  • Undoing a rate write deletes the rates of the wilayas that write created. Undoing a sync puts back the wilayas that had a rate before it; a wilaya the sync added keeps its new rate.

  • The undo writes back the saved values even when the rates or settings changed again since, in the dashboard or through the API.

  • A change undone a second time answers 409 already_undone.

  • An installed app's token cannot list or undo changes: both answer 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
  }
}

Errors

HTTP

Code

Cause

400

bad_request

The body is not a JSON object, rates is missing or not an object, an id in the path is malformed, wilaya_id is outside 0 to 69, or Idempotency-Key is missing or malformed.

400

invalid_rates

rates is empty or has more than 69 wilayas, a rate is not an object, or an on/off switch is not a boolean.

400, 422

invalid_wilaya

400: a rates key is not plain digits. 422: no wilaya has this id.

400, 422

invalid_price

400: not a number. 422: negative or above 100000.

400, 422

invalid_days

400: not a whole number. 422: outside 0 to 60.

400

nothing_to_update

PATCH /v1/shipping/settings without any of its three fields.

400

invalid_free_shipping

free_shipping is not a boolean.

400, 422

invalid_threshold

400: not a number or null. 422: negative or above 99999999.99.

400

invalid_wilaya_mode

wilaya_mode is neither "58" nor "69".

422

wilaya_mode_69_unsupported

wilaya_mode is "69", which is set from the dashboard.

400

provider_required

provider is missing.

400

credentials_required

No api_id was sent or stored, or no api_token for a courier that takes two values.

400

invalid_credentials_format

zrexpressnew values that hold JSON braces, spaces or line breaks, start with http, or run over 128 characters.

400

api_url_required, custom_name_required

customecotrack without its address, or a link without its name.

400, 422

invalid_delivery_tier

400: neither express nor economic. 422: economic for a courier other than guepex.

422

unsupported_provider

The slug is not in GET /v1/shipping/providers.

422

invalid_api_url, api_url_mismatch

The customecotrack address is not an https Ecotrack address, or differs from the stored one while the stored credentials are reused.

422

credentials_rejected

The courier refused the credentials. Nothing was saved.

422

rate_sync_unsupported

mdm and neardelivery have no price list.

422

provider_not_linked

Rate sync: the courier is not linked from the courier list, or is turned off.

404

provider_not_linked

Default, unlink or coverage: the store has not linked this courier.

422

store_wilaya_required

Yalidine-family rate sync before the store's wilaya is set.

422

confirmation_required, confirmation_stale

See the confirmation section above.

422

snapshot_too_large, snapshot_failed

The prior rates could not be saved, so the write was refused rather than made impossible to undo.

422

no_courier_linked

Coverage for a store with no courier.

422

shipping_not_available

A write on a store that sells digital products.

422

idempotency_key_reuse

The same Idempotency-Key with a different body.

403

forbidden

The key lacks the scope, for example "Missing scope: shipping:write", or a merchant key whose store is not on an active Enterprise plan.

404

not_found

Communes of a wilaya that does not exist.

404

store_not_found

The key's store no longer exists.

429

sync_cooldown

The same courier was synced less than 5 minutes ago. The message says how many minutes are left.

429

rate_limited, too_many_concurrent

The courier budget or the store's request limit is spent. See Rate limits.

503

sync_queue_failed

The sync could not be started and the rates did not change. Retry later.

500

server_error

Retry with the same Idempotency-Key.

Did this answer your question?