@wix/agent-skills 1.15.1 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/README.md +3 -7
  2. package/package.json +1 -1
  3. package/skills/wix-app/SKILL.md +4 -1
  4. package/skills/wix-app/references/APP_TOOLS.md +134 -0
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +1 -1
  6. package/skills/wix-app/references/DASHBOARD_PAGE.md +0 -10
  7. package/skills/wix-app/references/DATA_COLLECTION.md +1 -1
  8. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +42 -8
  9. package/skills/wix-app/references/SERVICE_PLUGIN.md +12 -10
  10. package/skills/wix-app/references/app-tools/TOOLS.md +75 -0
  11. package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +2 -2
  12. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +172 -0
  13. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +143 -0
  14. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +23 -2
  15. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +29 -0
  16. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +1 -1
  17. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +60 -0
  18. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +27 -2
  19. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +5 -3
  20. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +24 -7
  21. package/skills/wix-app/references/editor-react-component/PARTS.md +15 -2
  22. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +2 -3
  23. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +187 -0
  24. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +13 -9
  25. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +4 -0
  26. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +4 -0
  27. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +3 -1
  28. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +4 -0
  29. package/skills/wix-app/references/service-plugin/TOOLS_PROVIDER.md +54 -0
  30. package/skills/wix-app/references/stores/QUERY.md +32 -0
  31. package/skills/wix-app/scripts/scan-a11y-code.cjs +777 -0
  32. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +201 -0
  33. package/skills/wix-docs/SKILL.md +35 -3
  34. package/skills/wix-headless/SKILL.md +3 -1
  35. package/skills/wix-headless/references/CAPABILITIES.md +16 -3
  36. package/skills/wix-headless/references/CONTENT.md +36 -0
  37. package/skills/wix-headless/references/DESIGN.md +54 -0
  38. package/skills/wix-headless/references/DISCOVERY.md +24 -0
  39. package/skills/wix-headless/references/IMAGE_GENERATION.md +10 -0
  40. package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
  41. package/skills/wix-headless/references/SEED.md +1 -1
  42. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +3 -2
  43. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +560 -102
  44. package/skills/wix-headless/references/inline-recipes/setup-forms.md +210 -143
  45. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +32 -23
  46. package/skills/wix-headless/references/managed/CONNECT.md +1 -1
  47. package/skills/wix-headless/references/managed/CREATE.md +14 -0
  48. package/skills/wix-headless/references/managed/DEPLOYMENT.md +25 -0
  49. package/skills/wix-manage/SKILL.md +130 -7
  50. package/skills/wix-manage/references/accessibility/scan-site-accessibility.md +98 -0
  51. package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +40 -0
  52. package/skills/wix-manage/references/app-installation/app-installation-dashboard-navigation.md +28 -0
  53. package/skills/wix-manage/references/blog/blog-dashboard-navigation.md +56 -0
  54. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +31 -6
  55. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -1
  56. package/skills/wix-manage/references/bookings/bookings-dashboard-navigation.md +63 -0
  57. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +10 -1
  58. package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +44 -0
  59. package/skills/wix-manage/references/cms/cms-data-items-crud.md +31 -3
  60. package/skills/wix-manage/references/cms/cms-publishing-flow.md +287 -0
  61. package/skills/wix-manage/references/cms/cms-schema-management.md +27 -1
  62. package/skills/wix-manage/references/contacts/contacts-dashboard-navigation.md +46 -0
  63. package/skills/wix-manage/references/contacts/create-a-contact.md +82 -0
  64. package/skills/wix-manage/references/contacts/update-a-contact.md +119 -0
  65. package/skills/wix-manage/references/dashboard-navigation/dashboard-navigation.md +82 -0
  66. package/skills/wix-manage/references/dashboard-navigation/routes.json +1733 -0
  67. package/skills/wix-manage/references/domains/domains-dashboard-navigation.md +32 -0
  68. package/skills/wix-manage/references/ecommerce/ecom-pricing.md +4 -4
  69. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  70. package/skills/wix-manage/references/ecommerce/gift-cards/ecom-gift-cards-goal-sell-gift-cards.md +338 -0
  71. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +42 -78
  72. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
  73. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +1 -1
  74. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +1 -1
  75. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +90 -92
  76. package/skills/wix-manage/references/events/create-wix-event.md +176 -0
  77. package/skills/wix-manage/references/events/manage-wix-events.md +174 -0
  78. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +44 -0
  79. package/skills/wix-manage/references/get-paid/get-paid-dashboard-navigation.md +52 -0
  80. package/skills/wix-manage/references/google-ads/billing-and-payment.md +80 -0
  81. package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +212 -0
  82. package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +110 -0
  83. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +25 -0
  84. package/skills/wix-manage/references/google-ads/install-and-create-account.md +155 -0
  85. package/skills/wix-manage/references/google-ads/manage-campaign-lifecycle.md +63 -0
  86. package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +155 -0
  87. package/skills/wix-manage/references/marketing/marketing-dashboard-navigation.md +52 -0
  88. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +99 -1
  89. package/skills/wix-manage/references/pricing-plans/pricing-plans-dashboard-navigation.md +45 -0
  90. package/skills/wix-manage/references/restaurants/restaurants-dashboard-navigation.md +68 -0
  91. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +94 -125
  92. package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +48 -9
  93. package/skills/wix-manage/references/site-properties/site-properties-dashboard-navigation.md +31 -0
  94. package/skills/wix-manage/references/sites/create-headless-site.md +52 -0
  95. package/skills/wix-manage/references/sites/create-site-from-template.md +2 -25
  96. package/skills/wix-manage/references/sites/site-import.md +217 -192
  97. package/skills/wix-manage/references/sites/sites-dashboard-navigation.md +29 -0
  98. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +17 -1
  99. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +26 -8
  100. package/skills/wix-manage/references/stores/stores-dashboard-navigation.md +65 -0
  101. package/skills/wix-manage/references/stores/update-product-with-options.md +39 -7
  102. package/skills/wix-replatform/.publish-manifest.json +8 -0
  103. package/skills/wix-replatform/SKILL.md +693 -0
  104. package/skills/wix-replatform/lib/artifact-freshness.js +215 -0
  105. package/skills/wix-replatform/lib/completion-report.js +200 -0
  106. package/skills/wix-replatform/lib/config-env.js +59 -0
  107. package/skills/wix-replatform/lib/execution-manifest.js +185 -0
  108. package/skills/wix-replatform/lib/execution-state.js +173 -0
  109. package/skills/wix-replatform/lib/import-recovery.js +313 -0
  110. package/skills/wix-replatform/lib/local-state.js +642 -0
  111. package/skills/wix-replatform/lib/orchestration-preflight.js +143 -0
  112. package/skills/wix-replatform/lib/orchestration-router.js +122 -0
  113. package/skills/wix-replatform/lib/orchestration-state.js +455 -0
  114. package/skills/wix-replatform/lib/progress-log.js +224 -0
  115. package/skills/wix-replatform/lib/progress-log.sh +140 -0
  116. package/skills/wix-replatform/lib/url-preservation-state.js +391 -0
  117. package/skills/wix-replatform/resources/rp-discovery/SKILL.md +184 -0
  118. package/skills/wix-replatform/resources/rp-execute-import/SKILL.md +529 -0
  119. package/skills/wix-replatform/resources/rp-execute-setup/SKILL.md +316 -0
  120. package/skills/wix-replatform/resources/rp-execute-setup/scripts/mint-token.sh +64 -0
  121. package/skills/wix-replatform/resources/rp-import-codegen/SKILL.md +1114 -0
  122. package/skills/wix-replatform/resources/rp-mapper/SKILL.md +430 -0
  123. package/skills/wix-replatform/resources/rp-mapper/lib/mapping-resolve.js +217 -0
  124. package/skills/wix-replatform/resources/rp-mapper/scripts/resolve-mapping.js +148 -0
  125. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +378 -0
  126. package/skills/wix-replatform/resources/rp-setup-discovery/SKILL.md +183 -0
  127. package/skills/wix-replatform/resources/rp-source-csv/SKILL.md +478 -0
  128. package/skills/wix-replatform/resources/rp-source-csv/lib/canonical-record.js +136 -0
  129. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fileset.js +0 -0
  130. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-fingerprint.js +310 -0
  131. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-layout.js +1081 -0
  132. package/skills/wix-replatform/resources/rp-source-csv/lib/csv-parse.js +618 -0
  133. package/skills/wix-replatform/resources/rp-source-csv/scripts/csv-discovery.js +949 -0
  134. package/skills/wix-replatform/resources/rp-source-csv/source-schema.example.json +196 -0
  135. package/skills/wix-replatform/resources/rp-source-csv/vendors/bigcommerce.json +66 -0
  136. package/skills/wix-replatform/resources/rp-source-csv/vendors/magento.json +60 -0
  137. package/skills/wix-replatform/resources/rp-source-csv/vendors/shopify.json +95 -0
  138. package/skills/wix-replatform/resources/rp-source-csv/vendors/woocommerce.json +82 -0
  139. package/skills/wix-replatform/resources/rp-source-wordpress/SKILL.md +256 -0
  140. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-http.js +249 -0
  141. package/skills/wix-replatform/resources/rp-source-wordpress/lib/wp-route-classifier.js +444 -0
  142. package/skills/wix-replatform/resources/rp-source-wordpress/scripts/wp-discovery.js +774 -0
  143. package/skills/wix-replatform/resources/rp-source-wordpress/source-schema.example.json +71 -0
  144. package/skills/wix-replatform/resources/rp-target-wix/SKILL.md +632 -0
  145. package/skills/wix-replatform/resources/rp-target-wix/SPEC-product-reviews-and-blog-authorship.md +330 -0
  146. package/skills/wix-replatform/resources/rp-target-wix/domains/README.md +21 -0
  147. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/domain.json +19 -0
  148. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/category.json +37 -0
  149. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/comment.json +37 -0
  150. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/post.json +39 -0
  151. package/skills/wix-replatform/resources/rp-target-wix/domains/blog/entities/tag.json +35 -0
  152. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/domain.json +14 -0
  153. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/collection.json +35 -0
  154. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/data-item.json +36 -0
  155. package/skills/wix-replatform/resources/rp-target-wix/domains/cms/entities/reference.json +35 -0
  156. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/domain.json +14 -0
  157. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/contact.json +131 -0
  158. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/email-subscription.json +37 -0
  159. package/skills/wix-replatform/resources/rp-target-wix/domains/crm/entities/label.json +37 -0
  160. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/domain.json +21 -0
  161. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-line-item.json +37 -0
  162. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order-refund.json +37 -0
  163. package/skills/wix-replatform/resources/rp-target-wix/domains/ecom/entities/order.json +97 -0
  164. package/skills/wix-replatform/resources/rp-target-wix/domains/index.json +528 -0
  165. package/skills/wix-replatform/resources/rp-target-wix/domains/media/domain.json +14 -0
  166. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-file.json +38 -0
  167. package/skills/wix-replatform/resources/rp-target-wix/domains/media/entities/media-folder.json +37 -0
  168. package/skills/wix-replatform/resources/rp-target-wix/domains/members/domain.json +13 -0
  169. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/badge.json +37 -0
  170. package/skills/wix-replatform/resources/rp-target-wix/domains/members/entities/member.json +53 -0
  171. package/skills/wix-replatform/resources/rp-target-wix/domains/schema.json +84 -0
  172. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/domain.json +25 -0
  173. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/category.json +37 -0
  174. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/coupon.json +37 -0
  175. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/inventory-item.json +38 -0
  176. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product-tag.json +37 -0
  177. package/skills/wix-replatform/resources/rp-target-wix/domains/stores/entities/product.json +90 -0
  178. package/skills/wix-replatform/resources/rp-target-wix/lib/audit-summary.js +64 -0
  179. package/skills/wix-replatform/resources/rp-target-wix/lib/contract-ledger.js +141 -0
  180. package/skills/wix-replatform/resources/rp-target-wix/lib/domain-knowledge.js +384 -0
  181. package/skills/wix-replatform/resources/rp-target-wix/lib/ndjson.js +260 -0
  182. package/skills/wix-replatform/resources/rp-target-wix/lib/stores-verification.js +238 -0
  183. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-build.js +237 -0
  184. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-target-spec.js +238 -0
  185. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +2219 -0
  186. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge-validate.js +31 -0
  187. package/skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge.js +100 -0
  188. package/skills/wix-replatform/resources/rp-target-wix/scripts/verify-stores.js +107 -0
  189. package/skills/wix-replatform/resources/rp-telemetry/SKILL.md +344 -0
  190. package/skills/wix-replatform/resources/rp-telemetry/lib/bi-sink.js +250 -0
  191. package/skills/wix-replatform/resources/rp-telemetry/lib/telemetry-recorder.js +1927 -0
  192. package/skills/wix-replatform/resources/rp-telemetry/scripts/meter-from-audit.js +83 -0
  193. package/skills/wix-replatform/resources/rp-telemetry/scripts/rp-telemetry.js +141 -0
  194. package/skills/wix-replatform/scripts/artifact-freshness.js +76 -0
  195. package/skills/wix-replatform/scripts/execution-manifest-validate.js +43 -0
  196. package/skills/wix-replatform/scripts/execution-state-prepare.js +128 -0
  197. package/skills/wix-replatform/scripts/orchestration-preflight.js +48 -0
  198. package/skills/wix-replatform/scripts/orchestration-route.js +46 -0
  199. package/skills/wix-replatform/scripts/orchestration-state.js +245 -0
  200. package/skills/wix-vibe-headless/SKILL.md +49 -25
  201. package/skills/wix-vibe-headless/install/deploy.cjs +156 -0
  202. package/skills/wix-vibe-headless/install/pin-agents-md.cjs +34 -0
  203. package/skills/wix-vibe-headless/platforms/README.md +8 -4
  204. package/skills/wix-vibe-headless/platforms/base44.md +111 -101
  205. package/skills/wix-vibe-headless/platforms/generic.md +99 -64
  206. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +226 -119
  207. package/skills/wix-vibe-headless/references/blog/app/components/PostCard.jsx +43 -0
  208. package/skills/wix-vibe-headless/references/blog/app/components/PostChips.jsx +25 -0
  209. package/skills/wix-vibe-headless/references/blog/app/components/PostGrid.jsx +15 -0
  210. package/skills/wix-vibe-headless/references/blog/app/context/TaxonomyContext.jsx +35 -0
  211. package/skills/wix-vibe-headless/references/blog/app/hooks/usePostDetail.js +38 -0
  212. package/skills/wix-vibe-headless/references/blog/app/pages/Blog.jsx +40 -0
  213. package/skills/wix-vibe-headless/references/blog/app/pages/CategoryPage.jsx +54 -0
  214. package/skills/wix-vibe-headless/references/blog/app/pages/PostDetail.jsx +65 -0
  215. package/skills/wix-vibe-headless/references/blog/app/pages/TagPage.jsx +50 -0
  216. package/skills/wix-vibe-headless/references/blog/seed/SEED.md +103 -0
  217. package/skills/wix-vibe-headless/references/blog/seed/seed-blog.js +270 -0
  218. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +256 -149
  219. package/skills/wix-vibe-headless/references/bookings/app/components/BookingForm.jsx +65 -0
  220. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceCard.jsx +47 -0
  221. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceGrid.jsx +13 -0
  222. package/skills/wix-vibe-headless/references/bookings/app/components/SlotPicker.jsx +126 -0
  223. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +108 -0
  224. package/skills/wix-vibe-headless/references/bookings/app/hooks/useServices.js +58 -0
  225. package/skills/wix-vibe-headless/references/bookings/app/lib/serviceFacts.js +95 -0
  226. package/skills/wix-vibe-headless/references/bookings/app/pages/ServiceDetail.jsx +94 -0
  227. package/skills/wix-vibe-headless/references/bookings/app/pages/Services.jsx +89 -0
  228. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-checkout.js → app/rest/wix-bookings-checkout.js} +1 -1
  229. package/skills/wix-vibe-headless/references/bookings/{wix-bookings-services.js → app/rest/wix-bookings-services.js} +87 -11
  230. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +117 -0
  231. package/skills/wix-vibe-headless/references/bookings/seed/seed-bookings.js +333 -0
  232. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +168 -147
  233. package/skills/wix-vibe-headless/references/cms/app/collection.config.js +31 -0
  234. package/skills/wix-vibe-headless/references/cms/app/lib/wixImage.js +18 -0
  235. package/skills/wix-vibe-headless/references/cms/{wix-cms.js → app/rest/wix-cms.js} +47 -2
  236. package/skills/wix-vibe-headless/references/cms/seed/SEED.md +145 -0
  237. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +223 -131
  238. package/skills/wix-vibe-headless/references/events/app/components/CategoryFilter.jsx +23 -0
  239. package/skills/wix-vibe-headless/references/events/app/components/EventCard.jsx +43 -0
  240. package/skills/wix-vibe-headless/references/events/app/components/EventGrid.jsx +13 -0
  241. package/skills/wix-vibe-headless/references/events/app/components/EventRegistration.jsx +29 -0
  242. package/skills/wix-vibe-headless/references/events/app/components/RsvpForm.jsx +57 -0
  243. package/skills/wix-vibe-headless/references/events/app/components/TicketPicker.jsx +78 -0
  244. package/skills/wix-vibe-headless/references/events/app/hooks/useEventDetail.js +27 -0
  245. package/skills/wix-vibe-headless/references/events/app/hooks/useEventsList.js +54 -0
  246. package/skills/wix-vibe-headless/references/events/app/hooks/useRsvpForm.js +40 -0
  247. package/skills/wix-vibe-headless/references/events/app/hooks/useTicketing.js +81 -0
  248. package/skills/wix-vibe-headless/references/events/app/pages/EventDetail.jsx +48 -0
  249. package/skills/wix-vibe-headless/references/events/app/pages/Events.jsx +36 -0
  250. package/skills/wix-vibe-headless/references/events/{wix-events-browse.js → app/rest/wix-events-browse.js} +1 -1
  251. package/skills/wix-vibe-headless/references/events/seed/SEED.md +107 -0
  252. package/skills/wix-vibe-headless/references/events/seed/seed-events.js +251 -0
  253. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +272 -188
  254. package/skills/wix-vibe-headless/references/members/app/components/LoginForm.jsx +101 -0
  255. package/skills/wix-vibe-headless/references/members/app/components/MemberMenu.jsx +33 -0
  256. package/skills/wix-vibe-headless/references/members/app/components/RequireAuth.jsx +21 -0
  257. package/skills/wix-vibe-headless/references/members/app/components/SocialButtons.jsx +29 -0
  258. package/skills/wix-vibe-headless/references/members/app/context/MemberContext.jsx +54 -0
  259. package/skills/wix-vibe-headless/references/members/app/hooks/useLoginForm.js +77 -0
  260. package/skills/wix-vibe-headless/references/members/app/pages/Account.jsx +36 -0
  261. package/skills/wix-vibe-headless/references/members/app/pages/Callback.jsx +32 -0
  262. package/skills/wix-vibe-headless/references/members/app/pages/Login.jsx +35 -0
  263. package/skills/wix-vibe-headless/references/members/{wix-members-auth.js → app/rest/wix-members-auth.js} +6 -3
  264. package/skills/wix-vibe-headless/references/members/install/Register.jsx +22 -0
  265. package/skills/wix-vibe-headless/references/members/seed/SEED.md +22 -0
  266. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +229 -104
  267. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionCard.jsx +31 -0
  268. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionGrid.jsx +15 -0
  269. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectCard.jsx +39 -0
  270. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectGrid.jsx +15 -0
  271. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectMedia.jsx +29 -0
  272. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useCollectionProjects.js +35 -0
  273. package/skills/wix-vibe-headless/references/portfolio/app/hooks/usePortfolioGallery.js +27 -0
  274. package/skills/wix-vibe-headless/references/portfolio/app/hooks/useProjectDetail.js +25 -0
  275. package/skills/wix-vibe-headless/references/portfolio/app/pages/CollectionPage.jsx +39 -0
  276. package/skills/wix-vibe-headless/references/portfolio/app/pages/Portfolio.jsx +27 -0
  277. package/skills/wix-vibe-headless/references/portfolio/app/pages/ProjectDetail.jsx +60 -0
  278. package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +94 -0
  279. package/skills/wix-vibe-headless/references/portfolio/seed/seed-portfolio.js +236 -0
  280. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +236 -117
  281. package/skills/wix-vibe-headless/references/pricing-plans/app/components/OrderCard.jsx +35 -0
  282. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanCard.jsx +48 -0
  283. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanGrid.jsx +16 -0
  284. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanPrice.jsx +35 -0
  285. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/useMyPlans.js +25 -0
  286. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlanDetail.js +28 -0
  287. package/skills/wix-vibe-headless/references/pricing-plans/app/hooks/usePlans.js +30 -0
  288. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/MyPlans.jsx +30 -0
  289. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/PlanDetail.jsx +53 -0
  290. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/Plans.jsx +28 -0
  291. package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +86 -0
  292. package/skills/wix-vibe-headless/references/pricing-plans/seed/seed-pricing-plans.js +251 -0
  293. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +244 -124
  294. package/skills/wix-vibe-headless/references/restaurants/app/components/ItemDialog.jsx +81 -0
  295. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuItemCard.jsx +71 -0
  296. package/skills/wix-vibe-headless/references/restaurants/app/components/MenuList.jsx +43 -0
  297. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartButton.jsx +21 -0
  298. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +60 -0
  299. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +63 -0
  300. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useItemOrder.js +32 -0
  301. package/skills/wix-vibe-headless/references/restaurants/app/hooks/useReservation.js +73 -0
  302. package/skills/wix-vibe-headless/references/restaurants/app/pages/Menu.jsx +28 -0
  303. package/skills/wix-vibe-headless/references/restaurants/app/pages/Reservations.jsx +102 -0
  304. package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +180 -0
  305. package/skills/wix-vibe-headless/references/restaurants/seed/seed-restaurants.js +452 -0
  306. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +56 -0
  307. package/skills/wix-vibe-headless/references/shared/{wix-client.js → app/rest/wix-client.js} +6 -8
  308. package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +8 -0
  309. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +259 -157
  310. package/skills/wix-vibe-headless/references/storefront/app/components/CartButton.jsx +20 -0
  311. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +150 -0
  312. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +167 -0
  313. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +51 -0
  314. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +54 -0
  315. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +119 -0
  316. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +71 -0
  317. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +109 -0
  318. package/skills/wix-vibe-headless/references/storefront/app/hooks/useShop.js +98 -0
  319. package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +27 -0
  320. package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +139 -0
  321. package/skills/wix-vibe-headless/references/storefront/app/pages/Shop.jsx +75 -0
  322. package/skills/wix-vibe-headless/references/storefront/{wix-store-cart.js → app/rest/wix-store-cart.js} +1 -1
  323. package/skills/wix-vibe-headless/references/storefront/{wix-store-catalog.js → app/rest/wix-store-catalog.js} +20 -1
  324. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +111 -0
  325. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +338 -0
  326. /package/skills/wix-vibe-headless/references/blog/{wix-blog.js → app/rest/wix-blog.js} +0 -0
  327. /package/skills/wix-vibe-headless/references/events/{wix-events-registration.js → app/rest/wix-events-registration.js} +0 -0
  328. /package/skills/wix-vibe-headless/references/portfolio/{wix-portfolio.js → app/rest/wix-portfolio.js} +0 -0
  329. /package/skills/wix-vibe-headless/references/pricing-plans/{wix-pricing-plans.js → app/rest/wix-pricing-plans.js} +0 -0
  330. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-menu.js → app/rest/wix-restaurants-menu.js} +0 -0
  331. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-ordering.js → app/rest/wix-restaurants-ordering.js} +0 -0
  332. /package/skills/wix-vibe-headless/references/restaurants/{wix-restaurants-reservations.js → app/rest/wix-restaurants-reservations.js} +0 -0
@@ -1,174 +1,241 @@
1
1
  ---
2
2
  name: "Setup Forms"
3
- description: Initializes a Wix Forms backend — deletes the install's default sample form, then creates one lead-capture form schema per requested form (fields + human-readable `target` keys + each INPUT's `CONTACTS_*` system `identifier` + a `steps` layout, so the form and its submissions render in the dashboard, `namespace` wix.form_app.form) and verifies each persisted via the form summary. Specifies the *how* (calls + format); which forms, their fields, and counts come from the request.
3
+ description: Initializes a Wix Forms backend with Form Schemas v4 for any visitor-fillable form — contact, survey, application, waitlist or custom data capture — by cleaning the install's sample forms, creating one form schema per requested form, then verifying each renders via the form summary; revises an existing form with `PATCH` + its `revision`. Specifies the *how* (calls + format); which forms and what they collect come from the request.
4
4
  ---
5
5
  **RECIPE**: Business Recipe – Initial Setup for Wix Forms (Form Schemas v4)
6
6
 
7
- > **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`. Send `wix-site-id: <SITE_ID>` on every call.
8
-
9
- A concise checklist for preparing any new Wix site that uses the **Wix Forms** app to capture leads (contact / inquiry / signup / RSVP-style forms).
10
- **Notice** this recipe is for **initial backend setup ONLY**, not for coding the frontend.
11
-
12
- > **This recipe is the *how*, not the *what*.** How many forms, each form's fields, and their labels come from the request you're fulfilling. This recipe only specifies the calls and the request format; it does not decide which forms or fields to create.
13
-
14
- > **API surfaces:** Wix Forms is a **standalone CRM API** — a form **schema** (the field definitions) is created on the **Form Schemas v4** service at `https://www.wixapis.com/form-schema-service/v4/forms`. In the docs portal this lives under **CRM ▸ Forms ▸ Form Schemas**, *not* under Business Solutions. This is **NOT** the events/bookings per-event registration form (a different thing). The Forms app's `appDefId` is `225dd912-7dea-4738-8688-4b8c6955ffc2`; an `UNSUPPORTED_FORM_NAMESPACE` error means the app isn't installed. Call the **public** host shown above (no `/_api/` prefix). There is no bulk endpoint — one POST per form.
7
+ > **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for
8
+ > `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need
9
+ > `Content-Type: application/json`. Send `wix-site-id: <SITE_ID>` on every call.
10
+
11
+ A concise checklist for preparing any new Wix site that uses the **Wix Forms** app. Wix Forms backs
12
+ **any form a visitor fills in** — a contact or enquiry form, a signup or waitlist, an application, a
13
+ feedback form or survey, a quote request, an intake or registration questionnaire, or any custom data
14
+ capture. Lead capture is the most common case, not the only one: the schema is a generic
15
+ field-definition store, and whether a submission becomes a CRM contact is just the optional per-field
16
+ `contactMapping` (STEP 2). This recipe is for **initial backend setup ONLY**, not for coding the
17
+ frontend.
18
+
19
+ > **Two boundaries.** Forms does **not** own **RSVP to an event or occasion** (that is the `events`
20
+ > vertical, which ships its own registration form) or the **per-service booking form** (`bookings`).
21
+ > Route there when an event or a bookable service is involved; use `forms` for everything else.
22
+
23
+ > **This recipe is the *how*, not the *what*.** How many forms, and what each one collects, come
24
+ > from the request you're fulfilling. This recipe only specifies the calls and the request format;
25
+ > it does not decide which forms to create.
26
+
27
+ > **API surfaces:** Wix Forms is a **standalone CRM API**. A form **schema** (the field definitions)
28
+ > lives on **Form Schemas v4** at `https://www.wixapis.com/form-schema-service/v4/forms` — docs
29
+ > portal **CRM ▸ Forms ▸ Form Schemas**, *not* Business Solutions. This is **NOT** the
30
+ > events/bookings per-event registration form (a different thing). The Forms app's `appDefId` is
31
+ > `225dd912-7dea-4738-8688-4b8c6955ffc2`; an `UNSUPPORTED_FORM_NAMESPACE` error means the app isn't
32
+ > installed. Call the **public** host shown above (no `/_api/` prefix).
33
+ >
34
+ > **API reference:**
35
+ > - Create Form: <https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/create-form> — its
36
+ > examples are complete requests for common form types (contact, survey, order, booking, …). Copy
37
+ > the one closest to what you need.
38
+ > - About Form Fields:
39
+ > <https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/about-form-fields>
40
+ > - Form object: <https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/form-object>
15
41
 
16
42
  ---
17
43
 
18
44
  ## Article: Steps for Setting Up Wix Forms
19
- **YOU MUST** complete the steps in order, without requiring additional user input: clean the default form (STEP 1) **before** creating yours (STEP 2), then verify (STEP 3).
20
45
 
21
- **⚠️ CRITICAL ORDER REQUIREMENT: clean the install's default sample form FIRST (STEP 1), before creating any form.** Listing-then-deleting before you create guarantees every id you delete is a pre-existing form, never one you just created — and it prevents a name collision (see STEP 1). **But only delete forms that are obviously the install's own default sample form:** the site may already hold the owner's **real forms** (a connect/iterate run, or an owner-populated site). If what's there isn't obviously install sample data, or you're unsure, **do not delete it — ask the user first** (`SEED.md`: seeding is additive; deleting real content needs the owner's approval).
46
+ **⚠️ CRITICAL ORDER REQUIREMENT: clean the install's default sample form FIRST (STEP 1), before
47
+ creating any form.** Listing-then-deleting before you create guarantees every id you delete is a
48
+ pre-existing form, never one you just created — and it keeps you clear of the site's low form cap.
49
+ **But only delete forms that are obviously the install's own default sample form:** the site may
50
+ already hold the owner's **real forms** (a connect/iterate run, or an owner-populated site). If
51
+ what's there isn't obviously install sample data, or you're unsure, **do not delete it — ask the
52
+ user first** (`SEED.md`: seeding is additive; deleting real content needs the owner's approval).
22
53
 
23
54
  ### STEP 1: Clean — remove any pre-existing (install-default) forms
24
55
 
25
- A freshly installed Wix Forms app **may ship a default "Get in touch" form** (a contact form with `first_name` / `email` / `message` fields). Its presence is **not deterministic** — some fresh installs ship it and others don't, so it appears provisioning/timing-dependent. Rather than assume, **list what's actually there and delete whatever comes back** — this is a safe no-op when the list is empty.
26
-
27
- 1. **List the existing forms** — `GET https://www.wixapis.com/form-schema-service/v4/forms?namespace=wix.form_app.form`. `namespace` is a **required** query param. Collect every `form.id` from the response (`forms[].id`). On a fresh install this is **either empty or the single default form** — both are fine.
28
- 2. **Delete each** — `DELETE https://www.wixapis.com/form-schema-service/v4/forms/{formId}` (one call per id; returns `200 {}`). Because the list ran **before** any create, every id returned is a pre-existing form — safe to delete. If the list was empty, issue no DELETE (a correct no-op).
29
-
30
- **⚠️ Why clean even though it's often a no-op: when the default "Get in touch" form IS present, form names collide and the service silently auto-suffixes.** Form names must be unique; if the request's form is also called "Get in touch" and a default exists that you didn't clean, the create succeeds but your form is renamed **"Get in touch 1"**, quietly diverging from the name the frontend expects. Cleaning first removes that hazard whenever the default happens to be present. (With the default present, a second "Get in touch" create comes back renamed "Get in touch 1".)
31
-
32
- ### STEP 2: Create each form schema (fields + targets)
33
-
34
- Create the forms the request names — **one POST per form** to `POST https://www.wixapis.com/form-schema-service/v4/forms`. **How many forms, and each form's fields/labels, come from the request you're fulfilling — this step only gives the call and the required format.** (There is no bulk-create; issue one call per form. Forms are independent — no shared revision — so concurrent creates are safe, but typically it's just one form.)
35
-
36
- **⚠️ CRITICAL: every field needs a client-generated LOWERCASE GUID `id` — GENERATE IT IN THE SHELL, never type one from memory.** Each `formFields[].id` must be a distinct valid GUID (two the same → `400 DUPLICATED_FIELD_IDS`). Generate one per INPUT field **plus** one for the submit button and one for the layout step. **Generate them LOWERCASE** — each id is referenced twice (once as `formFields[].id`, once as the layout's `steps[].layout.large.items[].fieldId`) and they must match, but the server **lowercases** stored field ids; an uppercase `uuidgen` id in the layout would no longer match the stored field id and the dashboard layout would break. So lowercase at generation:
37
-
38
- ```bash
39
- # lowercase GUIDs — uuidgen (lowercased), with python3 / node fallbacks (both already lowercase)
40
- lc() { uuidgen 2>/dev/null | tr 'A-Z' 'a-z' || python3 -c 'import uuid;print(uuid.uuid4())' || node -e 'console.log(crypto.randomUUID())'; }
41
- F1=$(lc); F2=$(lc); F3=$(lc) # one per INPUT field
42
- SUBMIT=$(lc) # the submit-button (DISPLAY) field
43
- STEP=$(lc) # the layout step (page)
44
- ```
45
-
46
- **Request body shape** (a 3-field contact form — repeat/adjust the INPUT `formFields[]` and the matching layout `items[]` per the request):
47
-
48
- ```json
49
- {
50
- "form": {
51
- "name": "Get in touch",
52
- "namespace": "wix.form_app.form",
53
- "formFields": [
54
- { "id": "$SUBMIT", "hidden": false, "identifier": "SUBMIT_BUTTON", "fieldType": "DISPLAY",
55
- "displayOptions": { "displayFieldType": "PAGE_NAVIGATION", "pageNavigationOptions": { "nextPageText": "Next", "previousPageText": "Back", "submitText": "Submit" } } },
56
- { "id": "$F1", "hidden": false, "identifier": "CONTACTS_FIRST_NAME", "fieldType": "INPUT", "inputOptions": {
57
- "target": "first_name", "pii": true, "required": true, "inputType": "STRING", "readOnly": false,
58
- "stringOptions": { "validation": { "format": "UNKNOWN_FORMAT", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "First name", "showLabel": true } } } },
59
- { "id": "$F2", "hidden": false, "identifier": "CONTACTS_EMAIL", "fieldType": "INPUT", "inputOptions": {
60
- "target": "email", "pii": true, "required": true, "inputType": "STRING", "readOnly": false,
61
- "stringOptions": { "validation": { "format": "EMAIL", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "Email", "showLabel": true } } } },
62
- { "id": "$F3", "hidden": false, "identifier": "CONTACTS_PHONE", "fieldType": "INPUT", "inputOptions": {
63
- "target": "phone", "pii": true, "required": false, "inputType": "STRING", "readOnly": false,
64
- "stringOptions": { "validation": { "format": "PHONE", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "Phone", "showLabel": true } } } }
65
- ],
66
- "steps": [
67
- { "id": "$STEP", "name": "Page 1", "layout": { "large": { "items": [
68
- { "fieldId": "$F1", "row": 0, "column": 0, "width": 12, "height": 1 },
69
- { "fieldId": "$F2", "row": 1, "column": 0, "width": 12, "height": 1 },
70
- { "fieldId": "$F3", "row": 2, "column": 0, "width": 12, "height": 1 },
71
- { "fieldId": "$SUBMIT", "row": 3, "column": 0, "width": 12, "height": 1 }
72
- ], "sections": [] } } }
73
- ],
74
- "enabled": true
75
- }
76
- }
77
- ```
78
-
79
- **⚠️ CRITICAL FORMAT REQUIREMENTS:**
80
- - **`namespace` MUST be `"wix.form_app.form"`** (the Wix Forms namespace) — any other value fails with `400 UNSUPPORTED_FORM_NAMESPACE`. It is immutable after create.
81
- - **Every INPUT field MUST carry a non-empty `target`** — the human-readable key the frontend binds to (input `name` = `target`). An empty/missing target fails with `400 UNSUPPORTED_FIELD_TARGETS_NAME` (`MISSING_FIELD_TARGETS`). Targets are **immutable** (set once).
82
- - **Targets MUST be unique within a form** — two fields sharing a target → `400 DUPLICATED_FIELD_TARGETS`. Use lowercase snake_case keys the frontend can reuse verbatim (`first_name`, `email`, `phone`, `message`).
83
- - **Field envelope:** each field is `{ id, hidden: false, identifier: "<CONTACTS_*>", fieldType: "INPUT", inputOptions: { target, readOnly: false, inputType: "STRING", stringOptions: { validation: { format, enum: [] }, componentType: "TEXT_INPUT", textInputOptions: { label, showLabel } } } }`. The `identifier` is MANDATORY for dashboard rendering — see the CRITICAL identifier block below. Use `inputType: "STRING"` + `componentType: "TEXT_INPUT"` for text fields. Set `required: true` on the fields the form must collect (defaults to `false`); mark `pii: true` on personal fields (name/email/phone).
84
-
85
- **Dropdown (enum) fields — concrete envelope.** A dropdown is still `inputType: "STRING"`; only the `componentType` and its options block change. Set `componentType: "DROPDOWN"` and put the choices under `stringOptions.dropdownOptions.options` as `{ id, label, value }` — the `value` is what a submission stores (keep it a stable machine key), and **every option needs its own lowercase GUID `id`** (see the CRITICAL below). Keep the `validation` block as with any field (a plain dropdown reads back `format: UNDEFINED`, so write `UNKNOWN_FORMAT`):
56
+ A freshly installed Wix Forms app **may ship a default "Get in touch" form** (a contact form with
57
+ `first_name` / `email` / `message` fields). Its presence is **not deterministic** — some fresh
58
+ installs ship it and others don't, so it appears provisioning/timing-dependent. Rather than assume,
59
+ **list what's actually there and delete whatever comes back** — this is a safe no-op when the list
60
+ is empty.
61
+
62
+ 1. **List the existing forms** —
63
+ `GET https://www.wixapis.com/form-schema-service/v4/forms?namespace=wix.form_app.form&fieldsets=METADATA`,
64
+ then again with `&enabled=false`. Collect every `form.id` from both responses (`forms[].id`).
65
+ 2. **Delete each** — `DELETE https://www.wixapis.com/form-schema-service/v4/forms/{formId}` (one
66
+ call per id; returns `200 {}`). Because the list ran **before** any create, every id returned is
67
+ a pre-existing form — safe to delete. If the list was empty, issue no DELETE (a correct no-op).
68
+
69
+ **⚠️ Why clean even though it's often a no-op — the form cap.** Leftovers plus your new forms can
70
+ exhaust the site's form allowance (read it from
71
+ [List Forms Providers Configs](https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/list-forms-providers-configs)),
72
+ which is also why you must **never create throwaway forms to probe the shape.**
73
+
74
+ ### STEP 2: Create each form schema
75
+
76
+ **One POST per form** to `https://www.wixapis.com/form-schema-service/v4/forms`. How many forms, and
77
+ each form's fields and labels, come from the request you're fulfilling; this step gives the call and
78
+ the required format. Forms are independent (no shared revision), so concurrent creates are safe.
79
+
80
+ **⚠️ Generate every `id` in the shell as a lowercase UUID v4 — never type one from memory**
81
+ (`uuidgen | tr 'A-Z' 'a-z'`). Supply them at create rather than omitting them: `steps` must
82
+ reference each field by `fieldId` in the same request.
83
+
84
+ **Assemble the request** from the closest Create Form example, building each `formFields[]` entry —
85
+ including the `SUBMIT_BUTTON` — per
86
+ **[About Form Fields](https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/about-form-fields)**,
87
+ which owns every field-level rule, including placing every field in the layout — **with one
88
+ documented gap: where `required` goes (next paragraph). The guide never says, so don't infer it from
89
+ its "Validation" section.**
90
+ **Geometry (`row`/`column`/`width`) does not matter on headless** — the frontend renders its own
91
+ layout from `formFields[]` and never reads `steps[].layout` (`how-to-code-forms.md`) — so the layout
92
+ is a *correctness* requirement, not a design one: assert presence and coverage only. Use a single
93
+ step unless the request needs multiple pages.
94
+
95
+ **⚠️ `required` goes at `inputOptions.required` — NOT inside the field's `validation` block.** It sits
96
+ beside `target`/`inputType`:
86
97
 
87
98
  ```jsonc
88
- // generate an option GUID per choice in the shell, same lc() helper as the field ids:
89
- // O1=$(lc); O2=$(lc); O3=$(lc)
90
- { "id": "$F4", "hidden": false, "identifier": "budget", "fieldType": "INPUT", "inputOptions": {
91
- "target": "budget", "required": false, "inputType": "STRING", "readOnly": false,
92
- "stringOptions": {
93
- "validation": { "format": "UNKNOWN_FORMAT", "enum": [] },
94
- "componentType": "DROPDOWN",
95
- "dropdownOptions": {
96
- "label": "Budget", "showLabel": true, "placeholder": "Select a range",
97
- "options": [
98
- { "id": "$O1", "label": "Under $1k", "value": "under_1k" },
99
- { "id": "$O2", "label": "$1k–$5k", "value": "1k_5k" },
100
- { "id": "$O3", "label": "$5k+", "value": "5k_plus" }
101
- ]
102
- } } } }
99
+ "inputOptions": { "target": "full_name", "required": true, "inputType": "STRING",
100
+ "stringOptions": { "validation": {}, "componentType": "TEXT_INPUT",
101
+ "textInputOptions": { "label": "Full Name", "showLabel": true } } }
103
102
  ```
104
103
 
105
- Add a matching `steps[].layout.large.items[]` entry for its `fieldId` like any other field.
104
+ A `required` key inside `stringOptions.validation` — or any `<inputType>Options.validation`, since no
105
+ input type's validation object defines it — is **accepted at create and then silently discarded**:
106
+ `200`, the form lists, the summary returns every field, and every field still reads back
107
+ `required: false`. The form ships publicly with nothing mandatory and **no error anywhere in the
108
+ response**, so STEP 3's read-back diff is the only signal. `validation` carries value constraints
109
+ only (`format`, `enum`, `minimum`, `minLength`, `items`). The lone exception is the multi-line address
110
+ field, whose per-subfield flags genuinely live at
111
+ `addressOptions.validation.fields.<sub>.required`.
112
+
113
+ **⚠️ Any example value you author into the schema follows the site's country, not your default.** A
114
+ `placeholder` (or label/hint) carrying a phone number, postcode, currency or date is **visible to
115
+ every visitor**, so a `+44`- or US-shaped example on a site in another market is a locale bug. Resolve
116
+ the site's country and, for an illustrative phone number, take it from that country's
117
+ regulator-reserved fictional range — the resolution order and the vetted per-country map live in
118
+ `how-to-code-forms.md` ("Validation"). Leaving a constrained field's `placeholder` empty is fine: the
119
+ frontend synthesizes the example from the field's `format` at render time.
120
+
121
+ **⚠️ A `200` proves nothing: always run STEP 3.** Most mistakes here are accepted at create and only
122
+ surface in the dashboard or on the first real submission.
123
+
124
+ #### Plan gates — surface the choice, never engineer around it
125
+
126
+ Three plan-tier limits return a real `400` on create. **Do not work around any of them; tell the user
127
+ to reduce or upgrade.**
128
+
129
+ - **`FIELDS_COUNT_RESTRICTIONS_ERROR`** — the form exceeds the plan's per-form field cap. **Do NOT
130
+ split the form into multiple schemas** to dodge it. Reduce the field count, or upgrade.
131
+ - **`FILE_UPLOAD_RESTRICTIONS_ERROR`** — a file upload, signature, or payment field on a plan below
132
+ Core. **Do NOT suggest inlining files as base64** — it stores no real file, gives the owner nothing
133
+ usable, and blows past submission size limits. Drop the field, or upgrade.
134
+ - **`FORMS_COUNT_RESTRICTIONS_ERROR`** — the site hit its plan's total-form cap. Upgrade, or free a
135
+ slot (STEP 1's list-then-delete — but only delete forms that are clearly install sample data; ask
136
+ before deleting anything that could be the owner's real form).
137
+
138
+ **⚠️ A plan gate is a HARD BLOCK on the run — not a soft "record it and continue" precondition like
139
+ paid tickets or online reservations.** Those leave a working schema and fail only at runtime; here the
140
+ schema doesn't exist, so its `formId`/field `target`s don't either. **Put the choice to the user
141
+ (reduce, or upgrade — with the MSID + dashboard link), wait for their confirmation, then create and
142
+ verify the schema (STEP 2 → STEP 3) BEFORE any frontend work.** Do **not** build the frontend "in the
143
+ meantime": its inputs bind to those targets, so every binding would be a guess to rewrite.
144
+
145
+ Read `form.id` from the response as the `formId` to keep.
146
+
147
+ If a create fails transiently on a fresh site (`5xx`, or an identity/propagation error right after
148
+ install — the install returns `appInstance.status: "UNKNOWN"` until it propagates), retry the same
149
+ call **once**; do not loop.
106
150
 
107
- **⚠️ CRITICAL: every dropdown `options[]` entry MUST carry its own lowercase GUID `id` — a create without it 400s `options[N].id is not a valid GUID / must not be empty`.** The API spec marks the option `id` optional (it's for Multilingual translation), but the create validator **rejects an option with no `id`**. Generate one GUID per option in the shell (the same `lc()` helper used for field ids), exactly as you do for field/step ids — never type one from memory.
108
-
109
- **⚠️ A custom dropdown's options round-trip in `fields[].view.options`, NOT `formFields[]` — and the frontend reads them from there.** Verified live (2026-07-12): a dropdown whose `identifier` is a plain custom key (like `"budget"` — dropdowns rarely map to a `CONTACTS_*` system field) is **dropped from `formFields[]` by the identifier→dashboard rule below**, so it does **not** show in the Wix dashboard summary — *but its data is fully captured and its options survive under `form.fields[].view.options` as `[{ id, label, value }]`* (alongside `view.label` / `view.placeholder`). That's exactly where the schema-driven frontend reads dropdown choices from (`how-to-code-forms.md` projects `fields[]`, not `formFields[]`), so **a custom dropdown renders and submits correctly on the headless site even though the dashboard doesn't list it.** So: seed the dropdown as the request needs; verify persistence on the GET round-trip (STEP 3) by asserting the field appears in `fields[]` with a non-empty `view.options`; and — as with any custom (non-`CONTACTS_*`) field — do **not** claim the dashboard fully renders it (platform limitation, same as the CRITICAL identifier block). If a dropdown *does* map cleanly to a contact field, give it the matching `CONTACTS_*` identifier and it will also show in the dashboard.
110
-
111
- Other richer types (number, checkbox group, date) follow the same envelope with a different `inputType`/`stringOptions`/`arrayOptions` — but plain STRING text + dropdowns cover the lead-capture case.
112
-
113
- **⚠️ CRITICAL: every field MUST carry a `stringOptions.validation` block, or the field is NOT submittable — a visitor submission of it fails with `400 "must NOT have additional properties"`.** The submission validator builds its allowed-keys schema **only from fields that have a `validation` block**. A field created without one exists on the form and even renders, but any submission that includes its `target` is rejected as an unknown property (and `required` is silently dropped too) — the form looks fine but silently rejects real submissions. So give **every** field a `validation` block:
114
- - Plain text / name / message → `"validation": { "format": "UNKNOWN_FORMAT", "enum": [] }`.
115
- - Email → `"validation": { "format": "EMAIL", "enum": [] }`; phone → `"PHONE"`; URL → `"URL"`. (Full `format` enum: `UNKNOWN_FORMAT`, `DATE`, `TIME`, `DATE_TIME`, `EMAIL`, `URL`, `UUID`, `PHONE`, `URI`, `HOSTNAME`, `COLOR_HEX`, `CURRENCY`, `LANGUAGE`, `DATE_OPTIONAL_TIME`.)
116
- - **Use `UNKNOWN_FORMAT`, NOT `UNDEFINED`, on write.** The create/GET response echoes an unconstrained format back as `"UNDEFINED"` (and the docs' create example shows `"format": "UNDEFINED"`), but sending `"UNDEFINED"` on **create** fails with `400 "format enum must be in […]"` — `UNDEFINED` is the read-back value, not a writable one. Write `UNKNOWN_FORMAT`; it stores and reads back as `UNDEFINED`.
117
- - **Length & pattern constraints go in the SAME `validation` block — seed them when the request asks for field rules.** `stringOptions.validation` also accepts `minLength` (int), `maxLength` (int), and `pattern` (a regex string) alongside `format`/`enum`. A request like "first name 2–40 chars", "message at least 20 chars", or "note capped at 500" maps directly to these. Verified live (2026-07-12): `"validation": { "format": "UNKNOWN_FORMAT", "enum": [], "minLength": 2, "maxLength": 12, "pattern": "^[A-Za-z ]+$" }` persists and reads back under `validation.string.{minLength,maxLength,pattern}`. **These constraints are enforced server-side by `createSubmission`** — a violating submit is rejected with a field violation (`errorPath` = the field's `target`, e.g. message `"must have between 2 and 12 characters"`), which the frontend surfaces inline (see `how-to-code-forms.md`). The frontend also reads them from the schema to pre-validate client-side, so seeding them is what makes owner-set field rules flow through with no code change. `pattern` is a standard JS-style regex; omit it unless the request calls for a specific character rule.
118
- - `required` (at `inputOptions` level) lands in `validation.required` — but **only takes effect if the field has a `validation` block** (no block ⇒ `required` is dropped along with the field's submittability). This is another reason every field needs the block.
119
- - If a create fails transiently on a fresh site (`5xx`, or an identity/propagation error right after install — the install returns `appInstance.status: "UNKNOWN"` until it propagates), retry the same call **once**; do not loop. (Creates typically succeed immediately, but keep the retry-once safety net.)
120
-
121
- **⚠️ CRITICAL: include a `steps` layout + a `SUBMIT_BUTTON` DISPLAY field, or the Wix dashboard shows every submission EMPTY.** The form is technically submittable with INPUT fields alone — the submission *data* stores fine either way, and the headless frontend renders its own UI — BUT the Wix **Forms dashboard** (`Customers & Leads ▸ Forms & Submissions`) renders each submission's values against the form's **layout** (`formFields` + `steps`). A form seeded **without** a layout stores complete submissions that the dashboard displays as **blank** ("—" summary, empty details panel), so the site owner can't read their leads in the UI — it looks broken even though the data is intact. So always seed the layout:
122
- - Add a **`SUBMIT_BUTTON`** DISPLAY field (`fieldType: "DISPLAY"`, `displayOptions.displayFieldType: "PAGE_NAVIGATION"`) to `formFields`.
123
- - Add a **single `steps` entry** whose `layout.large.items[]` places **every** field (each INPUT + the submit button) by `fieldId`, one per row.
124
- - **Each `items[].fieldId` MUST equal the corresponding `formFields[].id`** — this is why the ids are generated **lowercase** up front (the server lowercases stored field ids; an uppercased layout `fieldId` would no longer match and the dashboard layout silently breaks).
125
- - A **single create call with the layout persists it** — no follow-up PATCH needed. (Omitting the layout is the cause of blank dashboard submissions; adding it via PATCH to an already-created form also fixes them retroactively.)
126
-
127
- **⚠️⚠️ CRITICAL: every INPUT field MUST carry a system `identifier`, or it is DROPPED FROM `formFields[]` and NEVER shows in the dashboard.** This is the #1 dashboard-blank cause and it is SEPARATE from (and stronger than) the layout requirement above — a form can have a perfect `steps` layout and still be blank. On create, the server keeps an INPUT field's component in `formFields[]` **only if its `identifier` is a recognized system value.** Without a recognized identifier (no identifier, a custom string, an extended-field key like `custom.x`, or a GUID — all fail) the field is normalized into the legacy `fields[]` array **only**, `formFields[]` comes back holding just the `SUBMIT_BUTTON`, and `GET .../{formId}/summary` returns **zero fields** → the Wix dashboard renders the form and every submission **blank**. (The public headless site still submits fine — the submission service matches by `target` — so this defect is invisible from the frontend; you must verify it server-side in STEP 3.)
128
- - **Map each field to its contact identifier.** Set `identifier` on every INPUT field to the `CONTACTS_*` value for what it collects. Verified working: `CONTACTS_FIRST_NAME`, `CONTACTS_LAST_NAME`, `CONTACTS_EMAIL`, `CONTACTS_PHONE`. (The contacts schema has more system fields — address, company, birthdate, etc.; use the matching `CONTACTS_*` identifier. `SUBMIT_BUTTON` is the identifier for the DISPLAY submit field.)
129
- - **⚠️ Custom (non-contact) fields do NOT render in the dashboard via this API.** A field with no matching `CONTACTS_*` identifier (e.g. "medical conditions", "fitness goal", a waiver checkbox) cannot be made to appear in the Wix Forms dashboard through `form-schema-service/v4/forms` — registering a Contacts extended field and referencing its `custom.<key>` does **not** work. Such fields still store submission data correctly (frontend + `fields[]` + submission records) but the owner won't see them in the dashboard UI. **So: for lead-capture forms the request should lean on contact-mappable fields (name / email / phone / address / company / birthdate). If the request genuinely needs custom fields, seed them anyway (data is captured) but do NOT report the dashboard as fully rendering — only the contact-mapped fields will show.** This is a platform limitation, not a seed bug; surface it rather than silently shipping a half-blank dashboard.
130
- - Also set `hidden: false` on each field and `readOnly: false` in `inputOptions` (matches the shape shown in the docs).
131
-
132
- **⚠️ Do NOT rely on `postSubmissionTriggers.upsertContact` (contact mapping) through this endpoint — it is SILENTLY DROPPED.** The docs' create example includes a `postSubmissionTriggers.upsertContact.fieldsMapping` block to auto-create a CRM contact from a submission. Live, the create returns `200` **but the trigger is not persisted** (absent from a follow-up GET — the same silent-drop pattern as CMS multi-refs at insert). Don't depend on it in the seed. You don't need it: **form submissions are recorded against the schema regardless**, so leads are captured by the seeded form's `formId` on their own. The seed's job ends at the schema + targets.
151
+ ### STEP 3: Verify each form persisted (mandatory)
133
152
 
134
- **⚠️ Reading the response — read the field `target`s from `form.fields[]`; the layout persists under `form.formFields[]` + `form.steps[]`.** A successful create returns `200` with:
153
+ A `200` on create is not proof the form is queryable or that the dashboard will render it.
154
+
155
+ 1. **List once** —
156
+ `GET https://www.wixapis.com/form-schema-service/v4/forms?namespace=wix.form_app.form&formIds=<id1>&formIds=<id2>`
157
+ — **`formIds` narrows the list to exactly the forms you just created**, so you assert against them
158
+ directly instead of filtering a whole-namespace listing. For each form, confirm its `id` appears,
159
+ its **`formFields[]`** covers every field you sent, and its **`steps` is non-empty and places
160
+ every field** (per About Form Fields). **Also diff every field's `inputOptions.required` against
161
+ what you sent** — a misplaced `required` is dropped silently (STEP 2), and this read-back is the
162
+ only signal. If a flag came back `false`, fix it with STEP 4's `PATCH` (moving the flag to
163
+ `inputOptions.required`) rather than deleting and re-creating: the `formId` survives and it costs
164
+ no extra slot against the form cap.
165
+ 2. **⚠️ Then verify the dashboard will actually render —
166
+ `GET https://www.wixapis.com/form-schema-service/v4/forms/{formId}/summary` and assert
167
+ `formSummary.fields` is NON-EMPTY**, with a count equal to **every input field you sent** (i.e.
168
+ `formFields[]` minus the `SUBMIT_BUTTON`). A 6-input form returns all 6 — **including non-contact
169
+ `DROPDOWN` and `TEXT_AREA` fields** — so do *not* expect only the contact-mapped ones. This is
170
+ the reliable dashboard-truth check: the summary returns exactly the fields the Wix dashboard
171
+ shows. A `summary.fields: []`, or a count short of your inputs, means the form renders blank (or
172
+ partly blank) for the owner even though the public site submits fine — **do not report success;
173
+ fix the `identifier`s and re-create.**
174
+
175
+ 3. **⚠️ If the form has a multi-choice ARRAY field (`CHECKBOX_GROUP` / `TAGS`), the two checks above
176
+ are NOT enough — send one real `createSubmission`.** A malformed `arrayOptions.validation.items`
177
+ (missing `itemType`, or an empty/omitted `items`) still lists fine and still counts in the
178
+ summary, so steps 1–2 pass while **every** submission to the form `400`s form-wide (see "Choice
179
+ fields"). The only proof is a live submission:
180
+ `POST https://www.wixapis.com/form-submission-service/v4/submissions` with the standard call
181
+ shape (`<AUTH>`, `Content-Type`, `wix-site-id`) and a minimal valid body — `formId` plus a
182
+ `submissions` map keyed by each field's `target`, the ARRAY field as an **array** of enum values:
183
+
184
+ ```jsonc
185
+ { "submission": { "formId": "<formId>",
186
+ "submissions": { "email": "test@example.com", "multi_choice": ["Option 1"] } } }
187
+ ```
188
+
189
+ Assert it returns `200`, not `400 SUBMISSION_VALIDATION`. A `400` here means the ARRAY `items`
190
+ shape is wrong — fix it (both `itemType` and `stringOptions.enum`) and re-create. Delete the test
191
+ submission afterward
192
+ (`DELETE https://www.wixapis.com/form-submission-service/v4/submissions/{submissionId}`, the `_id`
193
+ from the response) so the owner's dashboard stays clean.
194
+
195
+ If a form is missing, its layout didn't persist, or its summary is unexpectedly empty, re-create it
196
+ once and re-verify; if it still fails, surface the response verbatim rather than reporting success.
197
+
198
+ ### STEP 4 (when revising): update an existing form
199
+
200
+ To change a form the request has since revised — add a field, relabel one, tighten a rule — follow
201
+ [Update Form](https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/update-form):
135
202
 
136
- ```json
137
- { "form": {
138
- "id": "<formId>",
139
- "fields": [
140
- { "id": "<field-id>", "target": "first_name", "view": { "label": "First name" }, "pii": true },
141
- { "id": "<field-id>", "target": "email", "validation": { "string": { "format": "EMAIL" }, "required": true } }
142
- ],
143
- "formFields": [ /* the field components incl. the submit button */ ],
144
- "steps": [ /* the layout you sent */ ],
145
- "namespace": "wix.form_app.form", "name": "Get in touch", "enabled": true
146
- } }
203
+ ```
204
+ PATCH https://www.wixapis.com/form-schema-service/v4/forms/{formId}
147
205
  ```
148
206
 
149
- Read the **`form.id`** (→ the `formId` to keep and hand to the frontend) and each **`form.fields[].target`** (→ the input `name`s the frontend renders). **All** field definitions are normalized into **`fields[]`** (read `target`s here) — but **`formFields[]` only echoes back the components the server materialized: the `SUBMIT_BUTTON` plus each INPUT that carried a recognized `CONTACTS_*` identifier** (see the CRITICAL identifier block above). `steps` echoes the layout you sent. So `fields[]` having all N fields does NOT mean the dashboard will render them — `formFields[]` / summary is the dashboard-truth source. The field `id`s are echoed **lowercased** — which is exactly why you generated them lowercase, so the `steps[].…fieldId`s still match. Downstream, the frontend binds by **`target`**, never by field id.
150
-
151
- ### STEP 3: Verify each form persisted (mandatory)
152
-
153
- A `200` on create is not proof the form is queryable. After creating, **list once** and confirm every seeded form is present with its targets:
207
+ **Prefer updating over delete-and-recreate.** An update keeps the `formId` the handoff already
208
+ carries and consumes no additional slot against the site's form cap. **Re-run STEP 3 after any update**
209
+ — it can regress the layout or the dashboard summary exactly as a create can.
154
210
 
155
- `GET https://www.wixapis.com/form-schema-service/v4/forms?namespace=wix.form_app.form` — for each form you created, confirm its `id` appears, its `fields[].target` set matches what you sent, and its **`steps`** is non-empty (a `steps: []` means the layout didn't persist).
211
+ ---
156
212
 
157
- **⚠️ Then verify the dashboard will actually render — call `GET https://www.wixapis.com/form-schema-service/v4/forms/{formId}/summary` and assert `formSummary.fields` is NON-EMPTY and its count equals the number of contact-mapped INPUT fields you seeded.** This is the reliable dashboard-truth check: the summary returns exactly the fields the Wix dashboard shows (i.e. the `formFields[]` components, minus the submit button). A `summary.fields: []` (or a count short of your contact-mapped inputs) means the identifier mapping failed and the dashboard is blank for those fields — **do not report success; fix the `identifier`s (STEP 2 CRITICAL block) and re-create.** Expect the summary count to equal your contact-mappable fields only; if the form has custom (non-`CONTACTS_*`) fields, they will be legitimately absent from the summary (platform limitation) — call that out in the handoff rather than treating it as a pass or a hard failure.
213
+ ## Keep — what crosses into the handoff
158
214
 
159
- If a form is missing, its layout didn't persist, or its summary is unexpectedly empty, re-create it once and re-verify; if it still fails, surface the response verbatim rather than reporting success.
215
+ **Per form: the `formId` + each form's field `target` keys.**
160
216
 
161
- **Keep** per form: the **`formId`** and the ordered list of field **`target`** keys (with each field's label and `required`) — that map is the producer for the coding handoff (the frontend sets each input's `name` = `target` and submits against the `formId`).
217
+ The `target`s are *structural* — the frontend binds each input's `name` to a field's `target` to
218
+ submit (the same carve-out shape as cms's `collectionId` + field keys). Everything else — the field
219
+ set, order, labels, `required` flags, validation formats and dropdown options — is **read live from
220
+ the schema at render time** (visitor token, no `auth.elevate` — `how-to-code-forms.md`), so a field
221
+ the owner adds, removes or relabels reflects on the site with no code change. See
222
+ `SDK_HANDOFF.md` §4.
162
223
 
163
224
  ---
164
225
 
165
226
  ## Conclusion
227
+
166
228
  Following these steps **in order** sets up a Wix Forms backend:
167
- - Starts from a **clean form list** — any pre-existing form (the install's occasional default "Get in touch") is listed-then-deleted first (a safe no-op when none exists), avoiding the silent name-collision auto-suffix when a default is present.
168
- - Contains exactly the forms the request calls for, each created in the **`wix.form_app.form`** namespace with unique, non-empty, immutable **`target`** keys per field.
169
- - **Every field carries a `stringOptions.validation` block** (`UNKNOWN_FORMAT` for plain text, `EMAIL`/`PHONE`/… otherwise) — without it the field is created but **not submittable** (visitor submissions 400 as "additional properties"). This is what makes the seeded form actually accept the frontend's submissions.
170
- - Each form is created **with a `steps` layout + a `SUBMIT_BUTTON`**, AND **every INPUT field carries its `CONTACTS_*` system `identifier`** — both are required for the site owner's **Wix dashboard to render** the form and its submissions. A field with no recognized identifier is dropped from `formFields[]`/summary and shows blank (the data is still stored). Custom (non-contact) fields cannot render in the dashboard via this API (platform limitation) — captured as data only.
171
- - Dashboard rendering is **verified via `GET .../forms/{formId}/summary`** (non-empty, count == contact-mapped inputs), not merely by `steps` being present.
172
- - Contact-mapping (`postSubmissionTriggers`) is **not** relied upon (silently dropped here); submissions are captured against the schema regardless.
173
- - Every form is **verified present** via a namespace list before completion.
174
- - **Keep** per form the `formId` and its field `target` keys — the producer for the coding handoff.
229
+
230
+ - Starts from a **clean form list** — pre-existing forms are listed-then-deleted first (a safe no-op
231
+ when none exist), keeping clear of the site's form cap.
232
+ - Contains exactly the forms the request calls for, created on **Form Schemas v4** in the
233
+ **`wix.form_app.form`** namespace, each field built per **About Form Fields**, with lowercase GUID
234
+ ids and a `steps` layout placing every field plus a `SUBMIT_BUTTON`.
235
+ - Is **verified via `GET .../forms/{formId}/summary`** (non-empty, count equal to every input field
236
+ — contact-mapped or not) — not merely by a `200` on create, and not merely by `steps` being
237
+ present.
238
+ - Revises forms with **`PATCH` + the current `revision`** rather than delete-and-recreate, keeping
239
+ the `formId` and the form slot.
240
+ - **Keeps** per form the **`formId` + field `target`s** (the immutable submission keys) — the
241
+ frontend reads everything else (labels, options, order) live from the schema.
@@ -158,29 +158,38 @@ The request body is `items` (each with the product's `catalogItemId` and the Sto
158
158
 
159
159
  ### Attach images (imagery ON only — skip otherwise)
160
160
 
161
- **Only when `imagery` is on** (`SEED.md` § "Entity images"). Products were created text-only above; this pass-2 step writes a generated brand image onto each. Generate + import per `references/IMAGE_GENERATION.md`, keep `file.url`, then PATCH the product.
162
-
163
- **The exact working call — do this per product (getting it right first time avoids a multi-round debug loop):**
164
-
165
- 1. **`GET https://www.wixapis.com/stores/v3/products/{id}`** → read `revision`, `options`, and `variantsInfo` from **`response.product.*`**. The product is **nested under a `product` key** — the GET response is *not* flat.
166
- 2. **`PATCH https://www.wixapis.com/stores/v3/products/{id}`** with the body below. **⚠️ Everything nests under a `product` wrapper.** Putting `id` / `revision` / `media` at the **root** fails `400 "product is invalid: revision must not be empty"` — the #1 cause of the loop here. **Do not send a field mask** (the validator runs before masking → `428`):
167
-
168
- ```json
169
- {
170
- "product": {
171
- "id": "<product id>",
172
- "revision": "<revision from the GET — required; omitting it is the 400 above>",
173
- "media": { "itemsInfo": { "items": [ { "url": "<static.wixstatic.com/…>", "altText": "…" } ] } },
174
- "options": "<echo the GET's product.options, unchanged>",
175
- "variantsInfo": "<echo the GET's product.variantsInfo, unchanged>"
176
- }
177
- }
178
- ```
179
- The image may be referenced by a `static.wixstatic.com` **`url`** or by its Wix Media **`id`** (`<hash>~mv2.png`) — either works.
180
-
181
- - The field that persists is **`media.itemsInfo.items`**, NOT `media.main`. **⚠️ `media.main` set ALONE silently no-ops** — a `200` comes back but re-query shows no image; that is the trap. The server promotes the first `itemsInfo.items` entry to `media.main` for you, so **verify success by reading `media.main.image.url`** — it must resolve to a `static.wixstatic.com` URL. Check that nested string, **not** the presence of `media.main` (which can be a non-null object with no image and makes a failed attach look successful). Conversely `media.itemsInfo` is **write-only** — it comes back `null` on read, so never assert on it.
182
- - Send **one image per product** (primary); a larger gallery is out of scope for the seed.
183
- - **Never block on image failure** — skip and leave the product text-only.
161
+ **Only when `imagery` is on** (`SEED.md` § "Entity images"). Products were created text-only above; this pass-2 step writes a generated brand image onto each. Generate + import per `references/IMAGE_GENERATION.md`, keep each image's `url`.
162
+
163
+ **Attach every product in ONE call** — `POST https://www.wixapis.com/stores/v3/bulk/products/update` (up to 100 products). You already hold each product's `id` **and `revision`** from STEP 2's bulk-create response (`productResults.results[].item`), so **no per-product `GET` is needed**. Each entry nests under a `product` wrapper carrying just `id`, `revision`, and `media` — options, variants, and every other field are left untouched (it's a partial update):
164
+
165
+ ```json
166
+ {
167
+ "products": [
168
+ { "product": {
169
+ "id": "<product id>",
170
+ "revision": "<from the create response>",
171
+ "media": { "itemsInfo": { "items": [ { "url": "<static.wixstatic.com/… or Wix Media id>", "altText": "…" } ] } }
172
+ } }
173
+ ]
174
+ }
175
+ ```
176
+
177
+ - **`revision` is required on every entry** — omitting it fails `400 "revision must not be empty"`. Use the revision from the create response (or a fresh query); a stale one fails the optimistic-concurrency check.
178
+ - **Everything nests under `product`** — `id` / `revision` / `media` at the entry root fails validation. **Send no field mask** (the validator runs before masking → `428`).
179
+ - **Write the image via `media.itemsInfo.items`**; the server derives `media.main` from it. One primary image per product (a larger gallery is out of scope for the seed). The image may be referenced by a `static.wixstatic.com` **`url`** or by its Wix Media **`id`** (`<hash>~mv2.png`) — either works.
180
+ - **Success shape** — `bulkActionMetadata` totals the run, and each result carries an `itemMetadata`:
181
+
182
+ ```jsonc
183
+ {
184
+ "results": [ { "itemMetadata": { "id": "<product id>", "originalIndex": 0, "success": true } } ],
185
+ "bulkActionMetadata": { "totalSuccesses": 1, "totalFailures": 0, "undetailedFailures": 0 }
186
+ }
187
+ ```
188
+ Read `itemMetadata.success` per product (the result carries no product body). **Retry only the failed ids once**, then move on.
189
+ - **Confirm by requery** — `POST …/stores/v3/products/query` with `"fields": ["MEDIA_ITEMS_INFO"]`; the attached image is at `media.main.image.url`. Wix **re-hosts** the image on attach, so that URL is a **new** `wixstatic.com` id — verify it's *a* wixstatic URL, never string-equality against the one you sent. The read-back can lag a beat; one empty read right after success isn't a failure.
190
+ - **Never block on image failure** — a product that won't attach stays text-only.
191
+
192
+ **One-off fix (single product).** To (re)attach a single image later, `PATCH https://www.wixapis.com/stores/v3/products/{id}` with the same `{ "product": { "id", "revision", "media": {…} } }` body — same rules apply (revision required, no field mask, media-only is a partial update that leaves options/variants intact). Read the current `revision` from `GET …/products/{id}` → `response.product.revision` (the GET is not flat); the `200` response carries the image at `media.main.url`.
184
193
 
185
194
  ---
186
195
 
@@ -14,7 +14,7 @@ Run these in order:
14
14
 
15
15
  **If a `wix.config.json` (or `.wix/`) is already present, the project is already connected to Wix — this is the *iterate* case.** Do **not** run `init` again (it's for attaching a *new* Wix project). Read `./wix.config.json` → hold `SITE_ID` in scratch, and skip to §2.
16
16
 
17
- > **Iterate is incremental.** An already-connected project may already be set up and/or seeded from a prior run. In §3–§4, **check current state before acting** — query installed apps before installing, check for already-seeded content before seeding (re-seeding duplicates it), and inspect existing wiring before adding. Do only the delta the new intent requires; leave the rest untouched.
17
+ > **Iterate is incremental.** An already-connected project may already be set up and/or seeded from a prior run. In §3–§4, **check current state before acting** — query installed apps before installing (the Dynamic Context call in `DISCOVERY.md` §1 reports them in one call), check for already-seeded content before seeding (re-seeding duplicates it), and inspect existing wiring before adding. Do only the delta the new intent requires; leave the rest untouched.
18
18
 
19
19
  Otherwise, attach Wix in place:
20
20
 
@@ -93,6 +93,20 @@ Run the agnostic flow against the scaffolded site:
93
93
  (`createClient({ modules, auth: OAuthStrategy({ clientId }) })`), where `clientId` is the public
94
94
  `appId` from the `wix.config.json` written by `init` (§1).
95
95
 
96
+ **If the user didn't specify their own design direction** (no palette, no theme/style words, no
97
+ reference site, no brand guidelines), **decide the run's design tokens per `references/DESIGN.md`**
98
+ before writing any component — theme polarity, a 2–4 color palette, type scale, radius/spacing — and
99
+ hold them for reuse across every page and the themed-block fallback (`IMAGE_GENERATION.md`). If the
100
+ user *did* specify a direction, use theirs instead — `DESIGN.md` is a fallback, not a checklist to
101
+ enforce over an explicit ask. Either way, `DESIGN.md` §3's accessibility floor (WCAG 2.2 AA contrast,
102
+ 16px/1.5 body type) always applies — a page that fails it isn't done yet, regardless of whose palette
103
+ it's using.
104
+
105
+ **For page copy:** if the user didn't supply their own copy or voice direction, write hero/section
106
+ headlines, kickers, subtitles, and CTA labels per **`references/CONTENT.md`** — otherwise use theirs.
107
+ Either way, `CONTENT.md` §1 (the business's category must read literally above the fold) always holds —
108
+ a page a first-time visitor can't identify isn't done yet, regardless of voice.
109
+
96
110
  Then build the pages the user's intent calls for, **wired to the live backend**, using
97
111
  **`references/SDK_HANDOFF.md`** for the per-capability packages, the SDK docs, and the seeded schema to
98
112
  bind (collection/form names + field keys; all other content is queried live). Install the SDK packages the loaded verticals need, author the pages/components directly in the
@@ -28,6 +28,31 @@ Live site: <published-url>
28
28
  Dashboard: https://manage.wix.com/dashboard/<SITE_ID>
29
29
  ```
30
30
 
31
+ ## Suggest a custom domain (proactive, after release)
32
+
33
+ After delivering the links above, **proactively offer a custom domain** — don't wait for the user to ask. The published URL is a generic Wix subdomain; a custom domain is the obvious next step, and the CLI handles the whole flow.
34
+
35
+ 1. **Suggest options.** Build a search query from what you know about the site — its business name, topic, or purpose from this run (not a generic placeholder):
36
+
37
+ ```bash
38
+ npx @wix/cli@latest account domain suggest "<business name or site topic>" --limit 5 --json
39
+ ```
40
+
41
+ All returned suggestions are already available for purchase. Show the user a few of the best fits, and mention they can explore more options — re-run `suggest` with different keywords, a higher `--limit`, or `--tld com net ...` to filter extensions.
42
+
43
+ 2. **Offer to buy, with a direct purchase link.** For the domain(s) the user likes, generate a site-scoped deep link so the purchase is tied to this site and can be connected after payment:
44
+
45
+ ```bash
46
+ npx @wix/cli@latest account --site-id <SITE_ID> domain buy <domain> --json
47
+ ```
48
+
49
+ Use the `siteId` from `wix.config.json`. `buy` does **not** charge anything — it returns a checkout URL (`https://manage.wix.com/get-domain?...`); the user completes payment in the browser.
50
+
51
+ > Your site is live at <published-url>, and you can manage it from your [dashboard](https://manage.wix.com/dashboard/<SITE_ID>).
52
+ > To build a professional online presence, [connect a custom domain](<checkout-url>) — **mybusiness.com** is available.
53
+
54
+ If the user isn't interested, drop it — one offer, no upselling.
55
+
31
56
  ## Before you sign off — feedback checkpoint
32
57
 
33
58
  This is the last step of the run — the natural point to check `../FEEDBACK.md`. Don't wait for the