Automated Checks & Compliance¶
Every submission is validated before it reaches a human reviewer. A failure
is a hard 400 with a list of { code, severity, message } — nothing is
stored, so fix and resubmit.
App submission checks¶
Field rules¶
| Check | Rule |
|---|---|
| Name | Required, non-blank, ≤ 120 characters |
| Description | ≤ 5000 characters |
| Slug | Must match ^[a-z][a-z0-9-]{1,60}$ (derived from your name if you don't control it) |
| Version | Must be semver — ^\d+\.\d+\.\d+([-+].+)?$, e.g. 1.0.0, 2.1.0-beta |
| App URL | Required — an external-hosted app has to say where it lives |
| Tags | Must be an array, ≤ 20 tags, each ≤ 40 characters |
| Screenshots | ≤ 12, each URL safety-checked |
| Price | ≥ 0 |
There are no warning-level rules for apps. Everything above either passes or blocks the submission.
URL safety (anti-SSRF)¶
Applied to App URL, Redirect URL, Webhooks URL and the logo URL:
- Must parse as a URL.
- HTTPS only. Plain
http:is rejected, which also blocksjavascript:anddata:payloads. - Numeric-encoded hosts rejected — hex (
0x…), all-digit (2130706433), and leading-zero octal forms. - Private and internal hosts rejected —
localhost,*.local,*.internal,127.*,10.*,192.168.*,172.16–31.*,169.254.*, CGNAT100.64/10,0.0.0.0, and IPv6::*,fc*,fd*,fe80*.
The host is checked again with DNS resolution at webhook delivery time, so a public hostname that resolves to a private address will still fail later.
Allowlists¶
Unknown values are rejected outright — they are not ignored.
Permissions (11)
read_orders write_orders
read_products write_products
read_customers write_customers
read_inventory write_inventory
read_analytics read_shop
manage_webhooks
Events you may subscribe to (9)
order.created order.paid order.fulfilled order.cancelled
product.created product.updated
customer.created
app.installed app.uninstalled
ui_slots (6, phase-2 metadata only — nothing renders them)
storefront.product.below_price
storefront.product.below_add_to_cart
storefront.cart.footer
dashboard.order.detail.sidebar
dashboard.product.detail.sidebar
dashboard.nav.section
Slug ownership¶
A slug belongs to the developer who first published it. Submitting an app whose
slug is already owned by someone else fails with 409 — "The app identifier is
already in use by another developer." Resubmitting your own slug is an in-place
version update.
Theme package checks¶
The ZIP is validated on upload, before it is stored.
| Check | Rule |
|---|---|
| Archive | Must be a readable ZIP. Upload limit 50 MB |
| Manifest | theme.config.json must exist and be valid JSON |
| Manifest fields | name, slug, version, author all required |
| Slug | ^[a-z][a-z0-9-]{1,40}$ — note this is stricter than the app slug rule |
| Reserved slugs | Cannot be default, grid, manfare or general |
| Structure | A theme/ directory is required |
| Components | All nine required: index.ts, header.tsx, footer.tsx, product-card.tsx, single-product-page.tsx, category-page.tsx, cart-page.tsx, checkout-page.tsx, search-page.tsx |
| Templates | theme/templates/<type>.json must be valid JSON, <type> must be a known system page type, and every widget/section name must resolve — either to a platform registry entry or to your own x-<slug>-* namespace |
| Custom widgets | Each widget directory must be namespaced x-<slug>-* and contain a widget.json |
Content and code safety¶
Rejected in template strings: inline <script>, eval(, javascript:, inline
on*= handlers, srcdoc=.
Rejected in .ts / .tsx sources: Node built-in imports or requires, eval(,
new Function(.
Warning only (does not block): dangerouslySetInnerHTML. It is allowed, but
you own the sanitisation.
After upload an advisory security scan runs asynchronously. It never blocks the submission and never changes review status — it is information for the reviewer.
Run npm run validate in the preset kit before packaging; it catches most of
this locally.
What the platform does not check¶
Nothing here is enforced, so do not assume it is covered:
- No TLS certificate validation at review time beyond requiring
https. - No install-flow smoke test. Nobody clicks through your app automatically.
- No compliance webhooks. GDPR-style customer/shop data request and erasure webhooks do not exist on this platform.
- No embedded-app conformance checks — there is no App Bridge and no session token scheme to conform to.
- No uptime or performance monitoring of your hosted service.
See Compliance & Preliminary Steps for the pre-submit checklist.