X-Agent-Key: sq_agt_* (or a dashboard user session with X-Store-ID).
Scopes: read_online_store_navigation, write_online_store_navigation (menus);
read_content, write_content (pages, blogs, articles).
Every resource is scoped to the key’s store — an id from another store answers 404. Mutations
are audited and honour Idempotency-Key. Timestamps are RFC 3339 UTC; unset values are null.
A change reaches the live storefront’s data files within a short while of the response, with no
theme publish. Merchant guides: Navigation, Pages,
Blog posts.
Responses and errors
Handles
A handle is the URL segment and the key a theme setting stores. Lowercase letters, digits and single hyphens, up to 255 characters. Omithandle on create and it is generated from the title
("About Our Brand" → about-our-brand), de-duplicated with -2, -3, …. A generated page handle
that would collide with a built-in storefront page also gets a suffix ("About" → about-2). An
explicit handle is never rewritten — a collision is 409. Renaming a resource never changes its
handle; only an explicit handle update does.
Menus
Scopes:read_online_store_navigation · write_online_store_navigation.
GET /online_store/menus— summaries, default menus first, then by title. Every store hasmain-menuandfooter; they are created on first read if missing.POST /online_store/menus—{ "title", "handle"?, "items": MenuItemInput[] }→201data.menuGET /online_store/menus/{id}→data.menuPUT /online_store/menus/{id}—{ "title", "handle"?, "items" }. Replaces the whole item tree in one transaction. Itemids you send back are kept; items without one get a new id.DELETE /online_store/menus/{id}→data: { "deleted_id" }
MenuItemInput: { "id"?, "title", "type", "resource_id"?, "url"?, "items"? }.
Menu: { id, handle, title, is_default, items: MenuItem[], created_at, updated_at }.
MenuItem:
url is the storefront address the link resolves to now ("" when it resolves to nothing);
raw_url is the stored address of an http link. resource_missing: true means the linked resource
was deleted or is not on the storefront — the link is kept in the menu but left out of the storefront.
Item types
Validation:
title 1–255 characters; nesting at most 3 levels; at most 250 items per menu,
counting nested ones; a resource link’s resource_id must exist in the store when saved (an
unpublished page is accepted and reported resource_missing). An http url must be an absolute
http(s):// URL, a path starting with / (not //), or a mailto: / tel: link — empty, #…,
javascript: and data: are rejected.
The URL is derived from the resource’s current handle, so renaming a collection or page never
strands a menu link on an old address. On the storefront, a link that no longer resolves is omitted
together with its nested links.
Pages
Scopes:read_content · write_content.
GET /online_store/pages?query=&status=published|hidden|all&limit=&cursor=—data: { "pages": PageSummary[], "next_cursor" }, most recently updated first.querymatches title and handle;limit1–100, default 50.POST /online_store/pages—PageInput→201data.pageGET /online_store/pages/{id}→data.pagePATCH /online_store/pages/{id}— any subset ofPageInput→data.pageDELETE /online_store/pages/{id}→data: { "deleted_id" }
PageInput: { "title", "handle"?, "body_html"?, "published"?, "published_at"?, "template_suffix"?, "seo_title"?, "seo_description"? }
PageSummary omits body_html, template_suffix and the SEO fields.
Publishing: "published": true without published_at publishes now; published_at may be in the
past but not the future (there is no scheduled publishing). "published": false hides the page.
seo_description is at most 512 characters; body_html at most 1 MiB.
Blogs
Scopes:read_content · write_content.
GET /online_store/blogs→data.blogs, by titlePOST /online_store/blogs—{ "title", "handle"?, "template_suffix"?, "seo_title"?, "seo_description"? }→201data.blogGET /online_store/blogs/{id}·PATCH /online_store/blogs/{id}DELETE /online_store/blogs/{id}→data: { "deleted_id", "articles_deleted" }— deletes the blog’s articles
Articles
Scopes:read_content · write_content. One list across every blog.
GET /online_store/articles?blog_id=&query=&status=published|hidden|all&limit=&cursor=—data: { "articles": ArticleSummary[], "next_cursor" }, most recently updated firstPOST /online_store/articles—ArticleInput(blog_idrequired) →201data.articleGET /online_store/articles/{id}·PATCH /online_store/articles/{id}·DELETE /online_store/articles/{id}
ArticleInput: { "blog_id", "title", "handle"?, "author"?, "body_html"?, "summary_html"?, "image_url"?, "image_alt"?, "tags"?, "published"?, "published_at"?, "template_suffix"?, "seo_title"?, "seo_description"? }
ArticleSummary is the object above without body_html, summary_html, image_alt, tags,
template_suffix, the SEO fields and created_at.
- Handles are unique per blog. Changing
blog_idre-checks the handle in the target blog (409 HANDLE_TAKEN). tagsare trimmed and de-duplicated case-insensitively; each at most 255 characters, at most 250.summary_htmlat most 64 KiB;body_htmlat most 1 MiB. Publishing follows the same rules as pages.
HTML sanitization
body_html and summary_html are sanitized on write. Kept: headings, paragraphs, lists, links (with
target / rel), images (src, alt, width, height, loading), tables, figure /
figcaption, quotes, class attributes, and iframe embeds from https://www.youtube.com/embed/,
https://www.youtube-nocookie.com/embed/ and https://player.vimeo.com/video/. Removed: scripts,
style blocks, event-handler attributes and any other embed. The response carries the stored,
sanitized HTML.
Link resource picker
GET /online_store/link_resources?type=&query=&limit= · scope read_online_store_navigation.
type is product, collection, page, blog, article or policy; limit 1–50, default 20.
subtitle: "Hidden"); an article’s subtitle is its blog’s title.
Storefront data
GET /online_store/storefront_data · scopes read_content and read_online_store_navigation.
Returns exactly what the published storefront reads from data/menus.json, data/pages.json and
data/blogs.json, built from the live database — useful for previewing a theme that has not been
published.
menus: sorted by handle. Links that no longer resolve are omitted with their nested links.resourceisnullforfrontpage,catalog,collectionsandhttp; anarticleresource also carriesblog_handle.pages: published pages only.blogs: every blog, with its published articles newest first;tagsis the sorted union of those articles’ tags;imageisnullwhen a post has no featured image.