A landing page is a focused, single-product conversion page. They're independent of the storefront catalogue — you can have a landing page with no live product (for upcoming launches), or one tied to a specific product for paid ads.
Sections (image carousels, fake visitors, countdowns, etc.) are managed in the dashboard at v1; the API CRUDs the parent record only. A v1.1 update will expose section CRUD too.
Plan limits
Plan | Landing pages (all statuses — drafts count) |
Free | 0 (one-time purchase: 1000 DZD/lifetime each) |
Pro | 3 |
Unlimited / Enterprise | unlimited |
The cap is enforced by the dashboard create/duplicate flows only, counting every landing page including drafts. The API enforces nothing: POST /v1/landing-pages followed by /publish bypasses the cap entirely, and on a paid plan the extra pages render live on the storefront. Free-plan pages stay invisible unless the page was purchased (is_purchased).
GET /v1/landing-pages
List landing pages. Cursor-paginated. Cached for 30 s — check the X-Cache: HIT|MISS response header. GET /v1/landing-pages/{id} is not cached.
Auth: any active platform key for the store (landing_pages:read is not enforced at v1; only landing_pages:write is checked, on the write endpoints).
Query parameters
Param | Type | Notes |
| int 1–200 | Default 50 |
| string | Opaque |
|
| Filter |
An unrecognised status is ignored, returning all pages rather than a 400.
Response 200
{
"data": {
"items": [
{
"id": 42,
"title": "Black T-Shirt — 30% off",
"slug": "black-tshirt-30-off",
"status": "active",
"language": "ar",
"product_id": 26,
"views": 1543,
"is_purchased": false,
"created_at": "2026-03-01 10:00:00",
"updated_at": "2026-03-15 14:22:11"
}
],
"next_cursor": null,
"has_more": false
}
}
GET /v1/landing-pages/{id}
Detail with section_count.
{
"data": {
"id": 42,
"title": "Black T-Shirt — 30% off",
"slug": "black-tshirt-30-off",
"status": "active",
"language": "ar",
"product_id": 26,
"views": 1543,
"is_purchased": false,
"meta_title": "Black T-Shirt — Cotton 200gsm — 30% off | DZBuild",
"meta_description": "Limited-time offer on our cotton black t-shirt.",
"section_count": 7,
"created_at": "2026-03-01 10:00:00",
"updated_at": "2026-03-15 14:22:11"
}
}
Field reference
Field | Notes |
| Strict |
|
|
| The linked product, or |
| Read-only. Counted each time the public page is viewed; the API cannot write it and there is no way to reset it. |
|
|
| Detail endpoint only — a live count of the page's sections, computed per request. |
| SEO tags. See the note under create. |
POST /v1/landing-pages — create
Auth: platform key with landing_pages:write. Requires Idempotency-Key.
Body
Field | Type | Required | Notes |
| string 1–255 | ✅ | |
| string | Auto-derived from | |
|
| Default | |
|
| Default | |
| int | Must belong to your store; the page links to this product | |
| string ≤ 255 | SEO title. Omit it via the API and it is stored and returned as | |
| string | SEO description |
Slugs are made unique within your store by appending -2, -3, … An empty slug base falls back to landing- plus 6 hex characters.
Errors
Code | Cause |
| Wrong Content-Type or malformed JSON |
| Missing or over-long title |
| Cross-store id |
Request
curl -X POST 'https://api.dzbuild.app/v1/landing-pages' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"title": "Black T-Shirt — 30% off",
"language": "ar",
"product_id": 26,
"status": "draft"
}'
Returns 200 (not 201) and the same shape as GET /v1/landing-pages/{id}. The new landing page has zero sections — populate them in the dashboard.
PATCH /v1/landing-pages/{id}
Partial update.
PATCH validates more strictly than create: an invalid status returns 400 bad_request ("status must be active or draft") and an invalid language returns 400 ("language must be ar, fr, or en") instead of being coerced. title must still be 1–255 characters. A slug sent on PATCH is normalised, unlike on create.
curl -X PATCH 'https://api.dzbuild.app/v1/landing-pages/42' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "title": "Black T-Shirt — Spring promo" }'
Renaming auto-regenerates slug only if you didn't pass slug explicitly.
POST /v1/landing-pages/{id}/publish
Convenience: flip status to active. Equivalent to PATCH ... { status: "active" }.
curl -X POST 'https://api.dzbuild.app/v1/landing-pages/42/publish' \ -H "Authorization: Bearer $DZ_KEY" \ -H "Idempotency-Key: publish-42-$(date +%s)"
DELETE /v1/landing-pages/{id}
Hard delete. The page's sections are removed with it.
curl -X DELETE 'https://api.dzbuild.app/v1/landing-pages/42' \ -H "Authorization: Bearer $DZ_KEY" \ -H "Idempotency-Key: del-42"
Response: { "data": { "deleted": true, "id": 42 } }.