Skip to main content

Create Storefront Block

Append one draft widget to a storefront (Creator page).

type is required and must be one of the 14 widget types below. Omit layout to use that type's default. layout of "" or null returns 422. Omit config (or send {}) to use English defaults for that type and layout. Sparse config is merged onto those defaults: nested objects merge, items and fields replace when sent. Unknown keys at any nesting level return 422.

The new widget is appended at the next order (an empty page starts at 1). The response includes a fresh preview_url of the saved draft. Visitors still see the last published page at public_url until Publish Storefront.

type cannot be changed later — hide the widget and create a new one. See Update Storefront Block.

Request​

POST /storefronts/{id}/blocks

Path Parameters​

ParameterTypeRequiredDescription
idstringYesStorefront UUID

Request Body​

Unknown top-level keys are rejected. Do not send id or order — both are assigned in the response.

ParameterTypeRequiredDescription
typestringYesWidget type. One of the 14 types.
layoutstringNoLayout token for this type. Omit for the type default. Must be in that type's allowlist. "" and null return 422.
is_hiddenbooleanNoHide the widget from visitors. Default false.
is_hidden_on_mobilebooleanNoHide the widget on mobile viewports. Default false.
configobjectNoSparse object merged onto defaults for this type and layout. See Config keys.

Defaults are for the type and layout together. A product created with layout 6x3 is not a 3x3 product with the token swapped.

product_id (and collection items[].product_id) must be a product UUID of this store, or "". Integers and UUIDs from another store return 422. list_uuid must be a UUID or "". Empty identifiers and clearable URL strings store as "", not null.

Widget Types​

type must be one of:

product, product_collection, link, media, gallery, map, zencal, logotypes, contact_form, newsletter_signup, free_download, text, space, divider.

Layouts​

Omit layout to use the default. A token that is not in that type's list, an empty string, or null returns 422.

TypeDefaultAllowed layouts
product3x36x4, 6x3, 3x4, 3x3, 2x3, 3x2, 6x1
product_collectionsliderslider, list, grid
link6x16x1, 6x2, 3x1, 2x1, 2x2, 1x1
media3x36x4, 6x3, 6x2, 6x1, 4x4, 4x2, 4x1, 3x3, 3x2, 3x1, 2x3, 2x2
gallerygridgrid, slider, asymmetric, asymmetric-mosaic
map3x36x2, 4x2, 3x3, 3x2, 2x3, 2x2
zencal6x46x4
logotypes3x11x1, 2x1, 3x1
contact_form6x36x3, 6x4, 3x3, 3x4
newsletter_signup6x36x3, 6x2, 3x3
free_download6x26x3, 6x2, 2x2, 3x1
text6x1same grid presets as media
spacespace-mdspace-xs, space-sm, space-md, space-lg, space-xl
dividerdivider-mddivider-xs, divider-sm, divider-md, divider-lg, divider-xl

Config Keys​

Every type accepts chrome keys: use_block_padding, use_block_surface, and is_block_highlighted (booleans). Unknown config keys return 422.

Nested objects (photo, media, hideable {value, is_hidden}, privacy, file) sparse-merge. items and fields replace the whole array when sent.

TypeConfig keys (plus chrome)Notes
productproduct_id, photo, title, price, old_price, description, link, cta_label, ownership_status, owned_cta_labelownership_status: show_all, hide_owned, or mark_as_owned. product_id UUID or "". link absolute HTTP(S) or "". cta_label is hideable; owned_cta_label is a string. photo is a Photo.
product_collectiontitle, columns, product_layout, show_prices, show_images, show_description, show_buttons, cta_label, source, sort_order, ownership_status, owned_cta_label, dynamic_rule, enable_show_more, initial_visible_count, itemstitle is hideable; cta_label is a string. source: manual or dynamic. sort_order: manual, best_sellers, newest_first, or personalized. dynamic_rule: on_promotion, has_countdown_timer, owned_by_visitor, not_yet_owned, related_to_owned, or all_products. product_layout: vertical or horizontal. items replaces; each item is sparse-merged onto product-item defaults (product_id, photo, title, price, old_price, description, link, cta_label). items[].product_id is a product UUID of this store or "".
textcontent, vertical_position, horizontal_alignmentvertical_position: top, center, or bottom. horizontal_alignment: left, center, right, or justify.
newsletter_signuplist_uuid, success_message, error_message, title, subtitle, cta_label, privacy, vertical_positionlist_uuid UUID or "". title, subtitle, and privacy are hideable. cta_label is a string.
contact_formfields, privacy, cta_label, cta_action, webhook_url, email, error_message, success_message, vertical_positioncta_action: email or webhook_url. webhook_url absolute HTTP(S) or "". email a valid address or null. fields replaces. See Contact field and Privacy.
mapembed_urlAbsolute HTTP(S) or "". Omit config to use the default Google Maps embed.
linkphoto, title, description, link, cta_labellink absolute HTTP(S) or "". description and cta_label are hideable.
mediamediaNested Photo. Default video_src_url is "".
gallerytitle, columns, gallery_layout, enable_show_more, initial_visible_count, itemstitle is hideable. gallery_layout: vertical, square, or horizontal. items replaces; each item is a Photo. Stored items are not padded to a minimum count.
spacechrome onlyHeight is the layout token.
dividervertical_positionPlus chrome. vertical_position: top, center, or bottom.
zencalembed_urlAbsolute HTTP(S) or "". Default "".
logotypesmediaNested Photo. Default fit is contain.
free_downloadlist_uuid, file, success_message, error_message, photo, title, description, cta_label, privacylist_uuid UUID or "". file is a File. description and privacy are hideable.

Every URL must be an absolute http:// or https:// URL, or "" to leave empty. Relative paths return 422.

Photo​

Used as photo, media, and each gallery items[] entry. Sparse-merged. Unknown keys return 422.

ParameterTypeDescription
media_typestringimage, video, or iframe
src_urlstringImage URL, or "" to clear
altstringAlt text
video_src_urlstringVideo URL, or "" to clear
video_autoplaybooleanWhether the video autoplays
video_controlsbooleanWhether playback controls are shown
video_loopbooleanWhether the video loops
iframe_src_urlstringIframe URL, or "" to clear
is_hiddenbooleanWhether the media is hidden
fitstringcover or contain

Hideable​

Copy that can be shown or hidden: { "value": string, "is_hidden": boolean }. Sparse-merged. Unknown keys return 422. Distinct from the widget's is_hidden flag.

File​

Used as config.file on free_download. Sparse-merged. Host a file with Upload Media (prepare type file) and send the returned name and file_url with external: false.

ParameterTypeDescription
namestringDisplay name
urlstringFile URL, or "" to clear. Absolute http:// or https:// only.
externalbooleanWhether the URL is an external link

Contact Field​

Each contact_form fields[] item. The array replaces when sent.

ParameterTypeDescription
typestringemail, text, phone, textarea, or switch
labelstringField label
placeholderstringPlaceholder text
input_namestringSubmitted field name
requiredbooleanWhether the field is required
orderintegerDisplay order of the field

Privacy​

contact_form privacy is this object (sparse-merged). Newsletter and free-download privacy is hideable instead.

ParameterTypeDescription
is_hiddenbooleanWhether the privacy line is hidden
textstringPrivacy copy
link_labelstringLink label
linkstringPrivacy-policy URL, or "" to clear
validation_messagestringShown when the visitor must accept privacy to continue

Example Requests​

Type only — layout becomes 3x3, config is English defaults, product_id is "":

curl -X POST "https://cart.easy.tools/api/v1/storefronts/b10f5980-d653-4494-ad1c-6a9d68c96d19/blocks" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "product"
}'

Product with a layout and a store product UUID. Other config keys stay at defaults for product + 6x3:

curl -X POST "https://cart.easy.tools/api/v1/storefronts/b10f5980-d653-4494-ad1c-6a9d68c96d19/blocks" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "product",
"layout": "6x3",
"config": {
"product_id": "3288e647-aab0-4289-957f-dac92e9b3ffe"
}
}'

Response​

Success Response (201)​

Returns the created widget plus a fresh preview_url of the saved draft. A later GET of the same widget omits preview_url.

{
"id": "372a48fe-9035-4b1c-9257-1aa1fdff415d",
"type": "product",
"layout": "6x3",
"order": 3,
"is_hidden": false,
"is_hidden_on_mobile": false,
"config": {
"use_block_padding": true,
"use_block_surface": true,
"is_block_highlighted": false,
"product_id": "3288e647-aab0-4289-957f-dac92e9b3ffe",
"photo": {
"media_type": "image",
"src_url": "",
"alt": "",
"video_src_url": "",
"video_autoplay": true,
"video_controls": false,
"video_loop": true,
"iframe_src_url": "",
"is_hidden": false,
"fit": "cover"
},
"title": "Product title",
"price": { "value": "$0.00", "is_hidden": false },
"old_price": { "value": "", "is_hidden": false },
"description": { "value": "Product description", "is_hidden": false },
"link": "",
"cta_label": { "value": "Buy now", "is_hidden": false },
"ownership_status": "show_all",
"owned_cta_label": "Open"
},
"preview_url": "https://cart.easy.tools/storefront-preview/b10f5980-d653-4494-ad1c-6a9d68c96d19?expires=1788346311&signature=9c2ff69cbe27454f9a200f8d1b6ff1e8dc77701f411b01b7459d80d4344ac939"
}

preview_url is a fresh signature on every write. See Draft preview.

Response Fields​

Block fields are documented on the Block object. Creates add preview_url:

FieldTypeNullableDescription
preview_urlstringNoTemporary signed URL of the saved draft. Expires after about one hour.

Error Responses​

Bad Request (400)​

Returned when {id} is not a UUID.

{
"message": "Invalid storefront ID"
}

Not Found Error (404)​

Returned when the storefront UUID does not exist, belongs to another store, or points at a deleted storefront.

{
"message": "Storefront not found"
}

Validation Error (422 Unprocessable Entity)​

Returned for an unknown key, a type that is not one of the 14, a layout that is not allowed for that type (including "" and null), a product_id that is not a product UUID of this store, an email that is not a valid address, or a value outside an enum / URL rule.

{
"message": "The foo field is not allowed.",
"errors": {
"foo": [
"The foo field is not allowed."
]
}
}

Unauthorized (401)​

{
"message": "Unauthenticated."
}

Forbidden (403)​

Returned when your API key has not been granted access to the requested store.

{
"message": "You do not have API access to the requested store."
}

Too Many Requests (429)​

Returned when you exceed the rate limit. The Retry-After response header gives the number of seconds to wait.

{
"message": "Too many requests. Please retry after 60 seconds."
}