Skip to main content

Home page sections

The home layout is the ordered list of sections a store shows on its home page. Each section has a type and settings. Ten types can be added on every theme: category-products, featured, categories, banner, image-with-text, rich-text, trust-badges, testimonials, faq and video. A section theme such as atlas also offers hero and product-grid. types in the GET answer gives the settings of each. Every write on this page is live on the store as soon as it answers.

This is not GET /v1/store/home-sections, which reads the switches of the Digital, Ariana and Prestige home pages.

Before you start​

  • GET needs store:read and the writes need store:write. Merchant keys carry both.
  • POST, PATCH and DELETE need an Idempotency-Key. On PUT it is optional. See Idempotency.
  • A category id comes from GET /v1/categories, which needs products:read.

The section object​

FieldTypeNotes
idintStable while the section exists. A section that comes back through an undo gets a new id.
typestringOne of the type values listed in types by GET /v1/store/home-layout.
settingsobjectEvery setting of the type, with the defaults filled in.
is_activeboolfalse hides the section from buyers and keeps it in the list.
availableboolfalse when the store's theme no longer has this type. The section is kept as stored and a write may keep it.

Settings of category-products​

SettingTypeDefaultRules
categorycategory id0A category of this store. 0 means none, and the section then shows nothing to buyers. An id of another store answers 422 invalid_settings.
titletext""Up to 80 characters, HTML removed. Empty shows the category name.
countrange84 to 12. A number outside that range is moved to the nearest end.
layoutselectgridgrid or slider.
show_view_allcheckboxtrueA link to the category page.

A category with no products shows nothing to buyers either. Read the rules of any type from its settings_schema rather than hard-coding them: the list of types depends on the store's theme.

Setting formats​

Setting typeAccepted value
categoryAn id from GET /v1/categories, or 0 for none.
link#anchor, a /path on the store, an http:// or https:// address, or a tel: or mailto: link, up to 500 characters, or "". An address sent without its scheme, such as wa.me/213..., is stored with https:// in front.
youtubeA YouTube video link or its 11-character id. The id is stored.
imageThe path of an image uploaded in the dashboard for this store, /uploads/banners/{store_id}/..., or "". The API cannot upload images today: the merchant uploads the picture in the section's settings in the dashboard first, and GET then returns its path.

When buyers see a section​

A section whose content is not filled in yet is stored and the write answers 2xx, but buyers do not see it until it is:

TypeBuyers see it once
category-productscategory is a category of the store that has products.
featuredthe chosen source has products.
categoriesthe store has a category with products, or any category when show_empty is true.
bannerimage is set.
image-with-textimage is set, with a title or a text.
rich-texttitle or text is set.
trust-badgesalways. Empty badges 1 and 2 show the default delivery and cash on delivery lines.
testimonialsat least one tN_text is set.
faqat least one qN is set with its aN.
videovideo holds a YouTube id.

rendered does not change for this: it says whether the theme shows stored sections, not whether one section is visible. On a section theme (atlas), saved sections replace the theme's own home only while they include a visible product-grid section, and rendered is false until then; buyers see the theme's home, and GET lists only the saved sections, not the theme's own.

GET /v1/store/home-layout​

The sections in render order, the section types that can be added on the store's theme, and the plan cap.

Auth: platform key with store:read.

Request​

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

Response 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"}
}
FieldMeaning
themeThe store's theme key.
renderedfalse when the store's current theme does not show home page sections. The sections are kept and show again on a theme that does. On a section theme it is true only while a visible product-grid section is saved.
max_sections25, the most sections one home page holds.
capThe sections the store's plan allows: 3 on Free or an expired plan, 25 from Pro.
versionA fingerprint of the stored layout. Send it back as version on PUT to refuse a layout that changed since this read.
sectionsThe sections in render order, hidden ones included.
typesThe types that can be added on this theme, with name, description, icon, limit (the most sections of that type one page holds) and settings_schema. The sample above shows one of them.

Reading after a write​

Through api.dzbuild.app a successful GET is cached for 30 seconds per key and query string (the X-Cache: HIT|MISS header tells you which). A GET sent right after a write can therefore return the layout from before it. Use the layout in the write's answer: every write returns the whole list in render order with the new version. When you must read again, add a query string of your own, such as ?fresh=1727520000.

POST /v1/store/home-layout/sections​

Adds one section.

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

Body​

FieldTypeRequiredNotes
typestringyesA type from types.
settingsobjectnoSettings you do not send take the type's defaults.
positionintno0 puts the section at the top, 24 is the last place. Without it the section goes at the end.

Request​

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

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

Changes one section. The settings you send are merged over the stored ones. Send settings, is_active or both.

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

Body​

FieldTypeRequiredNotes
settingsobjectnoMerged over the stored settings.
is_activeboolnofalse hides the section, true shows it.
replaceboolnoWith settings, true resets every setting you do not send to its default.

Request​

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

Response 200​

The answer has the same fields as the POST answer: section (the section after the change), sections, version, change_id and 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}​

Removes one section.

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

Request​

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"

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

Sets the render order. ids lists every section of the page exactly once, hidden ones included.

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

Request​

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

Response 200​

The answer carries sections in the new order, version, change_id and rendered. An id that is not on the page answers 404 section_not_found. A missing or repeated id answers 422 invalid_order.

PUT /v1/store/home-layout​

Replaces the whole layout with the list you send, in that order.

Auth: platform key with store:write. Idempotency-Key is optional.

Body​

FieldTypeRequiredNotes
sectionsarrayyesAt most 25 items, each {id?, type, settings?, is_active?}. An empty list removes every section.
versionstringnoThe version from your last read. When the layout changed since, the call answers 409 write_conflict with the current sections and version, and writes nothing.

How each item is read:

  • An item with an id keeps that section. Its type must be the section's current type.
  • An item without an id creates a section.
  • A section of the page that is not in the list is deleted.
  • settings is the whole object: a setting you leave out goes back to its default. Send the full settings of every section you keep.
  • is_active defaults to true.

Request​

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

Response 200​

The answer carries sections, version, change_id and rendered. Section 418 was left out, so it is deleted. Sending back the layout you read, unchanged, answers change_id: null.

With an Idempotency-Key, a retry with the same key and the same body gets the stored answer back for 24 hours with Idempotency-Replay: 1, and the same key with another body answers 422 idempotency_key_reuse. Without a key the call runs every time, which is safe: sending the same list twice leaves the same layout.

Undo​

Every write answers with a change_id, or null when it changed nothing. POST /v1/changes/{change_id}/undo puts the whole home page back as it was before that change.

  • An added section can be undone too: the undo removes it. For other resources, undo refuses a change that created something.
  • If the home page changed after that change, through the API or in the dashboard, the undo answers 409 layout_changed and writes nothing. Read the layout and write what you want directly.
  • A section that comes back after a delete gets a new id.
  • The undo is recorded as a change of its own, undo_change_id, which you can undo in turn. Undoing the undo of a delete answers 409 layout_changed, because the section came back with a new id.
  • Changes the merchant saves in the dashboard are not recorded, so they cannot be undone through the API.
  • GET /v1/changes?entity=store.home_layout lists the home layout changes, newest first, with store:read.
  • The undo answer does not carry the layout. Read it with a query string of your own, such as ?fresh=<unix time>, so the 30-second cache does not return the layout from before the undo.

The undo needs store:write and an 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"}
}

A change undone a second time answers 409 already_undone.

Errors​

HTTPCodeCause
400bad_requestThe body is not a JSON object, a field has the wrong type (type missing, settings not an object, is_active not a boolean, position outside 0 to 24, ids not an array of section ids, version not a string), the section id in the path is not a positive number, or Idempotency-Key is missing or malformed on POST, PATCH or DELETE.
401unauthorizedBad or missing key.
402quota_exceededThe store's monthly request quota is used up. See Rate limits.
403forbiddenMissing scope: store:read or Missing scope: store:write.
403plan_requiredThe write would leave more sections than the plan allows. The error carries plan and cap.
404section_not_foundNo section with this id on the page.
409write_conflictAnother write landed first, or the version sent on PUT is not the current one. When the error carries sections and version, they are the current layout: retry from them. Otherwise read the layout and retry.
409layout_changedUndo only: the home page changed after this change.
409already_undoneUndo only: the change was already undone.
413payload_too_largeThe body is over 1 MB.
422invalid_settingsA value was refused. fields lists every refused setting of the section, such as settings.category. On PUT it lists those of the first refused section only, such as sections.2.settings.layout, and it also covers an id that is not on the page (sections.N.id) and a kept section sent with another type (sections.N.type). message names the paths too.
422invalid_section_typeThe type does not exist or cannot be added on this theme. fields gives the path.
422limit_reachedMore than 25 sections, or more of one type than its limit. The error carries limit, except when a PUT sends more than 25 items.
422invalid_orderReorder ids miss a section or repeat one.
422no_changesA PATCH without settings or is_active.
422idempotency_key_reuseThe same Idempotency-Key was used with another body.
429rate_limitedToo many requests, including more than 30 home layout writes a minute for the store. Wait for Retry-After.
429too_many_concurrentMore than 5 home layout writes running at once for the store. Retry in a few seconds.
500server_errorThe request failed. Retry with the same Idempotency-Key.

An invalid_settings answer looks like this.

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

Limits​

  • 25 sections per home page (max_sections).
  • Plan cap (cap): 3 sections on Free or an expired plan, 25 from Pro. Hidden sections count. A store above its cap after a downgrade keeps its sections and can still edit, hide, reorder and delete them. A write that leaves more sections than the cap and more than before answers 403 plan_required.
  • Per type: each type has a limit in types, 12 for category-products.
  • Settings: 8 KB per section once encoded. Longer text is cut to the setting's max.
  • Body: 1 MB.
  • Writes: 30 a minute and 5 at once per store, on top of the store's per-minute limit. See Rate limits.