Skip to main content

Store pages

Store pages are the merchant's text pages, such as About us, Delivery or Returns. Each page is written in Markdown. A published page lives at /pages/{slug} on the store and is listed in the store's sitemap.xml and llms.txt. A draft answers 404 on the store. These five endpoints list, read, create, change and delete the pages.

The merchant edits the same pages in the dashboard, in Customize, row Pages. See Store pages in the merchant docs.

Before you start​

  • Reads need store:read and writes need store:write. Merchant keys carry both.
  • POST, PATCH and DELETE need an Idempotency-Key. See Idempotency.
  • The API cannot upload images. An image in body_md is a link to a picture that is already online, written as ![text](https://...).

The page object​

FieldTypeNotes
idintThe page id.
slugstringThe end of the page address, after /pages/. 2 to 80 lowercase Latin letters, digits or dashes, starting and ending with a letter or a digit. Unique in the store.
titlestring1 to 120 characters.
body_mdstringThe text in Markdown, up to 65,536 bytes. See How the body is rendered.
seo_titlestring or nullThe title search engines show, up to 70 characters. null uses title.
seo_descriptionstring or nullThe description search engines show, up to 160 characters. null uses the first lines of the text.
statusstringdraft or published.
translationsobject or nullThe texts of the store's second language, keyed by language code, such as {"fr": {"title": "...", "body_md": "...", "seo_title": null, "seo_description": null}}, or null. See Second language.
urlstringThe full address of the page on the store.
created_atstringYYYY-MM-DD HH:MM:SS, server time.
updated_atstringYYYY-MM-DD HH:MM:SS, server time.

HTML tags in title, seo_title and seo_description are removed, and text over the limit is cut.

How the body is rendered​

  • Markdown is rendered in safe mode: raw HTML is escaped and shows as text.
  • A single line break in the text is kept as a line break.
  • A link to the store itself, such as /products, /category/12 or /pages/delivery, opens in the same tab. A link to another site opens in a new tab, and so does a link that starts with //.
  • A YouTube link alone on its line shows the video.

Second language​

translations is written only while the Multi-Language add-on is active on the store. Without it, the field is ignored and the stored value is kept. The key is the store's second language: fr for an Arabic store, ar for a French one. A buyer who browses the store in that language sees those texts, and an empty field falls back to the main field.

GET /v1/store/pages​

All the store's pages, drafts included, ordered by title. The items are summaries without the text: read one page for its body_md. The list is not paginated: a store has at most 25 pages.

Auth: platform key with store:read.

Request​

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

Response 200​

Each item carries id, slug, title, status, url and updated_at. cap is the number of pages the store's plan allows. max_pages is the hard limit for every plan.

{
"data": {
"items": [
{
"id": 7,
"slug": "retours",
"title": "Retours",
"status": "published",
"url": "https://my-store.dzbuild.app/pages/retours",
"updated_at": "2026-11-06 10:12:40"
}
],
"cap": 25,
"max_pages": 25
},
"meta": {"request_id": "3f1c9a7b20d4e865", "api_version": "v1"}
}

GET /v1/store/pages/{id}​

One page.

Auth: platform key with store:read.

Request​

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

Response 200​

The answer is the page object. A page that is not in the store answers 404 page_not_found.

POST /v1/store/pages​

Creates a page.

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

Body​

FieldTypeRequiredNotes
titlestringyes1 to 120 characters.
slugstringnoMade from the title when you leave it out. When that gives no usable slug (a title with no Latin letters or digits such as an Arabic one, a reserved word, or a slug another page uses), the page gets page-N. A slug you send is lowercased, then must be valid and free.
body_mdstringnoMarkdown, up to 65,536 bytes.
seo_titlestring or nullnoUp to 70 characters.
seo_descriptionstring or nullnoUp to 160 characters.
statusdraft or publishednoDefaults to draft. Publish only when the merchant asked.
translationsobject or nullnoSee Second language.

A slug must not be a word the store already uses for its own addresses, such as products, product, cart, checkout, category, track-order, landing, pages, sitemap, ar or fr. Such a slug answers 422 invalid_page.

Request​

curl -X POST 'https://api.dzbuild.app/v1/store/pages' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: page-create-retours-1" \
-d '{"title": "Retours", "slug": "retours", "body_md": "## Comment retourner un article\n\nÉcrivez-nous sur WhatsApp avec votre numéro de commande.", "status": "published"}'

Response 201​

{
"data": {
"page": {
"id": 7,
"slug": "retours",
"title": "Retours",
"body_md": "## Comment retourner un article\n\nÉcrivez-nous sur WhatsApp avec votre numéro de commande.",
"seo_title": null,
"seo_description": null,
"status": "published",
"translations": null,
"url": "https://my-store.dzbuild.app/pages/retours",
"created_at": "2026-11-06 10:12:40",
"updated_at": "2026-11-06 10:12:40"
},
"change_id": 90310
},
"meta": {"request_id": "8b2e04d1c9a7f356", "api_version": "v1"}
}

PATCH /v1/store/pages/{id}​

Changes only the fields you send. The body takes the fields of POST, all optional. A body with none of them answers 422 no_changes, and a call that changes nothing answers change_id: null.

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

  • A new slug changes the page address. The old address keeps answering with a 301 redirect to the new one, so shared links keep working. Setting the old slug back is allowed. Leaving slug out keeps the address, even when the title changes.
  • "status": "draft" takes the page off the store without deleting it.

Request​

curl -X PATCH 'https://api.dzbuild.app/v1/store/pages/7' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: page-7-seo-1" \
-d '{"seo_title": "Retours et échanges", "seo_description": "Comment retourner un article commandé sur notre boutique."}'

Response 200​

The answer has the same fields as the POST answer: page, the page after the change, and change_id.

DELETE /v1/store/pages/{id}​

Deletes a page. Its address on the store stops working at once.

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

Request​

curl -X DELETE 'https://api.dzbuild.app/v1/store/pages/7' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: page-7-delete-1"

Response 200​

{
"data": {
"deleted": true,
"id": 7,
"change_id": 90312
},
"meta": {"request_id": "c40a91e7b25d3f68", "api_version": "v1"}
}

Undo​

Every write answers with a change_id. POST /v1/changes/{change_id}/undo reverts that change. The undo needs store:write and an Idempotency-Key.

  • Undoing a PATCH puts back the page as it was before that call. When the page was deleted since, the undo answers 422 restore_target_missing.
  • Undoing a DELETE creates the page again under its old id and slug.
  • A create cannot be undone: the undo answers 422 nothing_to_restore. Delete the page instead.
  • When another page took the id or the slug of a deleted page since, or the store already holds 25 pages, the undo of the delete answers 409 page_restore_conflict. Rename or delete that page, then undo again.
  • A change undone a second time answers 409 already_undone.
  • Changes the merchant saves in Customize are not recorded, so they cannot be undone through the API.
  • GET /v1/changes?entity=store.page lists the page changes, newest first, with store:read. entity_id is the page id.
  • An installed app's token cannot read or undo changes: GET /v1/changes and the undo answer 403 forbidden (Apps cannot use this endpoint). Write answers still carry the change_id.
curl -X POST 'https://api.dzbuild.app/v1/changes/90312/undo' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: undo-90312"
{
"data": {
"undone": true,
"change_id": 90312,
"entity": "store.page",
"undo_change_id": 90315
},
"meta": {"request_id": "71d5e0a2c8b94f36", "api_version": "v1"}
}

Errors​

HTTPCodeCause
400bad_requestThe body is not a JSON object, the page id in the path is not a positive number, or Idempotency-Key is missing or malformed.
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, or API access requires an active Enterprise plan for a merchant key whose store is not on an active Enterprise plan.
403plan_requiredA create would go over the number of pages the plan allows. The error carries plan and cap.
404page_not_foundNo page with this id in the store.
409slug_takenAnother page of the store uses this slug. fields is [{"path": "slug", "code": "taken"}].
409write_conflictAnother write landed at the same moment. Read the page, then retry with a new Idempotency-Key.
409already_undoneUndo only: the change was already undone.
409page_restore_conflictUndo of a delete only: another page now uses the page's id or slug, or the store already holds 25 pages.
413payload_too_largeThe body is over 1 MB.
422invalid_pageA value was refused: a missing or empty title, a field that is not text, a malformed or reserved slug, a status other than draft and published, translations that is not an object, or a body_md over 65,536 bytes. fields gives {path, code} for the refused field, such as slug.
422limit_reachedThe store already has 25 pages. The error carries limit.
422no_changesA PATCH with none of the page fields.
422nothing_to_restoreUndo only: the change created the page.
422restore_target_missingUndo of a PATCH only: the page was deleted since.
422idempotency_key_reuseThe same Idempotency-Key was used with another body.
429rate_limitedToo many requests, including more than 30 page writes a minute for the store. Wait for Retry-After.
429too_many_concurrentMore than 5 page writes running at once for the store. Retry in a few seconds.
500server_errorThe request failed. Retry with the same Idempotency-Key.

An invalid_page answer looks like this.

{
"error": {
"code": "invalid_page",
"message": "slug: 2 to 80 lowercase latin letters, digits or dashes, not a store route",
"fields": [{"path": "slug", "code": "invalid"}]
},
"meta": {"request_id": "e9a3c17f04b26d58", "api_version": "v1"}
}

Limits​

  • 25 pages per store (max_pages), drafts included.
  • Plan cap (cap): 3 pages on Free or an expired plan, 25 from Pro. A store above its cap after a downgrade keeps its pages and can still read, change and delete them. A create answers 403 plan_required until the store is under its cap.
  • Body: body_md up to 65,536 bytes, and the request up to 1 MB.
  • Writes: 30 a minute and 5 at once per store, on top of the store's per-minute limit. See Rate limits.

MCP tools​

The MCP server, version 1.8.0, gives an AI assistant five page tools with the same rules: pages_list, page_get, page_create, page_update and page_delete. The page_delete tool tells the assistant to confirm with the merchant first.

This page for AI toolsView as MarkdownOpen in ChatGPTOpen in Claude