Sections de la page d'accueil
La mise en page de l'accueil est la liste ordonnée des sections qu'une boutique affiche sur sa page d'accueil. Chaque section a un type et des réglages. Dix types peuvent être ajoutés sur chaque thème : category-products, featured, categories, banner, image-with-text, rich-text, trust-badges, testimonials, faq et video. Un thème à sections comme atlas propose aussi hero et product-grid. types dans la réponse du GET donne les réglages de chacun. Chaque écriture de cette page est en ligne sur la boutique dès qu'elle répond.
Ce n'est pas GET /v1/store/home-sections, qui lit les interrupteurs des pages d'accueil Digital, Ariana et Prestige.
Avant de commencer
GETdemandestore:readet les écritures demandentstore:write. Les clés marchand ont les deux.POST,PATCHetDELETEdemandent uneIdempotency-Key. SurPUT, elle est facultative. Voir Idempotence.- L'id d'une catégorie vient de
GET /v1/categories, qui demandeproducts:read.
L'objet section
| Champ | Type | Notes |
|---|---|---|
id | int | Stable tant que la section existe. Une section qui revient par une annulation reçoit un nouvel id. |
type | string | L'une des valeurs type listées dans types par GET /v1/store/home-layout. |
settings | object | Tous les réglages du type, valeurs par défaut comprises. |
is_active | bool | false masque la section aux acheteurs et la garde dans la liste. |
available | bool | false quand le thème de la boutique n'a plus ce type. La section est gardée telle quelle et une écriture peut la conserver. |
Réglages de category-products
| Réglage | Type | Défaut | Règles |
|---|---|---|---|
category | id de catégorie | 0 | Une catégorie de cette boutique. 0 veut dire aucune, et la section n'affiche alors rien aux acheteurs. L'id d'une autre boutique répond 422 invalid_settings. |
title | text | "" | Jusqu'à 80 caractères, HTML retiré. Vide, il affiche le nom de la catégorie. |
count | range | 8 | De 4 à 12. Un nombre hors de cet intervalle est ramené à la borne la plus proche. |
layout | select | grid | grid ou slider. |
show_view_all | checkbox | true | Un lien vers la page de la catégorie. |
Une catégorie sans produits n'affiche rien aux acheteurs non plus. Lisez les règles de chaque type dans son settings_schema au lieu de les coder en dur : la liste des types dépend du thème de la boutique.
Formats des réglages
| Type de réglage | Valeur acceptée |
|---|---|
category | Un id de GET /v1/categories, ou 0 pour aucune. |
link | #ancre, un /chemin de la boutique, une adresse http:// ou https://, ou un lien tel: ou mailto:, 500 caractères au plus, ou "". Une adresse envoyée sans son préfixe, comme wa.me/213..., est enregistrée avec https:// devant. |
youtube | Un lien de vidéo YouTube ou son identifiant de 11 caractères. L'identifiant est enregistré. |
image | Le chemin d'une image envoyée depuis le dashboard pour cette boutique, /uploads/banners/{store_id}/..., ou "". L'API ne peut pas envoyer d'image aujourd'hui : le marchand envoie d'abord l'image dans les réglages de la section, dans le dashboard, puis GET renvoie son chemin. |
Quand les acheteurs voient une section
Une section dont le contenu n'est pas encore rempli est enregistrée et l'écriture répond 2xx, mais les acheteurs ne la voient pas tant qu'il ne l'est pas :
| Type | Les acheteurs la voient dès que |
|---|---|
category-products | category est une catégorie de la boutique qui a des produits. |
featured | la source choisie a des produits. |
categories | la boutique a une catégorie avec des produits, ou n'importe quelle catégorie quand show_empty vaut true. |
banner | image est rempli. |
image-with-text | image est rempli, avec un title ou un text. |
rich-text | title ou text est rempli. |
trust-badges | toujours. Les badges 1 et 2 vides affichent les lignes par défaut de livraison et de paiement à la livraison. |
testimonials | au moins un tN_text est rempli. |
faq | au moins un qN est rempli avec son aN. |
video | video contient un identifiant YouTube. |
rendered ne change pas pour autant : il dit si le thème affiche les sections enregistrées, pas si une section précise est visible. Sur un thème à sections (atlas), les sections enregistrées remplacent l'accueil du thème seulement tant qu'elles contiennent une section product-grid visible, et rendered vaut false jusque-là ; avant, les acheteurs voient l'accueil du thème, et le GET ne liste que les sections enregistrées, pas celles du thème.
GET /v1/store/home-layout
Les sections dans l'ordre d'affichage, les types de section qu'on peut ajouter sur le thème de la boutique, et le plafond du plan.
Auth : clé plateforme avec store:read.
Requête
curl 'https://api.dzbuild.app/v1/store/home-layout' \
-H "Authorization: Bearer $DZ_KEY"
Réponse 200
{
"data": {
"theme": "starter",
"rendered": true,
"max_sections": 25,
"cap": 25,
"version": "9c1e04b7a2d35f68",
"sections": [
{
"id": 412,
"type": "category-products",
"settings": {
"category": 57,
"title": "",
"count": 8,
"layout": "grid",
"show_view_all": true
},
"is_active": true,
"available": true
},
{
"id": 415,
"type": "category-products",
"settings": {
"category": 61,
"title": "Nos parfums",
"count": 10,
"layout": "slider",
"show_view_all": false
},
"is_active": false,
"available": true
}
],
"types": [
{
"type": "category-products",
"name": {"ar": "منتجات فئة", "fr": "Produits d'une catégorie"},
"description": {"ar": "اعرض منتجات فئة واحدة في شبكة أو شريط تمرير.", "fr": "Affichez les produits d'une catégorie en grille ou en carrousel."},
"icon": "bi-grid-3x3-gap",
"limit": 12,
"settings_schema": [
{"id": "category", "type": "category", "default": 0, "label": {"ar": "الفئة", "fr": "Catégorie"}},
{"id": "title", "type": "text", "max": 80, "default": "", "label": {"ar": "العنوان (إذا تركته فارغاً يظهر اسم الفئة)", "fr": "Titre (si vide, le nom de la catégorie s'affiche)"}},
{"id": "count", "type": "range", "min": 4, "max": 12, "default": 8, "label": {"ar": "عدد المنتجات", "fr": "Nombre de produits"}},
{"id": "layout", "type": "select", "options": ["grid", "slider"], "default": "grid", "label": {"ar": "طريقة العرض", "fr": "Affichage"}, "option_labels": {"ar": ["شبكة", "شريط تمرير"], "fr": ["Grille", "Carrousel"]}},
{"id": "show_view_all", "type": "checkbox", "default": true, "label": {"ar": "زر عرض الكل", "fr": "Lien « Voir tout »"}}
]
}
]
},
"meta": {"request_id": "8f2c1a9d4b7e6035", "api_version": "v1"}
}
| Champ | Signification |
|---|---|
theme | La clé du thème de la boutique. |
rendered | false quand le thème actuel de la boutique n'affiche pas les sections de l'accueil. Les sections sont gardées et réapparaissent sur un thème qui les affiche. Sur un thème à sections, il vaut true seulement tant qu'une section product-grid visible est enregistrée. |
max_sections | 25, le nombre maximum de sections sur une page d'accueil. |
cap | Les sections que le plan de la boutique autorise : 3 sur Free ou un plan expiré, 25 à partir de Pro. |
version | Une empreinte de la mise en page enregistrée. Renvoyez-la dans version sur PUT pour refuser une mise en page qui a changé depuis cette lecture. |
sections | Les sections dans l'ordre d'affichage, sections masquées comprises. |
types | Les types qu'on peut ajouter sur ce thème, avec name, description, icon, limit (le nombre maximum de sections de ce type sur une page) et settings_schema. L'exemple ci-dessus en montre un seul. |
Lire après une écriture
Par api.dzbuild.app, un GET réussi est mis en cache 30 secondes par clé et par chaîne de requête (l'en-tête X-Cache: HIT|MISS indique lequel). Un GET envoyé juste après une écriture peut donc renvoyer la mise en page d'avant. Utilisez la mise en page de la réponse à l'écriture : chaque écriture renvoie la liste complète dans l'ordre d'affichage, avec la nouvelle version. Si vous devez relire, ajoutez votre propre chaîne de requête, par exemple ?fresh=1727520000.
POST /v1/store/home-layout/sections
Ajoute une section.
Auth : clé plateforme avec store:write. Nécessite Idempotency-Key.
Corps
| Champ | Type | Requis | Notes |
|---|---|---|---|
type | string | oui | Un type de types. |
settings | object | non | Les réglages non envoyés prennent les valeurs par défaut du type. |
position | int | non | 0 met la section en haut, 24 est la dernière place. Sans lui, la section va à la fin. |
Requête
curl -X POST 'https://api.dzbuild.app/v1/store/home-layout/sections' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-add-sacs-1" \
-d '{"type": "category-products", "settings": {"category": 64, "layout": "slider"}, "position": 0}'
Réponse 201
{
"data": {
"section": {
"id": 418,
"type": "category-products",
"settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true},
"is_active": true,
"available": true
},
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},
{"id": 412, "type": "category-products", "settings": {"category": 57, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 10, "layout": "slider", "show_view_all": false}, "is_active": false, "available": true}
],
"version": "e27a90c4b1f36d05",
"change_id": 90231,
"rendered": true
},
"meta": {"request_id": "3b7d0e5a9c14f862", "api_version": "v1"}
}
PATCH /v1/store/home-layout/sections/{id}
Modifie une section. Les réglages envoyés sont fusionnés avec ceux enregistrés. Envoyez settings, is_active ou les deux.
Auth : clé plateforme avec store:write. Nécessite Idempotency-Key.
Corps
| Champ | Type | Requis | Notes |
|---|---|---|---|
settings | object | non | Fusionnés avec les réglages enregistrés. |
is_active | bool | non | false masque la section, true l'affiche. |
replace | bool | non | Avec settings, true remet à sa valeur par défaut chaque réglage non envoyé. |
Requête
curl -X PATCH 'https://api.dzbuild.app/v1/store/home-layout/sections/415' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-415-show-1" \
-d '{"settings": {"count": 6}, "is_active": true}'
Réponse 200
La réponse a les mêmes champs que celle de POST : section (la section après le changement), sections, version, change_id et rendered.
{
"data": {
"section": {
"id": 415,
"type": "category-products",
"settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false},
"is_active": true,
"available": true
},
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},
{"id": 412, "type": "category-products", "settings": {"category": 57, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}, "is_active": true, "available": true}
],
"version": "51d8c3e06fa2b974",
"change_id": 90232,
"rendered": true
},
"meta": {"request_id": "c90a6e1f2d7b4538", "api_version": "v1"}
}
DELETE /v1/store/home-layout/sections/{id}
Supprime une section.
Auth : clé plateforme avec store:write. Nécessite Idempotency-Key.
Requête
curl -X DELETE 'https://api.dzbuild.app/v1/store/home-layout/sections/412' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: hs-del-412-1"
Réponse 200
{
"data": {
"deleted": true,
"id": 412,
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}, "is_active": true, "available": true}
],
"version": "0f6b2d9e84a1c357",
"change_id": 90233,
"rendered": true
},
"meta": {"request_id": "71e4b08c3a5d9f26", "api_version": "v1"}
}
POST /v1/store/home-layout/reorder
Fixe l'ordre d'affichage. ids liste chaque section de la page une seule fois, sections masquées comprises.
Auth : clé plateforme avec store:write. Nécessite Idempotency-Key.
Requête
curl -X POST 'https://api.dzbuild.app/v1/store/home-layout/reorder' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-order-2" \
-d '{"ids": [415, 418]}'
Réponse 200
La réponse porte sections dans le nouvel ordre, version, change_id et rendered. Un id absent de la page répond 404 section_not_found. Un id manquant ou répété répond 422 invalid_order.
PUT /v1/store/home-layout
Remplace toute la mise en page par la liste envoyée, dans cet ordre.
Auth : clé plateforme avec store:write. Idempotency-Key est facultative.
Corps
| Champ | Type | Requis | Notes |
|---|---|---|---|
sections | array | oui | 25 éléments au plus, chacun {id?, type, settings?, is_active?}. Une liste vide supprime toutes les sections. |
version | string | non | La version de votre dernière lecture. Si la mise en page a changé depuis, l'appel répond 409 write_conflict avec les sections et la version actuelles, et n'écrit rien. |
Comment chaque élément est lu :
- Un élément avec un
idgarde cette section. Sontypedoit être le type actuel de la section. - Un élément sans
idcrée une section. - Une section de la page absente de la liste est supprimée.
settingsest l'objet complet : un réglage omis revient à sa valeur par défaut. Envoyez les réglages complets de chaque section que vous gardez.is_activevauttruepar défaut.
Requête
curl -X PUT 'https://api.dzbuild.app/v1/store/home-layout' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hs-replace-7" \
-d '{
"version": "0f6b2d9e84a1c357",
"sections": [
{"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}},
{"type": "category-products", "settings": {"category": 57}}
]
}'
Réponse 200
La réponse porte sections, version, change_id et rendered. La section 418 n'a pas été envoyée, elle est donc supprimée. Renvoyer telle quelle la mise en page lue répond change_id: null.
Avec une Idempotency-Key, un réessai avec la même clé et le même corps renvoie la réponse conservée pendant 24 heures avec Idempotency-Replay: 1, et la même clé avec un autre corps répond 422 idempotency_key_reuse. Sans clé, l'appel s'exécute à chaque fois, ce qui est sans risque : envoyer deux fois la même liste laisse la même mise en page.
Annulation
Chaque écriture répond avec un change_id, ou null quand elle n'a rien changé. POST /v1/changes/{change_id}/undo remet toute la page d'accueil telle qu'elle était avant ce changement.
- Un ajout de section s'annule aussi : l'annulation retire la section. Pour les autres ressources, l'annulation refuse un changement qui a créé quelque chose.
- Si la page d'accueil a changé après ce changement, par l'API ou dans le dashboard, l'annulation répond
409 layout_changedet n'écrit rien. Lisez la mise en page et écrivez directement ce que vous voulez. - Une section qui revient après une suppression reçoit un nouvel id.
- L'annulation est enregistrée comme un changement à part,
undo_change_id, que vous pouvez annuler à son tour. Annuler l'annulation d'une suppression répond409 layout_changed, parce que la section est revenue avec un nouvel id. - Les changements que le marchand enregistre dans le dashboard ne sont pas enregistrés, on ne peut donc pas les annuler par l'API.
GET /v1/changes?entity=store.home_layoutliste les changements de la mise en page de l'accueil, du plus récent au plus ancien, avecstore:read.- La réponse de l'annulation ne contient pas la mise en page. Relisez-la avec votre propre chaîne de requête, par exemple
?fresh=<unix time>, pour que le cache de 30 secondes ne renvoie pas la mise en page d'avant l'annulation.
L'annulation demande store:write et une Idempotency-Key.
curl -X POST 'https://api.dzbuild.app/v1/changes/90231/undo' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: undo-90231"
{
"data": {
"undone": true,
"change_id": 90231,
"entity": "store.home_layout",
"undo_change_id": 90240
},
"meta": {"request_id": "5ad2f7c01e9b8634", "api_version": "v1"}
}
Un changement annulé une seconde fois répond 409 already_undone.
Erreurs
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | Le corps n'est pas un objet JSON, un champ a le mauvais type (type absent, settings qui n'est pas un objet, is_active qui n'est pas un booléen, position hors de 0 à 24, ids qui n'est pas un tableau d'ids de section, version qui n'est pas une chaîne), l'id de section dans le chemin n'est pas un nombre positif, ou Idempotency-Key manque ou est mal formée sur POST, PATCH ou DELETE. |
| 401 | unauthorized | Clé absente ou invalide. |
| 402 | quota_exceeded | Le quota mensuel de requêtes de la boutique est épuisé. Voir Limites de taux. |
| 403 | forbidden | « Missing scope: store:read » ou « Missing scope: store:write ». |
| 403 | plan_required | L'écriture laisserait plus de sections que le plan n'en autorise. L'erreur porte plan et cap. |
| 404 | section_not_found | Aucune section avec cet id sur la page. |
| 409 | write_conflict | Une autre écriture est arrivée avant, ou la version envoyée sur PUT n'est pas l'actuelle. Quand l'erreur porte sections et version, c'est la mise en page actuelle : réessayez à partir d'elles. Sinon, relisez la mise en page et réessayez. |
| 409 | layout_changed | Annulation seulement : la page d'accueil a changé après ce changement. |
| 409 | already_undone | Annulation seulement : le changement a déjà été annulé. |
| 413 | payload_too_large | Le corps dépasse 1 Mo. |
| 422 | invalid_settings | Une valeur a été refusée. fields liste chaque réglage refusé de la section, par exemple settings.category. Sur PUT, il liste ceux de la première section refusée seulement, par exemple sections.2.settings.layout, et couvre aussi un id absent de la page (sections.N.id) et une section gardée envoyée avec un autre type (sections.N.type). message nomme aussi les chemins. |
| 422 | invalid_section_type | Le type n'existe pas ou ne peut pas être ajouté sur ce thème. fields donne le chemin. |
| 422 | limit_reached | Plus de 25 sections, ou plus de sections d'un type que sa limit. L'erreur porte limit, sauf quand un PUT envoie plus de 25 éléments. |
| 422 | invalid_order | Les ids du réordonnancement oublient une section ou en répètent une. |
| 422 | no_changes | Un PATCH sans settings ni is_active. |
| 422 | idempotency_key_reuse | La même Idempotency-Key a servi avec un autre corps. |
| 429 | rate_limited | Trop de requêtes, y compris plus de 30 écritures de mise en page de l'accueil par minute pour la boutique. Attendez la durée de Retry-After. |
| 429 | too_many_concurrent | Plus de 5 écritures de mise en page de l'accueil en cours en même temps pour la boutique. Réessayez dans quelques secondes. |
| 500 | server_error | La requête a échoué. Réessayez avec la même Idempotency-Key. |
Une réponse invalid_settings ressemble à ceci.
{
"error": {
"code": "invalid_settings",
"message": "Invalid value at settings.category: category not found in this store; accepted values are in settings_schema of GET /v1/store/home-layout",
"fields": [{"path": "settings.category", "code": "invalid"}]
},
"meta": {"request_id": "e4c19a0b7d2f5836", "api_version": "v1"}
}
Limites
- 25 sections par page d'accueil (
max_sections). - Plafond du plan (
cap) : 3 sections sur Free ou un plan expiré, 25 à partir de Pro. Les sections masquées comptent. Une boutique au-dessus de son plafond après un changement de plan garde ses sections et peut toujours les modifier, les masquer, les réordonner et les supprimer. Une écriture qui laisse plus de sections que le plafond et plus qu'avant répond403 plan_required. - Par type : chaque type a une
limitdanstypes, 12 pourcategory-products. - Réglages : 8 Ko par section une fois encodés. Un texte plus long est coupé au
maxdu réglage. - Corps : 1 Mo.
- Écritures : 30 par minute et 5 en même temps par boutique, en plus de la limite par minute de la boutique. Voir Limites de taux.