# Journal des modifications

L'API est en pilote. Les clés API personnelles doivent appartenir à une boutique disposant d'un plan Enterprise actif, sans quoi chaque appel renvoie `403` ; les jetons d'application installée fonctionnent avec tous les plans. `https://api.dzbuild.app` est le seul hôte pris en charge.

## v1.12 - 2026-10-28 (pilote)[​](#v112---2026-10-28-pilote "Lien direct vers v1.12 - 2026-10-28 (pilote)")

* ✨ **Familles de variantes pour DZBuild POS.** Avec un jeton de caisse, `GET /v1/products` et `GET /v1/products/{id}` renvoient `variants` : les groupes, le mode de stock et un élément par variante avec sa `key`, son sku, son barcode, son prix, son stock et le `external_id` de la caisse. `POST /v1/products/batch` accepte un bloc `variants` et répond `variants` avec `price_online` pour chacune. Un élément du lot peut nommer dans `id` le produit de la boutique auquel il correspond, pour qu'un produit importé par la caisse ne soit pas créé une seconde fois. Voir [DZBuild POS](https://dzbuild.com/fr/fr/api-docs/pos.md).
* ✨ **Stock par variante depuis la caisse.** `POST /v1/inventory/adjustments/batch` accepte `target: "variant"` avec `variant_external_id`, avec quatre nouvelles erreurs d'élément : `unknown_variant`, `variant_gone`, `variant_stock_mode` et `variant_mismatch`.
* ✨ **Les événements `inventory.level_changed` et les lignes de commande de la caisse portent `variant_key` et `variant_external_id`**, `null` au niveau du produit.
* ⚠️ **Aucun changement pour une caisse qui n'envoie pas de bloc `variants`** : les variantes du produit en ligne restent telles quelles, et `target: "product"` sur un produit avec un stock par variante répond toujours `variant_product`.

## v1.10 - 2026-10-09 (pilote)[​](#v110---2026-10-09-pilote "Lien direct vers v1.10 - 2026-10-09 (pilote)")

* ✨ **DZBuild POS.** La caisse Windows gratuite se relie à une boutique par OAuth, avec la découverte sur `https://dzbuild.com/.well-known/oauth-authorization-server`, et appelle ses propres endpoints avec un jeton de caisse : `GET /v1/me`, `POST /v1/devices` et les heartbeats, `GET /v1/locations` et `POST /v1/locations`, `POST /v1/products/batch`, `POST /v1/media/uploads`, `POST /v1/inventory/adjustments/batch`, `POST /v1/pos/sales`, `POST /v1/pos/sales/{sale_id}/refunds`, `POST /v1/pos/closures`, `POST /v1/orders/{id}/claim` et `GET /v1/events`. Les quatre chemins de sauvegarde répondent `501 not_implemented`. Les clés API personnelles et les jetons d'application reçoivent `403` sur les chemins réservés à la caisse. Voir [DZBuild POS](https://dzbuild.com/fr/fr/api-docs/pos.md).
* ✨ **`GET /v1/store` renvoie `currency` (`DZD`), `stock_deduction` (`on_create` ou `on_confirm`), `plan` et `plan_limits`.** Un plan payant expiré se lit `free`, et `plan_limits.active_products` vaut `null` quand le plan n'a pas de plafond.
* ⚠️ **Aucun changement pour `POST /v1/products` au plafond du plan** : il répond toujours `400 bad_request` avec le même message. Le nouveau code `402 product_limit_reached` concerne seulement l'appel par lot de la caisse.

## v1.9 - 2026-10-08 (pilote)[​](#v19---2026-10-08-pilote "Lien direct vers v1.9 - 2026-10-08 (pilote)")

* ✨ **Champs de la barre d'achat.** `PATCH /v1/store/design` accepte `buybar_show_mobile`, `buybar_show_qty`, `fc_show_qty` et `product_button_size` (`normal` ou `large`) sur tous les plans : ils affichent ou masquent la barre d'achat du téléphone et la quantité dans la barre et dans le formulaire Fast Checkout, et règlent la taille des boutons d'achat. Voir [Boutique](https://dzbuild.com/fr/fr/api-docs/resources/store.md).
* ✨ **`GET /v1/store` renvoie `store_theme`, `fast_checkout_theme` et `variant_card_style`**, les trois clés utilisées, en lecture seule.
* ✨ **`GET /v1/themes` liste les thèmes Fast Checkout et les styles de variantes** dans `fast_checkout` et `variant_styles`, chacun avec son plan, si la boutique peut l'utiliser et celui qui est utilisé. Voir [Thèmes](https://dzbuild.com/fr/fr/api-docs/resources/themes.md).
* ✨ **Les écritures de design et de thème renvoient `change_id`.** `PATCH /v1/store/design`, `POST /v1/store/theme`, `POST /v1/store/fast-checkout-theme` et `POST /v1/store/variant-style` portent l'id à envoyer à `POST /v1/changes/{id}/undo`.

## v1.8.1 - 2026-10-02 (pilote)[​](#v181---2026-10-02-pilote "Lien direct vers v1.8.1 - 2026-10-02 (pilote)")

* ⚠️ **Supprimer un produit utilisé par une page de destination est refusé** avec `409 product_in_use_by_landing_page`. L'erreur liste les pages dans `landing_pages[]` avec `id`, `title` et `slug`. Supprimez d'abord la page de destination, ou rattachez-lui un autre produit avec `PATCH /v1/landing-pages/{id}`, puis supprimez le produit. Voir [Produits](https://dzbuild.com/fr/fr/api-docs/resources/products.md).

## v1.8 - 2026-09-28 (pilote)[​](#v18---2026-09-28-pilote "Lien direct vers v1.8 - 2026-09-28 (pilote)")

* ✨ **Sections de la page d'accueil.** `GET /v1/store/home-layout` lit les sections de la page d'accueil d'une boutique et les types de section que son thème accepte. `POST /v1/store/home-layout/sections` en ajoute une, `PATCH` et `DELETE /v1/store/home-layout/sections/{id}` en modifient ou en suppriment une, `POST /v1/store/home-layout/reorder` fixe l'ordre et `PUT /v1/store/home-layout` remplace toute la liste. Dix types de section peuvent être ajoutés sur chaque thème, dont `category-products`, `banner`, `faq` et `video`. Les réglages d'image prennent une image envoyée depuis le dashboard : l'API ne peut pas encore en envoyer. Ces endpoints utilisent `store:read` et `store:write`, les clés existantes fonctionnent donc. Voir [Sections de la page d'accueil](https://dzbuild.com/fr/fr/api-docs/resources/home-layout.md).
* ✨ **Chaque écriture de la mise en page de l'accueil peut être annulée, ajout de section compris.** La réponse porte un `change_id` pour `POST /v1/changes/{id}/undo`, qui répond `409 layout_changed` si la page a encore changé depuis.
* ⚠️ **Les écritures de la mise en page de l'accueil ont leur propre budget** : 30 par minute et 5 en même temps par boutique. Voir [Limites de taux](https://dzbuild.com/fr/fr/api-docs/rate-limits.md).

## v1.7 - 2026-09-26 (pilote)[​](#v17---2026-09-26-pilote "Lien direct vers v1.7 - 2026-09-26 (pilote)")

* ✨ **Applications tierces.** Une application s'installe sur une boutique via OAuth et appelle l'API avec un jeton d'installation, quel que soit le plan. Ses appels peuvent recevoir quatre nouveaux codes `403`, `app_uninstalled`, `app_suspended`, `app_not_approved` et `app_plan_required`, et chaque installation a sa propre limite de 120 requêtes par minute, vérifiée avant celle de la boutique. Voir [Erreurs](https://dzbuild.com/fr/fr/api-docs/errors.md).
* ⚠️ **L'`expires_at` d'une clé est désormais appliqué** : une fois la date passée, la clé répond `401`.
* ⚠️ **Les clés Copilot et de connecteur ne gèrent pas les clés** : elles reçoivent `403` sur `/v1/keys`.
* ✨ **Les nouvelles clés portent `analytics:read`** ; les clés plus anciennes gardent les portées reçues à leur création.
* ⚠️ **Les webhooks API v1 sont signés avec le secret propre à chaque webhook** (`X-DZ-Signature: t=<ts>,v1=<hmac>`), l'enregistrement n'accepte que `https://`, `408` et `429` sont réessayés, et tout autre 4xx ou 3xx passe aussitôt en file morte. Les webhooks enregistrés avant doivent l'être de nouveau. Voir [Vérifier les signatures](https://dzbuild.com/fr/fr/api-docs/webhooks/verifying-signatures.md).
* ✨ **`PUT` accepte une `Idempotency-Key` facultative** et suit alors les mêmes règles de rejeu.
* ⚠️ **Le rejeu idempotent s'applique sur les deux hôtes**, et réutiliser une clé avec un autre corps renvoie `422 idempotency_key_reuse`. Voir [Idempotence](https://dzbuild.com/fr/fr/api-docs/idempotency.md).
* ⚠️ **Pas de preflight CORS** : une requête `OPTIONS` reçoit le `401` habituel, et l'API sert uniquement aux appels de serveur à serveur.
* ⚠️ **Les refus traversent la passerelle tels quels** : un `403` d'application, ou un `429`, venant de `api.dzbuild.app` arrive avec son vrai statut et son vrai corps au lieu d'un `401`.

## v1.6 - 2026-09-26 (pilote)[​](#v16---2026-09-26-pilote "Lien direct vers v1.6 - 2026-09-26 (pilote)")

* ✨ **Messages WhatsApp via l'API.** `GET /v1/whatsapp/templates` liste les modèles de messages de commande validés pour la plateforme avec leur statut de validation, `GET /v1/whatsapp/balance` lit le solde WhatsApp de la boutique, `GET /v1/whatsapp/messages` liste les messages envoyés aux acheteurs, et `POST /v1/orders/{id}/whatsapp` envoie un modèle à l'acheteur d'une commande, débité du solde. L'addon WhatsApp Sender doit être activé. Les deux nouvelles portées sont `whatsapp:read` et `whatsapp:send`. Voir [Messages WhatsApp](https://dzbuild.com/fr/fr/api-docs/resources/whatsapp.md).
* ⚠️ **Les portées sont figées à la création de la clé** : une clé créée avant cette version n'a pas les deux nouvelles portées. Créez une nouvelle clé pour les utiliser.
* ⚠️ **Un réessai après `402 no_credit` ou un `422` exige une nouvelle `Idempotency-Key`.** La première réponse est conservée 24 heures et rejouée pour la même clé et le même corps : recharger le solde ou corriger la commande ne change rien pour l'ancienne clé.
* ✨ **Chaque message de `GET /v1/whatsapp/messages` porte `billing`** : `charged` une fois facturé par WhatsApp, `free` une fois son crédit revenu sur le solde, `null` tant que le résultat n'est pas encore connu.

## v1.5 - 2026-09-23 (pilote)[​](#v15---2026-09-23-pilote "Lien direct vers v1.5 - 2026-09-23 (pilote)")

* ⚠️ Les retries des webhooks s'espacent désormais (1 min, 5 min, 30 min, 2 h) et s'arrêtent après 5 tentatives échouées ; les timeouts et les échecs DNS/TLS sont réessayés au lieu d'être abandonnés.

## v1.4 — 2026-09-05 (pilote)[​](#v14--2026-09-05-pilote "Lien direct vers v1.4 — 2026-09-05 (pilote)")

* ✨ **Les commandes peuvent être écrites.** `POST /v1/orders` crée une commande, `PATCH /v1/orders/{id}` change son statut, `POST /v1/orders/{id}/cancel` l'annule et `POST /v1/orders/{id}/send-to-delivery` confie un colis au transporteur de la boutique. Les deux nouvelles portées sont `orders:write` et `delivery:send`.
* ⚠️ **Les portées sont figées à la création de la clé** : une clé existante n'obtient pas les nouvelles portées. Créez une nouvelle clé, ou reconnectez le connecteur, pour les utiliser. Une clé créée depuis le dashboard reçoit `orders:write`. Les clés créées depuis le dashboard ou via `POST /v1/keys` ne reçoivent jamais `delivery:send` : elles ne peuvent donc pas appeler `send-to-delivery`.
* ⚠️ **Un envoi au transporteur exige toujours une confirmation émise par le serveur.** Le premier appel renvoie `409 confirmation_required` avec un jeton à usage unique et un récapitulatif nommant le client, le téléphone, la destination, le total et le transporteur ; seul ce jeton envoie le colis. Un `confirm: true` dans le corps n'est accepté sur ce point d'entrée pour aucun appelant. Une commande déjà envoyée est refusée par `409 already_sent`.
* ⚠️ **Le calcul monétaire d'une commande vient désormais du serveur.** Les valeurs `shipping_cost` et `payment_fee` envoyées par l'appelant sont ignorées : le coût de livraison vient de la table de tarifs de la boutique pour cette wilaya et ce type de livraison, et `discount` est plafonné au sous-total plus la livraison. Les prix des articles fonctionnaient déjà ainsi.
* ✨ **`GET /v1/shipping/coverage`** indique si le transporteur lié dessert une commune et s'il possède un bureau dans une wilaya, avec la fraîcheur des données du transporteur.
* ✨ **`GET /v1/shipping/providers`** signale aussi un transporteur configuré directement sur la boutique plutôt qu'ajouté depuis la liste des fournisseurs, ainsi que `is_send_default`, `economic_available`, `synced_tier`, `stock_account`, `auto_validate` et `custom_name`. Les identifiants et les adresses ne sont jamais renvoyés.
* ✨ **`GET /v1/landing-pages/{id}/check`** signale ce qu'un acheteur rencontrerait sur la page : un formulaire de commande sans produit, aucun formulaire, plusieurs, ou une section pointant vers un produit d'une autre boutique.
* ⚠️ **Publier une page de destination cassée est refusé.** `PATCH /v1/landing-pages/{id}` avec `status: active` échoue avec `landing_page_has_no_product` quand la page prendrait des commandes à zéro. Modifier une page déjà en ligne reste possible, pour pouvoir la réparer. L'écriture d'une section nommant un `product_id` d'une autre boutique est refusée comme erreur de validation.
* ⚠️ **`PATCH /v1/landing-page-sections/{id}` avec `replace: true`** réinstalle désormais les réglages par défaut du type de section sous l'objet que vous envoyez : une clé omise revient à sa valeur par défaut au lieu de disparaître de la page.
* ✨ **`GET /v1/connection`** liste les boutiques couvertes par une même autorisation et celle qui est active ; `POST /v1/connection/active-store` déplace le pointeur. Ce pointeur n'est pas une permission : une boutique que le marchand n'a jamais approuvée n'a pas de clé et ne peut pas être sélectionnée.

## v1.3 — 2026-08-13 (pilote)[​](#v13--2026-08-13-pilote "Lien direct vers v1.3 — 2026-08-13 (pilote)")

* ✨ **Gestion des clés en libre-service** — les propriétaires de boutiques Enterprise peuvent désormais générer et révoquer leurs clés API depuis le dashboard marchand, dans **Paramètres → API** (`/dashboard/api`). Les secrets ne sont affichés qu'une fois, à la création.
* ⚠️ La limite de taux par minute est désormais appliquée **par boutique**, partagée entre toutes les clés de la boutique (auparavant par clé). Le plafond Enterprise reste inchangé à **600 requêtes/minute**.
* ⚠️ Une boutique peut désormais détenir au plus **3 clés actives** (contre 20), quel que soit le canal de création — dashboard, `POST /v1/keys` ou support. Révoquer une clé libère sa place.

## v1.2 — 2026-08-13 (pilote)[​](#v12--2026-08-13-pilote "Lien direct vers v1.2 — 2026-08-13 (pilote)")

* ⚠️ **L'API est désormais réservée au plan Enterprise.** Les clés ne s'authentifient que tant que leur boutique est sur un **plan Enterprise actif** ; tout autre plan — ainsi qu'un abonnement Enterprise expiré — reçoit `403 forbidden` (« API access requires an active Enterprise plan »). Les nouvelles clés ne peuvent être créées que pour des boutiques Enterprise. Les clés existantes des boutiques non-Enterprise cessent de fonctionner immédiatement mais ne sont pas supprimées : elles reprennent dès que la boutique passe sur (ou renouvelle) Enterprise, sans rien à réémettre.
* ⚠️ Les tiers de limite de taux hérités Free / Pro / Unlimited sont retirés. Le plafond Enterprise reste **600 requêtes/minute** par clé sans plafond mensuel ; les surcharges par boutique du support s'appliquent toujours.

## v1.1 — 2026-08-12 (pilote)[​](#v11--2026-08-12-pilote "Lien direct vers v1.1 — 2026-08-12 (pilote)")

* ✨ **Images produits via l'API** — `POST /v1/products/{id}/images` ajoute une image depuis une URL `https` publique (DZBuild la télécharge, l'optimise et l'héberge), `PATCH .../images/{image_id}` définit le texte alternatif, l'ordre d'affichage et l'image principale, `DELETE .../images/{image_id}` en supprime une. Les URL en double sont dédupliquées, la première image devient automatiquement l'image principale, maximum 20 images par produit.
* ✨ **`PUT /v1/products/{id}/variants`** — créez et gérez les groupes de variantes, leurs options et le stock par combinaison en un seul appel (remplacement complet). Les champs `price_adjustment`, `stock`, `sku`, `image_id` et `show_as_card` par option sont désormais modifiables, et les indicateurs de mode de stock sont réglés pour vous.
* ✨ `GET /v1/products/{id}` renvoie maintenant le bloc **`combinations`** ainsi que les champs d'option complets (`price_adjustment`, `sku`, `show_as_card`, `sort_order`, `is_active`) et le `alt_text` des images.
* ⚠️ **Changement notable :** `primary_image` et `images[].url` renvoient désormais des **URL CDN complètes** au lieu de noms de fichiers nus. Si votre code ajoute le préfixe manuellement, retirez cette logique.

## v1.0.1 — 2026-05-02 (pilote)[​](#v101--2026-05-02-pilote "Lien direct vers v1.0.1 — 2026-05-02 (pilote)")

* ✨ **`POST /v1/orders`** — création de commandes via l'API. Conçu pour les thèmes personnalisés, les vitrines headless, les apps mobiles et l'automatisation des revendeurs. Tarification des lignes autoritative côté serveur ; support complet des variantes ; idempotent.
* 📚 Nouveau guide : **Thèmes & vitrines personnalisés** — build de bout en bout : catalogue, UI variantes, panier, checkout, intégration webhooks.
* 📚 Nouveau guide : **Pour revendeurs** — gérer plusieurs boutiques clients, opérations en bulk, white-label, modèles de facturation.
* 📚 Nouveau guide : **Environnement & .env** — stockage sécurisé des credentials pour Node, Python, PHP, Go, Vercel, Cloudflare, AWS, Docker/K8s, GitHub Actions.
* 📚 Référence `Orders` enrichie — documentation complète des variantes : stock par variante, par combinaison, variantes en cascade, variantes image-texte, offres multi-pièces.

## v1.0 — 2026-04-30 (pilote)[​](#v10--2026-04-30-pilote "Lien direct vers v1.0 — 2026-04-30 (pilote)")

* 🎉 Lancement initial en pilote.
* Authentification, limitation de taux et cache de lecture, par clé.
* Endpoints de lecture : boutique / produits / commandes / clients / landing pages.
* Endpoints d'écriture avec idempotence : produits / commandes / landing pages.
* Ingestion asynchrone de `/v1/signups` et `/v1/events` (`202 Accepted`).
* Webhooks sortants avec réessais automatiques.
