Home page sections
Your app can read and change the sections of a store's home page. A section is a block on the home page with 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. Every write is live on the store as soon as it answers.
The full request and response reference is in the OpenAPI description, linked from the API reference page: getStoreHomeLayout, addStoreHomeSection, updateStoreHomeSection, deleteStoreHomeSection, reorderStoreHomeSections and replaceStoreHomeLayout. This page explains how the pieces fit together.
Scopes
| Scope | Allows |
|---|---|
store:read | GET /v1/store/home-layout |
store:write | POST /v1/store/home-layout/sections, PATCH /v1/store/home-layout/sections/{id}, DELETE /v1/store/home-layout/sections/{id}, POST /v1/store/home-layout/reorder, PUT /v1/store/home-layout |
A call without the scope answers 403 with the code forbidden and the message Missing scope: store:write (or store:read). See Scopes.
Read the layout
GET /v1/store/home-layout returns:
| Field | Meaning |
|---|---|
theme | The store's theme key. |
rendered | false 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_sections | 25, the most sections one home page holds. |
cap | The sections the store's plan allows: 3 on Free or an expired plan, 25 from Pro. Your app installs on stores of every plan, so read cap instead of assuming 25. |
version | A fingerprint of the stored layout, for PUT. |
sections | {id, type, settings, is_active, available} in render order, hidden sections included. available is false when the theme no longer has that type; the section is kept as stored. |
types | The types that can be added on this theme, each with name, description, icon, limit and settings_schema. |
Build your forms from settings_schema rather than hard-coding a type: the list depends on the store's theme. Each setting has an id, a type (checkbox, range, select, text, textarea, color, link, image, category or youtube), a default, min and max or options where they apply, and label and option_labels in Arabic and French.
The settings of category-products are category (a category id from GET /v1/categories, which needs products:read), title (up to 80 characters, empty shows the category name), count (4 to 12), layout (grid or slider) and show_view_all (a link to the category page).
A section whose content is not filled in yet (no category or one without products, a banner without image, an image-with-text without image or without both title and text, an empty rich-text, testimonials, faq or video) is stored and the write answers 2xx, but buyers do not see it until it is filled. rendered only says whether the theme shows stored sections.
An image setting takes only the path of a picture the merchant uploaded in the dashboard for this store (/uploads/banners/{store_id}/...) or "". The API cannot upload images today, so a banner or an image-with-text needs that upload first.
Change the layout
Every write except PUT needs an Idempotency-Key header (see Rate limits).
POST /v1/store/home-layout/sections HTTP/1.1
Host: api.dzbuild.app
Authorization: Bearer dzpk_live_xxxxxxxx
Idempotency-Key: hs-add-64
Content-Type: application/json
{"type": "category-products", "settings": {"category": 64}, "position": 0}
The call answers 201 with the new section and the whole layout:
{
"data": {
"section": {"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},
"sections": [
{"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "grid", "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}
],
"version": "e27a90c4b1f36d05",
"change_id": 90231,
"rendered": true
},
"meta": { "request_id": "3b7d0e5a9c14f862", "api_version": "v1" }
}
| Operation | Body | Notes |
|---|---|---|
POST .../sections | {type, settings?, position?} | Unsent settings take the defaults. position 0 is the top; without it the section goes at the end. |
PATCH .../sections/{id} | {settings?, is_active?, replace?} | Settings are merged over the stored ones. replace: true resets the unsent ones to their defaults. is_active: false hides the section. |
DELETE .../sections/{id} | none | Answers deleted: true and the section id. |
POST .../reorder | {ids} | Every section id of the page exactly once, hidden ones included. |
PUT /v1/store/home-layout | {sections, version?} | The whole list, 25 items at most. An item with an id keeps that section, an item without one creates a section, a section left out is deleted. settings is the whole object here: an omitted setting goes back to its default. |
Every write answers the whole layout in render order with the new version, a change_id (null when nothing changed) and rendered. Keep that answer. Through api.dzbuild.app a successful GET is cached for 30 seconds per token and query string, so a GET sent right after a write can return the layout from before it. Add a query string of your own when you must read again.
To make sure nobody changed the page between your read and your write, send the version you read with PUT. If the layout moved, the call answers 409 write_conflict and writes nothing; error then carries the current sections and version to retry from.
Undo
Install tokens cannot call /v1/changes or POST /v1/changes/{id}/undo: they answer 403 with Apps cannot use this endpoint. Each write is still recorded, so the merchant can undo it from your app's page in their dashboard. To revert inside your app, keep the sections you read before the change and send them back with PUT. A section you deleted comes back with a new id.
Limits
- 25 sections per home page, and at most
capfor the store's plan. Hidden sections count. A store above its cap after a downgrade keeps its sections; a write that leaves more sections than the cap and more than before answers403 plan_required. - Each type has a
limitintypes, 12 forcategory-products. - 8 KB of settings per section once encoded, and 1 MB per request body.
- 30 writes a minute and 5 at once per store, on top of your install's budget and the store's budget. See Rate limits.
Answers and error codes
| Status | Code | Meaning |
|---|---|---|
200 | Read, changed, deleted, reordered or replaced. | |
201 | Section added. | |
400 | bad_request | The body is not a JSON object, a field has the wrong type, the path id is not a positive number, or Idempotency-Key is missing on POST, PATCH or DELETE. |
403 | forbidden | The token lacks store:read or store:write. |
403 | plan_required | The write would leave more sections than the store's plan allows. error carries plan and cap. |
404 | section_not_found | No section with this id on the store's home page. |
409 | write_conflict | Another write changed the layout first, or the version sent on PUT is not the current one. When error carries sections and version, retry from them; otherwise read again. Retry with a new key. |
413 | payload_too_large | The body is over 1 MB. |
422 | invalid_settings | A value was refused. error.fields lists the refused settings, such as settings.category; on PUT, those of the first refused section only, such as sections.2.settings.layout. The message names them too. |
422 | invalid_section_type | The type does not exist or cannot be added on this theme. |
422 | limit_reached | More than 25 sections, or more of one type than its limit. |
422 | invalid_order | Reorder ids miss a section or repeat one. |
422 | no_changes | A PATCH without settings or is_active. |
429 | rate_limited or too_many_concurrent | A per-minute budget is used up, or 5 home layout writes are already running for the store. Wait retry_after seconds. |
See Errors for the codes every call can get, such as app_uninstalled.