Changements et annulation
La plupart des écritures de configuration faites par l'API sont enregistrées comme changements : réglages, design et thème de la boutique, sections de la page d'accueil, catégories, stock, codes promo, pixels, tarifs et réglages de livraison, et sections de landing page. Chaque changement garde les valeurs qu'il a remplacées, et une annulation les réécrit en passant par les mêmes contrôles que l'écriture d'origine. Les écritures faites sur la boutique par Copilot, par un assistant IA connecté (Claude ou ChatGPT) ou par une application installée sont aussi enregistrées. Les changements enregistrés dans le dashboard ne le sont pas.
Les trois endpoints ci-dessous listent les changements, en lisent un en entier et en annulent un. Les écritures sous /v1/store/home-layout et la synchronisation des tarifs d'un transporteur répondent avec un change_id. Pour les autres écritures, retrouvez le changement avec GET /v1/changes.
Ce qui est enregistré
entity | Enregistré par | entity_id | Portée pour le lire en entier | Portée pour l'annuler |
|---|---|---|---|---|
store.settings | PATCH /v1/store | settings | store:read | store:write |
store.design | PATCH /v1/store/design | design | store:read | store:write |
store.theme | POST /v1/store/theme, POST /v1/store/fast-checkout-theme, POST /v1/store/variant-style | theme | store:read | store:write |
store.home_sections | PATCH /v1/store/home-sections | home_sections | store:read | store:write |
store.home_layout | Toute écriture sous /v1/store/home-layout | layout | store:read | store:write |
category | POST /v1/categories, PATCH et DELETE /v1/categories/{id} | Id de la catégorie | products:read | products:write |
stock | POST /v1/products/{id}/stock | Id du produit | products:read | products:write |
promo_code | POST /v1/promo-codes, PATCH et DELETE /v1/promo-codes/{id} | Id du code promo | promos:read | promos:write |
pixels | POST /v1/pixels, PATCH et DELETE /v1/pixels/{id} | L'id du pixel chez DZBuild, pas son pixel_id | pixels:read | pixels:write |
shipping.rates | POST /v1/shipping/rates, POST /v1/shipping/rates/sync | rates | shipping:read | shipping:write |
shipping.settings | PATCH /v1/shipping/settings | settings | shipping:read | shipping:write |
lp.section | Les écritures de sections sous /v1/landing-pages/{id}/sections | Id de la section, ou lp: suivi de l'id de la page pour un réordonnancement | landing_pages:read | landing_pages:write |
- Ces écritures ne sont pas enregistrées et ne peuvent pas être annulées : les produits avec leurs images, variantes, offres, add-ons et règles de quantité (le stock est enregistré), les commandes, les landing pages elles-mêmes, l'ordre des catégories, les transporteurs, les webhooks et les clés.
lp.pageest accepté comme filtreentity, mais aucune écriture ne l'enregistre.- L'enregistrement ne bloque pas une écriture. Quand un changement ne peut pas être enregistré, par exemple parce que ses valeurs d'avant ou d'après dépassent 256 KB, l'écriture passe quand même et ne peut pas être annulée. Les écritures de tarifs de livraison font exception : elles vérifient la taille d'abord et répondent
422 snapshot_too_largeau lieu de s'exécuter. - Chaque portée du tableau fait partie des portées par défaut d'une nouvelle clé : une clé créée depuis le dashboard (Paramètres → API,
/dashboard/api) peut donc utiliser les trois endpoints. Les portées sont figées à la création de la clé : une clé plus ancienne sans la portée qu'il faut répond403 forbidden. Créez une nouvelle clé depuis le dashboard.
GET /v1/changes
Les changements de la boutique, du plus récent au plus ancien, sans les valeurs qu'ils ont remplacées.
Auth : clé plateforme avec store:read. Le jeton d'une application installée reçoit 403 forbidden (Apps cannot use this endpoint).
Paramètres de requête
| Param | Type | Défaut | Notes |
|---|---|---|---|
entity | string | aucun | Seulement les changements d'une entity du tableau ci-dessus. Toute autre valeur est ignorée et la liste entière revient. |
limit | int | 25 | De 1 à 100. Une valeur plus petite compte pour 1, une plus grande pour 100. |
cursor | string | aucun | Le next_cursor de la page précédente. Voir Pagination. |
Requête
curl 'https://api.dzbuild.app/v1/changes?limit=2' \
-H "Authorization: Bearer $DZ_KEY"
Réponse 200
{
"data": {
"items": [
{
"id": 120,
"entity": "shipping.rates",
"entity_id": "rates",
"action": "update",
"summary": "Shipping rates updated for 2 wilaya(s)",
"undone_at": null,
"created_at": "2026-10-06 11:02:17",
"undone": false
},
{
"id": 119,
"entity": "promo_code",
"entity_id": "7",
"action": "update",
"summary": "Updated promo code SUMMER10",
"undone_at": null,
"created_at": "2026-10-06 10:52:30",
"undone": false
}
],
"next_cursor": "MTE5",
"has_more": true
}
}
| Champ | Signification |
|---|---|
id | L'id du changement, pour GET /v1/changes/{id} et l'annulation. |
entity | Ce qui a changé. Voir le tableau ci-dessus. |
entity_id | L'élément qui a changé, en chaîne. Voir le tableau ci-dessus. |
action | create, update ou delete. Une annulation est enregistrée comme un update. |
summary | Une courte description en anglais. Une annulation affiche Undo of change # suivi de l'id du changement annulé. |
undone | true une fois le changement annulé. |
undone_at | Quand le changement a été annulé, sinon null. |
created_at | YYYY-MM-DD HH:MM:SS, heure du serveur. undone_at suit le même format. |
GET /v1/changes/{id}
Un changement avec before, les valeurs qu'il a remplacées, et after, les valeurs qu'il a écrites. Leur forme dépend de l'entité : certaines gardent seulement les champs touchés par l'écriture, d'autres l'élément entier.
Auth : clé plateforme avec store:read, plus la portée de lecture de l'entité du changement, d'après le tableau ci-dessus. Le jeton d'une application installée reçoit 403 forbidden.
Requête
curl 'https://api.dzbuild.app/v1/changes/118' \
-H "Authorization: Bearer $DZ_KEY"
Réponse 200
{
"data": {
"id": 118,
"key_id": "dzpk_live_xxxxxxxxxxxxxx",
"entity": "category",
"entity_id": "12",
"action": "update",
"summary": "Updated category #12 (name, slug)",
"undone_at": null,
"undone_by_id": null,
"created_at": "2026-10-06 10:41:05",
"before": {"name": "Shoes", "slug": "shoes"},
"after": {"name": "Sneakers", "slug": "sneakers"},
"undone": false
}
}
La réponse porte les champs de la liste, plus ceux-ci.
| Champ | Signification |
|---|---|
key_id | La clé qui a fait le changement, ou null pour une annulation faite depuis le dashboard. |
undone_by_id | L'id du changement qui a annulé celui-ci, sinon null. |
before | Les valeurs que le changement a remplacées. null pour un create. |
after | Les valeurs que le changement a écrites. null pour un delete et pour une synchronisation des tarifs d'un transporteur. |
Le jeton d'accès (access token) d'un pixel n'est jamais gardé dans un changement. Quand le pixel en a un, before et after affichent •••••••• à sa place.
Erreurs
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | L'id du chemin n'est pas composé uniquement de chiffres. |
| 403 | forbidden | La clé n'a pas store:read ou la portée de lecture de l'entité du changement (Missing scope: ...), ou l'appel vient du jeton d'une application installée. |
| 404 | not_found | Aucun changement avec cet id dans la boutique. |
POST /v1/changes/{id}/undo
Réécrit les valeurs before du changement en passant par les mêmes contrôles que l'écriture d'origine, puis enregistre l'annulation comme un nouveau changement. Pas de corps de requête.
Auth : clé plateforme avec la portée d'annulation de l'entité du changement, d'après le tableau ci-dessus ; store:read n'est pas nécessaire. Nécessite Idempotency-Key. Le jeton d'une application installée reçoit 403 forbidden (Apps cannot use this endpoint). Le propriétaire de la boutique voit les 20 derniers changements de chaque application installée sur la page de cette application dans le dashboard (/dashboard/apps/{id}, bloc Ses dernières modifications) et peut les annuler depuis là avec le bouton Annuler.
Ce que fait l'annulation
- Un changement qui a créé quelque chose n'a rien à restaurer et répond
422 nothing_to_restore: supprimez l'élément à la place. L'ajout d'une section de la page d'accueil par/v1/store/home-layoutfait exception, parce que chaque écriture de la mise en page de l'accueil est enregistrée comme unupdatede toute la mise en page. - Un
updates'annule en réécrivant les valeursbeforepar-dessus ce qui est là maintenant. Seule la page d'accueil vérifie les changements ultérieurs et répond409 layout_changed(voir Sections de la page d'accueil). Pour revenir sur plusieurs changements d'un même élément, annulez-les du plus récent au plus ancien. - Une catégorie supprimée revient avec son id, sans son image. Un code promo supprimé revient avec son id si aucun autre code ne l'a pris, et avec son nombre d'utilisations.
- Un pixel supprimé revient avec son id s'il est encore libre, mais sans son jeton d'accès et sans ses affectations aux produits, catégories et landing pages. Annuler une modification de pixel laisse son jeton d'accès actuel en place.
- Une section de landing page supprimée revient avec un nouvel id.
- Une annulation de stock remet chaque valeur au nombre enregistré avant le changement, quoi que les commandes aient fait au stock depuis.
- Annuler
POST /v1/shipping/ratesremet les tarifs précédents, et retire le tarif d'une wilaya qui n'en avait pas avant le changement. Annuler une synchronisation des tarifs d'un transporteur remet chaque tarif que la synchronisation a écrasé, et garde les tarifs qu'elle a ajoutés pour des wilayas qui n'en avaient pas. - L'annulation est enregistrée comme un changement à part,
undo_change_id, que vous pouvez annuler pour réappliquer le changement d'origine. Quand le changement d'origine n'a pas d'after(une suppression ou une synchronisation des tarifs d'un transporteur), annuler l'annulation répond422 nothing_to_restore. - Un changement s'annule une seule fois. Une annulation suivante répond
409 already_undone, et de deux annulations envoyées au même moment une seule s'exécute. - Quand la restauration elle-même échoue (
restore_target_missing, une valeur refusée ou un500), le changement n'est pas marqué comme annulé : vous pouvez réessayer une fois la cause corrigée. Les règles de réessai sont plus bas.
La réponse de l'annulation ne contient pas les valeurs restaurées. Relisez l'élément. Par api.dzbuild.app, le cache de lecture court (GET /v1/store et chaque GET en dessous, les listes GET /v1/products et GET /v1/landing-pages) peut encore renvoyer les anciennes valeurs jusqu'à 30 secondes après l'annulation.
Requête
curl -X POST 'https://api.dzbuild.app/v1/changes/118/undo' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: undo-118"
Réponse 200
{
"data": {
"undone": true,
"change_id": 118,
"entity": "category",
"undo_change_id": 121
}
}
| Champ | Signification |
|---|---|
undone | Toujours true avec un 200. |
change_id | Le changement annulé. |
entity | Son entité. |
undo_change_id | Le changement qui enregistre cette annulation, ou null s'il n'a pas pu être enregistré. |
Erreurs
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | L'id du chemin n'est pas composé uniquement de chiffres, ou Idempotency-Key est absente ou mal formée. |
| 403 | forbidden | La clé n'a pas la portée d'annulation de l'entité du changement (Missing scope: ...), ou l'appel vient du jeton d'une application installée. |
| 404 | not_found | Aucun changement avec cet id dans la boutique. |
| 409 | already_undone | Le changement a déjà été annulé. |
| 409 | layout_changed | Page d'accueil seulement : la mise en page a changé après ce changement. |
| 422 | not_undoable | Ce type de changement ne peut pas être annulé. |
| 422 | nothing_to_restore | Le changement a créé quelque chose, ou ne contient aucune valeur à restaurer. Supprimez l'élément à la place. |
| 422 | restore_target_missing | Ce que le changement a touché n'existe plus, par exemple une catégorie ou une section de landing page supprimée depuis. |
| 422 | idempotency_key_reuse | La même Idempotency-Key a déjà servi pour une autre requête, par exemple l'annulation d'un autre changement. |
| 4xx | Le code de l'écriture d'origine | Les contrôles de l'écriture d'origine refusent les valeurs, par exemple invalid_wilaya sur les tarifs de livraison, ou un thème qui n'est plus proposé. |
| 500 | server_error | L'annulation n'a pas pu s'exécuter. Le changement reste annulable. |
Réessais et Idempotency-Key
La première réponse à une clé est conservée 24 heures, un 4xx compris. Un réessai avec la même clé pour le même changement renvoie cette réponse avec Idempotency-Replay: 1, et aucune seconde annulation ne s'exécute. Après avoir corrigé la cause d'une erreur, réessayez donc avec une nouvelle clé. Une réponse 5xx ou 429 n'est jamais conservée : réessayez-la avec la même clé. Voir Idempotence.