Skip to main content

Shipping

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.
ScopeDescription
shipping:readRead shipping rates and settings, linked couriers, courier coverage and the wilaya and commune lists.
shipping:writeChange 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
}
}
}
}
FieldMeaning
wilaya_mode58 or 69, the same value as in GET /v1/shipping/settings.
limitsThe highest price and the highest days that POST /v1/shipping/rates accepts.
countNumber of wilayas in rates.
home_price, desk_pricePrice of home delivery and of desk delivery, in DZD.
home_enabled, desk_enabledWhether the store offers that delivery type in this wilaya.
daysDelivery time in days.
synced_provider, synced_atThe 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.

FieldTypeNotes
home_pricenumberDZD, rounded to two decimals, 0 to 100000. A numeric string is accepted.
home_enabledbooltrue or false. 0, 1, "0" and "1" are accepted too.
desk_pricenumberSame rules as home_price.
desk_enabledboolSame rules as home_enabled.
daysintA 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"
}
}
FieldMeaning
free_shippingtrue when delivery is free on every order.
free_shipping_thresholdOrder subtotal in DZD from which delivery is free. 0 or null means no threshold.
free_shipping_threshold_activetrue 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​

FieldTypeNotes
free_shippingbooltrue or false. 0, 1, "0" and "1" are accepted too.
free_shipping_thresholdnumber or nullDZD, rounded to two decimals, 0 to 99999999.99. 0 or null turns the threshold off.
wilaya_modestringOnly "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"
}
]
}
}
FieldMeaning
familyyalidine, procolis, ecotrack or standalone.
credentialsWhat 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_fieldsThe other fields this courier accepts when you link it, keyed by name. An empty array when there are none.
supports_rate_syncWhether POST /v1/shipping/rates/sync works with this courier.
linkedWhether the store has this courier.
sourcestore_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_enabledWhether the link is turned on.
is_defaultWhether this is the store's default courier.
is_send_defaultThe courier POST /v1/orders/{id}/send-to-delivery uses when the call names none.
delivery_tier, synced_tier, economic_availableYalidine-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_nameThe extra fields stored for this courier, null when not set.
credentials_failed_atISO 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_atYYYY-MM-DD HH:MM:SS. null for a courier set in the store settings.

What api_id and api_token hold​

providerapi_idapi_token
yalidine, yalitec, guepex, easyandspeed, economiqua, wecanAPI IDAPI Token
zrexpress, abexexpress, leopardexpress, colilog, flashdeliveryTokenKey
zrexpressnewAPI Key (secret key)Tenant ID
noestAPI TokenUser GUID
colivraisonPublic KeyBearer Token
ecomdeliveryAPI KeyAPI Token
neardeliveryApiKeyApiSecret
maystroAPI Tokennone
zimouBearer Tokennone
elogistiaAPI Keynone
mdmx-api-keynone
customecotrack and every courier of the ecotrack familyBearer Tokennone

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​

FieldTypeRequiredNotes
providerstringyesA slug from GET /v1/shipping/providers.
api_idstringunless storedFirst credential.
api_tokenstringunless storedSecond credential, for couriers that take two.
api_urlstringcustomecotrack onlyThe courier's Ecotrack address. When the stored credentials are reused, it must match the stored address.
delivery_tierstringnoexpress 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:

FieldTypeDefaultNotes
enabledbooltrueTurn the link on or off.
set_defaultboolfalseMake this courier the store's default.
custom_namestringnonecustomecotrack only, required there. HTML tags are removed and the name is cut to 100 characters.
stock_accountboolstored valueecotrack family.
auto_validateboolstored valuenoest.
  • 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\". "
}
}

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​

FieldTypeRequiredNotes
providerstringyesA courier linked from the courier list and turned on. mdm and neardelivery have no price list.
confirm_tokenstringsee aboveFrom the confirmation_required answer.
confirmboolsee abovetrue, 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​

ParamTypeDefaultNotes
providerstringnoneA linked courier's slug. Without it, the courier marked is_send_default, or else the first linked one.
wilaya_idint00 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 }
]
}
}
FieldMeaning
knowledge_synced_atWhen the platform last refreshed this courier's communes and desks. null when it never did.
wilayasPer 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_allowedWhether POST /v1/orders/{id}/send-to-delivery accepts a desk order to this wilaya with this courier. It is the same check.
communescommune_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.
desksThe 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​

HTTPCodeCause
400bad_requestThe 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.
400invalid_ratesrates is empty or has more than 69 wilayas, a rate is not an object, or an on/off switch is not a boolean.
400, 422invalid_wilaya400: a rates key is not plain digits. 422: no wilaya has this id.
400, 422invalid_price400: not a number. 422: negative or above 100000.
400, 422invalid_days400: not a whole number. 422: outside 0 to 60.
400nothing_to_updatePATCH /v1/shipping/settings without any of its three fields.
400invalid_free_shippingfree_shipping is not a boolean.
400, 422invalid_threshold400: not a number or null. 422: negative or above 99999999.99.
400invalid_wilaya_modewilaya_mode is neither "58" nor "69".
422wilaya_mode_69_unsupportedwilaya_mode is "69", which is set from the dashboard.
400provider_requiredprovider is missing.
400credentials_requiredNo api_id was sent or stored, or no api_token for a courier that takes two values.
400invalid_credentials_formatzrexpressnew values that hold JSON braces, spaces or line breaks, start with http, or run over 128 characters.
400api_url_required, custom_name_requiredcustomecotrack without its address, or a link without its name.
400, 422invalid_delivery_tier400: neither express nor economic. 422: economic for a courier other than guepex.
422unsupported_providerThe slug is not in GET /v1/shipping/providers.
422invalid_api_url, api_url_mismatchThe customecotrack address is not an https Ecotrack address, or differs from the stored one while the stored credentials are reused.
422credentials_rejectedThe courier refused the credentials. Nothing was saved.
422rate_sync_unsupportedmdm and neardelivery have no price list.
422provider_not_linkedRate sync: the courier is not linked from the courier list, or is turned off.
404provider_not_linkedDefault, unlink or coverage: the store has not linked this courier.
422store_wilaya_requiredYalidine-family rate sync before the store's wilaya is set.
422confirmation_required, confirmation_staleSee the confirmation section above.
422snapshot_too_large, snapshot_failedThe prior rates could not be saved, so the write was refused rather than made impossible to undo.
422no_courier_linkedCoverage for a store with no courier.
422shipping_not_availableA write on a store that sells digital products.
422idempotency_key_reuseThe same Idempotency-Key with a different body.
403forbiddenThe key lacks the scope, for example "Missing scope: shipping:write", or a merchant key whose store is not on an active Enterprise plan.
404not_foundCommunes of a wilaya that does not exist.
404store_not_foundThe key's store no longer exists.
429sync_cooldownThe same courier was synced less than 5 minutes ago. The message says how many minutes are left.
429rate_limited, too_many_concurrentThe courier budget or the store's request limit is spent. See Rate limits.
503sync_queue_failedThe sync could not be started and the rates did not change. Retry later.
500server_errorRetry with the same Idempotency-Key.
This page for AI toolsView as MarkdownOpen in ChatGPTOpen in Claude