DevelopersAPI reference

Store design API

REST endpoints for store design in SKUFlow: 5 operations with parameters, request and response fields, permissions and curl examples.

Base URL: https://app.skuflow.ai/api. Every call needs Authorization: Bearer skf_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.

OperationEndpointRisk
A store's page designGET /organizations/{organizationId}/stores/{storeId}/designread
Save a store's draft designPUT /organizations/{organizationId}/stores/{storeId}/designwrite
Change one section of a store's draftPATCH /organizations/{organizationId}/stores/{storeId}/design/sections/{sectionId}write
Publish a store's designPOST /organizations/{organizationId}/stores/{storeId}/design/publishsensitive
Discard a store's draft designPOST /organizations/{organizationId}/stores/{storeId}/design/discardwrite

A store's page design

GET /organizations/{organizationId}/stores/{storeId}/design

The store's home and About pages as sections: the draft being edited and the published design shoppers see. A store never designed answers the default layout made from its settings. Read-only. Call this before changing a section (its ids). Section types and their props: storeHero { layout overlay|centered|split, height small|medium|large, title, text, imageUrl, ctaLabel, ctaLink } (empty title/text/imageUrl = the store's banner settings; empty ctaLabel = Shop all); productGrid { heading, source all|category|picked, categoryId (a category of this store), productIds (store product ids of this store, GET /stores/{storeId}/products), limit 1-60, showViewAll }; categoryTiles { heading }; featuredProduct { storeProductId, heading, text, ctaLabel, ctaLink }; countdown { heading, text } (days to the order deadline); howItWorks { heading, steps [{ title, text }], showAllowance }; storeContact { heading, body } (the store's contact email and phone); and the website blocks text { heading, body }, about { layout imageRight|imageLeft, heading, body, imageUrl, highlights[] }, gallery { heading, images [{ url, caption }] }, testimonials { layout cards|quotes, heading, items [{ quote, author, location, rating 1-5 }] }, faq { heading, items [{ question, answer }] }. Images: POST /stores/images (/image-proxy/avatars/store-…) or https URLs. Buttons (storeHero, featuredProduct) take ctaLink, where the button goes, picked from the store's own pages (never a typed URL): { kind: shop } (default for storeHero), { kind: category, categoryId } (a category of this store, GET /stores/{storeId}), { kind: product, storeProductId } (a store product of this store, GET /stores/{storeId}/products; on a featuredProduct an empty storeProductId = that product, the default), { kind: about } (only when the store has an About page with a visible section), { kind: policy, policy: returns|guarantee|privacy }, { kind: cart }, or { kind: section, sectionId } (a section id on the same page). Send the whole ctaLink object (it replaces the old one). Saves refuse a target that is not in this store (400); a target removed later sends shoppers to the shop. Designs saved before ctaLink go to the shop (banner) or the product (featured product).

Permissionstores.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolstoreDesigns_get (toolset stores)

Parameters

NameInTypeRequiredDescription
storeIdpathstringYesThe store (GET /stores).

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/stores/{storeId}/design" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
storeIdstring
draftobjectThe design being edited (what the staff preview shows).
draft.versioninteger
draft.pagesarray of object
draft.pages[].slugenumOne of home, about.
draft.pages[].titlestring
draft.pages[].sectionsarray of object
publishedobjectWhat shoppers see now.
published.versioninteger
published.pagesarray of object
published.pages[].slugenumOne of home, about.
published.pages[].titlestring
published.pages[].sectionsarray of object
usesDefaultbooleanNever designed: the default layout (banner, category tiles, products) from the settings.
hasUnpublishedChangesbooleanThe draft differs from what shoppers see.
designUpdatedAtstring (date-time) or null
designPublishedAtstring (date-time) or null

Save a store's draft design

PUT /organizations/{organizationId}/stores/{storeId}/design

Replaces the whole DRAFT design (every page and section, in order; validated per type, a 400 names the field; categories and products must be this store's). Shoppers see nothing until POST /stores/{storeId}/design/publish. To change one section, PATCH …/design/sections/{sectionId} instead. Read GET …/design first.

Permissionstores.manage (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolstoreDesigns_update (toolset stores)
PlanOnline stores: the Grow plan and up.

Parameters

NameInTypeRequiredDescription
storeIdpathstringYesThe store (GET /stores).

Request body

FieldTypeRequiredDescription
designobjectYesThe design: a home page and optionally an About page. Section types and their props: storeHero { layout overlay|centered|split, height small|medium|large, title, text, imageUrl, ctaLabel, ctaLink } (empty title/text/imageUrl = the store's banner settings; empty ctaLabel = Shop all); productGrid { heading, source all|category|picked, categoryId (a category of this store), productIds (store product ids of this store, GET /stores/{storeId}/products), limit 1-60, showViewAll }; categoryTiles { heading }; featuredProduct { storeProductId, heading, text, ctaLabel, ctaLink }; countdown { heading, text } (days to the order deadline); howItWorks { heading, steps [{ title, text }], showAllowance }; storeContact { heading, body } (the store's contact email and phone); and the website blocks text { heading, body }, about { layout imageRight|imageLeft, heading, body, imageUrl, highlights[] }, gallery { heading, images [{ url, caption }] }, testimonials { layout cards|quotes, heading, items [{ quote, author, location, rating 1-5 }] }, faq { heading, items [{ question, answer }] }. Images: POST /stores/images (/image-proxy/avatars/store-…) or https URLs. Buttons (storeHero, featuredProduct) take ctaLink, where the button goes, picked from the store's own pages (never a typed URL): { kind: shop } (default for storeHero), { kind: category, categoryId } (a category of this store, GET /stores/{storeId}), { kind: product, storeProductId } (a store product of this store, GET /stores/{storeId}/products; on a featuredProduct an empty storeProductId = that product, the default), { kind: about } (only when the store has an About page with a visible section), { kind: policy, policy: returns|guarantee|privacy }, { kind: cart }, or { kind: section, sectionId } (a section id on the same page). Send the whole ctaLink object (it replaces the old one). Saves refuse a target that is not in this store (400); a target removed later sends shoppers to the shop. Designs saved before ctaLink go to the shop (banner) or the product (featured product).
design.version1No
design.pagesarray of objectYes
design.pages[].slugenumYeshome: the store's front page; about: the optional About page (in the navigation). One of home, about.
design.pages[].titlestringYesThe page's name in the navigation. Up to 60 characters.
design.pages[].sectionsarray of anyYesEvery section of the page in order: { id, type, hidden, props }. Up to 30 items.

Example

curl -X PUT "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/stores/{storeId}/design" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"design":{"pages":[{"slug":"home","title":"string","sections":[]}]}}'

Response

200: the answer's fields
FieldTypeDescription
storeIdstring
draftobjectThe design being edited (what the staff preview shows).
draft.versioninteger
draft.pagesarray of object
draft.pages[].slugenumOne of home, about.
draft.pages[].titlestring
draft.pages[].sectionsarray of object
publishedobjectWhat shoppers see now.
published.versioninteger
published.pagesarray of object
published.pages[].slugenumOne of home, about.
published.pages[].titlestring
published.pages[].sectionsarray of object
usesDefaultbooleanNever designed: the default layout (banner, category tiles, products) from the settings.
hasUnpublishedChangesbooleanThe draft differs from what shoppers see.
designUpdatedAtstring (date-time) or null
designPublishedAtstring (date-time) or null

Change one section of a store's draft

PATCH /organizations/{organizationId}/stores/{storeId}/design/sections/{sectionId}

Merges props into one section of the DRAFT design (only the props sent change) and/or shows or hides it. 404 when the page has no such section (GET …/design for the ids). Shoppers see it once the design is published (POST …/design/publish). To change where a button goes, send props.ctaLink, e.g. { "ctaLink": { "kind": "category", "categoryId": "…" } } (kinds shop, category, product, about, policy, cart, section; see the props guide).

Permissionstores.manage (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolstoreDesigns_updateSection (toolset stores)
PlanOnline stores: the Grow plan and up.

Parameters

NameInTypeRequiredDescription
storeIdpathstringYesThe store (GET /stores).
sectionIdpathstringYesThe section's id within the page (GET …/design), not a database record. Up to 40 characters.

Request body

FieldTypeRequiredDescription
pageenumNohome: the store's front page; about: the optional About page (in the navigation). One of home, about. Default home.
propsobjectNoProps to change for the section's type. Section types and their props: storeHero { layout overlay|centered|split, height small|medium|large, title, text, imageUrl, ctaLabel, ctaLink } (empty title/text/imageUrl = the store's banner settings; empty ctaLabel = Shop all); productGrid { heading, source all|category|picked, categoryId (a category of this store), productIds (store product ids of this store, GET /stores/{storeId}/products), limit 1-60, showViewAll }; categoryTiles { heading }; featuredProduct { storeProductId, heading, text, ctaLabel, ctaLink }; countdown { heading, text } (days to the order deadline); howItWorks { heading, steps [{ title, text }], showAllowance }; storeContact { heading, body } (the store's contact email and phone); and the website blocks text { heading, body }, about { layout imageRight|imageLeft, heading, body, imageUrl, highlights[] }, gallery { heading, images [{ url, caption }] }, testimonials { layout cards|quotes, heading, items [{ quote, author, location, rating 1-5 }] }, faq { heading, items [{ question, answer }] }. Images: POST /stores/images (/image-proxy/avatars/store-…) or https URLs. Buttons (storeHero, featuredProduct) take ctaLink, where the button goes, picked from the store's own pages (never a typed URL): { kind: shop } (default for storeHero), { kind: category, categoryId } (a category of this store, GET /stores/{storeId}), { kind: product, storeProductId } (a store product of this store, GET /stores/{storeId}/products; on a featuredProduct an empty storeProductId = that product, the default), { kind: about } (only when the store has an About page with a visible section), { kind: policy, policy: returns|guarantee|privacy }, { kind: cart }, or { kind: section, sectionId } (a section id on the same page). Send the whole ctaLink object (it replaces the old one). Saves refuse a target that is not in this store (400); a target removed later sends shoppers to the shop. Designs saved before ctaLink go to the shop (banner) or the product (featured product).
hiddenbooleanNoHide the section from shoppers (kept in the design).

Example

curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/stores/{storeId}/design/sections/{sectionId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"page":"home","props":{},"hidden":true}'

Response

200: the answer's fields
FieldTypeDescription
storeIdstring
draftobjectThe design being edited (what the staff preview shows).
draft.versioninteger
draft.pagesarray of object
draft.pages[].slugenumOne of home, about.
draft.pages[].titlestring
draft.pages[].sectionsarray of object
publishedobjectWhat shoppers see now.
published.versioninteger
published.pagesarray of object
published.pages[].slugenumOne of home, about.
published.pages[].titlestring
published.pages[].sectionsarray of object
usesDefaultbooleanNever designed: the default layout (banner, category tiles, products) from the settings.
hasUnpublishedChangesbooleanThe draft differs from what shoppers see.
designUpdatedAtstring (date-time) or null
designPublishedAtstring (date-time) or null

Publish a store's design

POST /organizations/{organizationId}/stores/{storeId}/design/publish

Customer-visible: the draft design becomes what shoppers see on the storefront at once (an open store changes immediately). Checked again first: a product grid or featured product naming a product no longer in the store is 400.

Permissionstores.manage (Owner, Admin, Staff)
Risksensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolstoreDesigns_publish (toolset stores)
PlanOnline stores: the Grow plan and up.
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in SKUFlow). See Approvals.

Parameters

NameInTypeRequiredDescription
storeIdpathstringYesThe store (GET /stores).

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/stores/{storeId}/design/publish" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
storeIdstring
draftobjectThe design being edited (what the staff preview shows).
draft.versioninteger
draft.pagesarray of object
draft.pages[].slugenumOne of home, about.
draft.pages[].titlestring
draft.pages[].sectionsarray of object
publishedobjectWhat shoppers see now.
published.versioninteger
published.pagesarray of object
published.pages[].slugenumOne of home, about.
published.pages[].titlestring
published.pages[].sectionsarray of object
usesDefaultbooleanNever designed: the default layout (banner, category tiles, products) from the settings.
hasUnpublishedChangesbooleanThe draft differs from what shoppers see.
designUpdatedAtstring (date-time) or null
designPublishedAtstring (date-time) or null

Discard a store's draft design

POST /organizations/{organizationId}/stores/{storeId}/design/discard

Throws the draft away: back to what shoppers see (to: published), or start over from the default layout made from the store's settings (to: default, still a draft until published). Shoppers see no change.

Permissionstores.manage (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolstoreDesigns_discard (toolset stores)
PlanOnline stores: the Grow plan and up.

Parameters

NameInTypeRequiredDescription
storeIdpathstringYesThe store (GET /stores).

Request body

FieldTypeRequiredDescription
toenumNopublished: the live design; default: the layout made from the settings. One of published, default. Default published.

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/stores/{storeId}/design/discard" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"published"}'

Response

200: the answer's fields
FieldTypeDescription
storeIdstring
draftobjectThe design being edited (what the staff preview shows).
draft.versioninteger
draft.pagesarray of object
draft.pages[].slugenumOne of home, about.
draft.pages[].titlestring
draft.pages[].sectionsarray of object
publishedobjectWhat shoppers see now.
published.versioninteger
published.pagesarray of object
published.pages[].slugenumOne of home, about.
published.pages[].titlestring
published.pages[].sectionsarray of object
usesDefaultbooleanNever designed: the default layout (banner, category tiles, products) from the settings.
hasUnpublishedChangesbooleanThe draft differs from what shoppers see.
designUpdatedAtstring (date-time) or null
designPublishedAtstring (date-time) or null

On this page