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.
| Operation | Endpoint | Risk |
|---|---|---|
| A store's page design | GET /organizations/{organizationId}/stores/{storeId}/design | read |
| Save a store's draft design | PUT /organizations/{organizationId}/stores/{storeId}/design | write |
| Change one section of a store's draft | PATCH /organizations/{organizationId}/stores/{storeId}/design/sections/{sectionId} | write |
| Publish a store's design | POST /organizations/{organizationId}/stores/{storeId}/design/publish | sensitive |
| Discard a store's draft design | POST /organizations/{organizationId}/stores/{storeId}/design/discard | write |
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).
| Permission | stores.read (Owner, Admin, Staff, Member) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | storeDesigns_get (toolset stores) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
storeId | path | string | Yes | The 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
| Field | Type | Description |
|---|---|---|
storeId | string | |
draft | object | The design being edited (what the staff preview shows). |
draft.version | integer | |
draft.pages | array of object | |
draft.pages[].slug | enum | One of home, about. |
draft.pages[].title | string | |
draft.pages[].sections | array of object | |
published | object | What shoppers see now. |
published.version | integer | |
published.pages | array of object | |
published.pages[].slug | enum | One of home, about. |
published.pages[].title | string | |
published.pages[].sections | array of object | |
usesDefault | boolean | Never designed: the default layout (banner, category tiles, products) from the settings. |
hasUnpublishedChanges | boolean | The draft differs from what shoppers see. |
designUpdatedAt | string (date-time) or null | |
designPublishedAt | string (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.
| Permission | stores.manage (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | storeDesigns_update (toolset stores) |
| Plan | Online stores: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
storeId | path | string | Yes | The store (GET /stores). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
design | object | Yes | The 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.version | 1 | No | |
design.pages | array of object | Yes | |
design.pages[].slug | enum | Yes | home: the store's front page; about: the optional About page (in the navigation). One of home, about. |
design.pages[].title | string | Yes | The page's name in the navigation. Up to 60 characters. |
design.pages[].sections | array of any | Yes | Every 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
| Field | Type | Description |
|---|---|---|
storeId | string | |
draft | object | The design being edited (what the staff preview shows). |
draft.version | integer | |
draft.pages | array of object | |
draft.pages[].slug | enum | One of home, about. |
draft.pages[].title | string | |
draft.pages[].sections | array of object | |
published | object | What shoppers see now. |
published.version | integer | |
published.pages | array of object | |
published.pages[].slug | enum | One of home, about. |
published.pages[].title | string | |
published.pages[].sections | array of object | |
usesDefault | boolean | Never designed: the default layout (banner, category tiles, products) from the settings. |
hasUnpublishedChanges | boolean | The draft differs from what shoppers see. |
designUpdatedAt | string (date-time) or null | |
designPublishedAt | string (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).
| Permission | stores.manage (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | storeDesigns_updateSection (toolset stores) |
| Plan | Online stores: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
storeId | path | string | Yes | The store (GET /stores). |
sectionId | path | string | Yes | The section's id within the page (GET …/design), not a database record. Up to 40 characters. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
page | enum | No | home: the store's front page; about: the optional About page (in the navigation). One of home, about. Default home. |
props | object | No | Props 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). |
hidden | boolean | No | Hide 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
| Field | Type | Description |
|---|---|---|
storeId | string | |
draft | object | The design being edited (what the staff preview shows). |
draft.version | integer | |
draft.pages | array of object | |
draft.pages[].slug | enum | One of home, about. |
draft.pages[].title | string | |
draft.pages[].sections | array of object | |
published | object | What shoppers see now. |
published.version | integer | |
published.pages | array of object | |
published.pages[].slug | enum | One of home, about. |
published.pages[].title | string | |
published.pages[].sections | array of object | |
usesDefault | boolean | Never designed: the default layout (banner, category tiles, products) from the settings. |
hasUnpublishedChanges | boolean | The draft differs from what shoppers see. |
designUpdatedAt | string (date-time) or null | |
designPublishedAt | string (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.
| Permission | stores.manage (Owner, Admin, Staff) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | storeDesigns_publish (toolset stores) |
| Plan | Online stores: the Grow plan and up. |
| Approval | Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in SKUFlow). See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
storeId | path | string | Yes | The 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
| Field | Type | Description |
|---|---|---|
storeId | string | |
draft | object | The design being edited (what the staff preview shows). |
draft.version | integer | |
draft.pages | array of object | |
draft.pages[].slug | enum | One of home, about. |
draft.pages[].title | string | |
draft.pages[].sections | array of object | |
published | object | What shoppers see now. |
published.version | integer | |
published.pages | array of object | |
published.pages[].slug | enum | One of home, about. |
published.pages[].title | string | |
published.pages[].sections | array of object | |
usesDefault | boolean | Never designed: the default layout (banner, category tiles, products) from the settings. |
hasUnpublishedChanges | boolean | The draft differs from what shoppers see. |
designUpdatedAt | string (date-time) or null | |
designPublishedAt | string (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.
| Permission | stores.manage (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | storeDesigns_discard (toolset stores) |
| Plan | Online stores: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
storeId | path | string | Yes | The store (GET /stores). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
to | enum | No | published: 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
| Field | Type | Description |
|---|---|---|
storeId | string | |
draft | object | The design being edited (what the staff preview shows). |
draft.version | integer | |
draft.pages | array of object | |
draft.pages[].slug | enum | One of home, about. |
draft.pages[].title | string | |
draft.pages[].sections | array of object | |
published | object | What shoppers see now. |
published.version | integer | |
published.pages | array of object | |
published.pages[].slug | enum | One of home, about. |
published.pages[].title | string | |
published.pages[].sections | array of object | |
usesDefault | boolean | Never designed: the default layout (banner, category tiles, products) from the settings. |
hasUnpublishedChanges | boolean | The draft differs from what shoppers see. |
designUpdatedAt | string (date-time) or null | |
designPublishedAt | string (date-time) or null |
Customer products API
REST endpoints for customer products in SKUFlow: 7 operations with parameters, request and response fields, permissions and curl examples.
Store imports API
REST endpoints for store imports in SKUFlow: 10 operations with parameters, request and response fields, permissions and curl examples.