Store
The "store" is the top-level container of products, orders, customers, etc. Every key is bound to exactly one store. There is no way to query other merchants' stores.
GET /v1/store
Returns the profile of the store the calling key belongs to.
Auth: platform key with store:read. Merchant keys carry it by default; a key without it gets 403 forbidden (Missing scope: store:read).
Served fresh on every call: a dashboard change appears on the next GET through api.dzbuild.app and through the alias dzbuild.com/api/v1/store.
Request
curl https://api.dzbuild.app/v1/store \
-H "Authorization: Bearer $DZ_KEY"
Response 200
{
"data": {
"id": 12345,
"name": "My Store",
"slug": "my-store",
"language": "ar",
"description": "Short tagline",
"logo": "/uploads/logos/12345/logo.webp",
"favicon": null,
"banner": null,
"theme": {
"primary_color": "#f59e0b",
"secondary_color": "#fbbf24",
"background_color": "#ffffff",
"font_family": "Cairo"
},
"store_theme": "starter",
"fast_checkout_theme": "classic",
"variant_card_style": "default",
"subdomain": "my-store.dzbuild.app",
"custom_domain": null,
"custom_domain_verified": false,
"public_url": "https://my-store.dzbuild.app",
"hide_branding": false,
"created_at": "2026-01-01 12:00:00"
},
"meta": { "request_id": "...", "api_version": "v1" }
}
Field reference
| Field | Type | Notes |
|---|---|---|
id | int | Stable internal id. Same as store_id everywhere else. |
name | string | Display name. Shown in storefront navbar + emails. |
slug | string | URL-safe identifier. Used in <slug>.dzbuild.app etc. |
language | enum | ar or fr. Drives storefront RTL/LTR. |
description | string|null | Short tagline. |
logo | string|null | Path on cdn.dzbuild.app if set. Prepend the CDN base if you display it. |
favicon | string|null | Same. |
banner | string|null | Same. |
theme.primary_color | hex string | The dominant button + accent color. |
theme.secondary_color | hex string | Hover / secondary accents. |
theme.background_color | hex string | Page background. |
theme.font_family | string | Typography (default Cairo). |
store_theme | string | Key of the storefront theme in use, the same as current in GET /v1/themes. Read-only here: switch it with POST /v1/store/theme. |
fast_checkout_theme | string | Key of the fast-checkout form theme, classic until the merchant picks another. Switch it with POST /v1/store/fast-checkout-theme. |
variant_card_style | string | Key of the variant picker style, default when no style is set. Switch it with POST /v1/store/variant-style. |
subdomain | string|null | The DZBuild-issued subdomain. Normally present; null if the store has no subdomain configured yet. |
custom_domain | string|null | The merchant's own domain. Only set if added via dashboard. |
custom_domain_verified | bool | true once the domain's DNS settings are confirmed. The security certificate and the final check can still be running at that point; public_url switches to the domain only when it is fully live. |
public_url | string|null | Where customers actually land: the merchant's own domain once it is fully live and set as the store's main address, otherwise the subdomain; null if neither exists. |
hide_branding | bool | "Powered by DZBuild" hidden in storefront footer. Unlimited. |
created_at | timestamp | Store creation time, in Algiers time (UTC+01:00). |
Errors
| HTTP | Code | Cause |
|---|---|---|
| 401 | unauthorized | Bad or missing key |
| 402 | quota_exceeded | Store's monthly request quota exhausted — see Rate limits |
| 403 | forbidden | Missing scope: store:read; a merchant key whose store is not on an active Enterprise plan ("API access requires an active Enterprise plan"); or pilot mode: key not enrolled ("API is in pilot mode; key not enrolled") |
| 404 | not_found | The store was deleted while you were holding the key (very rare) |
| 429 | rate_limited | Per-minute cap for this store, shared by all of its keys; honour Retry-After. See Rate limits |
PATCH /v1/store
Updates the store's settings profile, the same fields as the store settings page in the dashboard except the WhatsApp number. Only the fields you send change.
Auth: platform key with store:write. Requires Idempotency-Key.
Body
| Field | Type | Notes |
|---|---|---|
store_name | string | Up to 100 characters. Cannot be empty. |
description | string | Up to 5000 characters. |
wilaya_id | int|null | A wilaya id from GET /v1/wilayas (needs shipping:read). 0 or null clears it. |
commune | string | Up to 100 characters. |
address | string | Up to 500 characters. |
store_phone | string | Up to 20 characters. |
store_email | string|null | A valid email address. "" or null clears it. |
google_site_verification | string|null | Google Search Console verification code, up to 100 characters. "" or null clears it. |
bing_site_verification | string|null | Bing Webmaster verification code, up to 100 characters. "" or null clears it. |
HTML tags are removed from text values and longer text is cut to the limit. The slug, the custom domain and the colors are not part of this endpoint; colors and other design values are changed with PATCH /v1/store/design.
Request
curl -X PATCH https://api.dzbuild.app/v1/store \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: store-profile-1" \
-d '{"store_phone": "0550000000", "description": "Short tagline"}'
Response 200
{
"data": {
"updated": ["description", "store_phone"],
"values": {"description": "Short tagline", "store_phone": "0550000000"}
},
"meta": { "request_id": "...", "api_version": "v1" }
}
The change is recorded and can be undone with POST /v1/changes/{change_id}/undo; find its id with GET /v1/changes?entity=store.settings. A GET /v1/store sent right after the write returns the new values.
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | The body is not valid JSON, or Idempotency-Key is missing or malformed. |
| 403 | forbidden | Missing scope: store:write, or a merchant key whose store is not on an active Enterprise plan. |
| 404 | store_not_found | The store was deleted. |
| 422 | no_writable_fields | The body holds none of the fields above. |
| 422 | invalid_value | A field is an object or a list, or store_name is empty. |
| 422 | invalid_wilaya | wilaya_id is not a known wilaya. |
| 422 | invalid_email | store_email is not a valid email address. |
| 422 | idempotency_key_reuse | The same Idempotency-Key was used with another body. |
GET /v1/store/design
Returns the store's design: the fields of the customize page of the dashboard (/dashboard/customize) for the store's current theme, grouped in the same sections, each with its current value. A few themes hide some of these fields on that page; the API lists them all.
Auth: platform key with store:read.
Served fresh through api.dzbuild.app, like GET /v1/store. The answer of PATCH /v1/store/design also carries the written values in values.
Request
curl https://api.dzbuild.app/v1/store/design \
-H "Authorization: Bearer $DZ_KEY"
Response 200
Two sections are shown, with some of their fields.
{
"data": {
"theme": "starter",
"plan": "enterprise",
"sections": [
{
"key": "theme",
"name": {"ar": "الألوان والخط", "fr": "Couleurs et Police"},
"plan_required": "free",
"page": "home",
"fields": [
{"key": "primary_color", "type": "color", "plan_required": "free", "writable": true, "locked": false, "value": "#f59e0b"},
{"key": "background_color", "type": "color", "plan_required": "pro", "writable": true, "locked": false, "value": "#ffffff"},
{"key": "font_family", "type": "select", "plan_required": "free", "writable": true, "locked": false, "value": "Cairo"}
]
},
{
"key": "productCard",
"name": {"ar": "بطاقة المنتج", "fr": "Carte produit"},
"plan_required": "free",
"page": "home",
"fields": [
{"key": "card_hide_price", "type": "switch", "plan_required": "free", "writable": true, "locked": false, "value": false},
{"key": "card_border_radius", "type": "select", "plan_required": "free", "writable": true, "locked": false, "allowed_values": ["0px", "8px", "16px", "24px"], "value": "16px"}
]
}
]
},
"meta": { "request_id": "...", "api_version": "v1" }
}
Field reference
| Field | Type | Notes |
|---|---|---|
theme | string | Key of the theme the store uses. See Themes. |
plan | string | The plan the locks are worked out for: free, pro, unlimited or enterprise. A paid plan that has expired counts as free. |
sections[].key | string | Section id, for example header, theme, productCard or checkoutPage. |
sections[].name | object | The section title the dashboard shows, in ar and fr. |
sections[].plan_required | string | The plan the dashboard shows on the section. |
sections[].page | string | home when the customize page lists the section under the home page preview, all when it lists it on every preview. |
sections[].fields | array | The section's fields. Can be empty: a few sections, such as helpWidget and the home page blocks of the Digital theme, are not saved through design fields. |
fields[].key | string | The name to send in PATCH /v1/store/design. |
fields[].type | string | The dashboard control: text, textarea, color, select or switch. |
fields[].plan_required | string | The plan the dashboard shows on the field. |
fields[].writable | bool | false when the API does not accept the field. custom_js is one: it is set in the dashboard only. |
fields[].locked | bool | true when the store's plan cannot write the field through the API. Read this flag, not plan_required, to know whether a write will be applied. |
fields[].allowed_values | array | Only on fixed-choice fields: the values the field takes. |
fields[].value | any | The current value. Switches come back as true or false, products_per_page as a number, the rest as stored. null when the store has no value for the field. |
GET /v1/store/design/fields
The same list without the value key. Call it before a write to see which fields the store's theme shows, the name to send for each one and which ones the plan locks.
Auth: platform key with store:read. Served fresh through api.dzbuild.app, like GET /v1/store.
Request
curl https://api.dzbuild.app/v1/store/design/fields \
-H "Authorization: Bearer $DZ_KEY"
Response 200
The last two sections are shown.
{
"data": {
"theme": "starter",
"plan": "enterprise",
"sections": [
{
"key": "customCss",
"name": {"ar": "CSS مخصّص", "fr": "CSS personnalisé"},
"plan_required": "enterprise",
"page": "all",
"fields": [
{"key": "custom_css", "type": "textarea", "plan_required": "enterprise", "writable": true, "locked": false}
]
},
{
"key": "customJs",
"name": {"ar": "JavaScript مخصّص", "fr": "JavaScript personnalisé"},
"plan_required": "enterprise",
"page": "all",
"fields": [
{"key": "custom_js", "type": "textarea", "plan_required": "enterprise", "writable": false, "locked": false}
]
}
]
},
"meta": { "request_id": "...", "api_version": "v1" }
}
Errors
GET /v1/store/design and GET /v1/store/design/fields answer the same errors as GET /v1/store: 401 unauthorized, 402 quota_exceeded, 403 forbidden (Missing scope: store:read, plan or pilot), 404 not_found and 429 rate_limited.
PATCH /v1/store/design
Changes design fields: colours, header, hero, product cards, product page, checkout texts, footer, social links, SEO and more. Only the fields you send change. Colours and hide_branding are set here, not with PATCH /v1/store.
Auth: platform key with store:write. Requires Idempotency-Key.
Body
Send any field that GET /v1/store/design/fields lists with writable: true. The design fields the current theme does not list are accepted too: they are stored, and a theme that shows them uses them. Keys the API does not know are ignored. Each value is cleaned by its kind:
| Kind | Examples | What is stored |
|---|---|---|
| Switch | show_hero, navbar_sticky, card_hide_price | Send true or false. The answer shows 1 or 0. |
| Colour | primary_color, navbar_color, footer_color | A #RRGGBB value. null clears it. Any other value is replaced with the field's default colour, for example #f59e0b for primary_color. |
| Override colour | announcement_bg_color, product_buy_now_color, fc_button_color | A #RRGGBB value. Anything else clears the override. |
| Text | hero_title, footer_about, seo_description | HTML tags are removed and the text is cut to the field's length, for example 255 characters for hero_title and 2000 for footer_about. |
| Link | hero_button_link, facebook, custom_link_url | An https://, http://, mailto: or tel: link, a /path, an #anchor or a bare handle, cut to 255 characters (20 for whatsapp). Any other scheme answers 422 invalid_url. |
| Fixed choice | card_border_radius, checkout_layout, store_language | One of the field's allowed_values. Any other value is stored as the field's default. |
| Number | products_per_page | Kept between 4 and 48. |
Some fields have their own rules:
font_family: Latin letters, digits, spaces and hyphens. Anything else is stored asCairo. The dashboard offersCairo,TajawalandAlmarai.button_style: the dashboard offersrounded,squareandpill.navbar_styletakesdefault,centered,minimalortransparent;navbar_menu_styletakesdefault,pills,underlineorbuttons;navbar_logo_sizetakessmall,mediumorlarge;cart_icon_styletakesdefault,filled,outlineorminimal. These four carry noallowed_values, and any other value refuses the whole write with422 invalid_value.facebook_pixel_id: 15 to 17 digits, or empty to clear it.custom_css: Enterprise plan only. It is cleaned before it is stored.
The buy bar and the order form on product pages have four fields of their own. Every plan can write them, and their defaults keep the look a store had before they existed.
| Field | Values | What it changes |
|---|---|---|
buybar_show_mobile | true (default) or false | false hides the buy bar fixed at the bottom of product pages on phones. The bar stays when the fast-checkout form is off, so a phone always shows a buy button. |
buybar_show_qty | true (default) or false | false removes the quantity buttons from the buy bar, on phones and computers. |
fc_show_qty | true (default) or false | false removes the quantity from the fast-checkout form. The buyer then orders one item, unless they picked an offer or a quantity in the buy bar, or the product has a minimum quantity. |
product_button_size | normal (default) or large | large makes the buy bar buttons and the order button of the fast-checkout form 56 pixels tall, with a 17 pixel label. Any other value is stored as normal. |
The Digital theme has no fast-checkout form: there fc_show_qty changes nothing, and buybar_show_mobile: false hides the phone bar while the buy buttons stay on the page.
Plan locks
A field the store's plan locks is not written. It is listed in skipped with the reason, and the call still answers 200 when another field was written. When every field you sent is skipped, the call answers 422 no_writable_fields.
Reason in skipped | When |
|---|---|
requires a paid plan | A field reserved for the pro plan and above, for example background_color, navbar_color, hide_branding or the announcement bar fields, sent for a free store. |
requires the enterprise plan | custom_css on any plan other than enterprise. |
requires the unlimited plan | hide_branding: true on a pro store. A pro store can still send hide_branding: false, which shows "Powered by DZBuild" in the footer again. |
A merchant key belongs to a store on an active Enterprise plan, so nothing is locked for it. The locks apply to installed-app tokens, which work on every plan.
Request
curl -X PATCH https://api.dzbuild.app/v1/store/design \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: store-design-1" \
-d '{"primary_color": "#0f766e", "show_hero": true, "hero_title": "New collection"}'
Response 200
{
"data": {
"updated": ["primary_color", "show_hero", "hero_title"],
"skipped": [],
"values": {"primary_color": "#0f766e", "show_hero": 1, "hero_title": "New collection"},
"change_id": 812
},
"meta": { "request_id": "...", "api_version": "v1" }
}
updated lists the fields written and values the value stored for each, after cleaning. skipped is an empty list when nothing was skipped, and otherwise an object such as {"hide_branding": "requires the unlimited plan"}.
The change is recorded and can be undone with POST /v1/changes/{change_id}/undo, using the change_id of the answer; it is null in the rare case the write was saved without an undo record, and GET /v1/changes?entity=store.design lists the earlier ones. An installed app's token cannot read or undo changes (403 forbidden, Apps cannot use this endpoint). A GET /v1/store/design sent right after the write returns the new values.
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | The body is not valid JSON, or Idempotency-Key is missing or malformed. |
| 403 | forbidden | Missing scope: store:write, or a merchant key whose store is not on an active Enterprise plan. |
| 404 | store_not_found | The store was deleted. |
| 413 | payload_too_large | The body is larger than 1 MB. |
| 422 | no_writable_fields | The body holds no design field, or every field it holds was skipped for the plan. |
| 422 | invalid_value | A field is an object or a list, or a value was refused, such as a navbar_style outside its list. |
| 422 | invalid_url | A link field uses a scheme other than https, http, mailto or tel. |
| 422 | invalid_pixel_id | facebook_pixel_id is not 15 to 17 digits. |
| 422 | idempotency_key_reuse | The same Idempotency-Key was used with another body. |
A 422 writes nothing.