@wix/agent-skills 1.16.0 β†’ 1.16.2

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 (94) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +72 -8
  3. package/skills/wix-app/references/CODE_QUALITY.md +0 -1
  4. package/skills/wix-app/references/DASHBOARD_MODAL.md +21 -14
  5. package/skills/wix-app/references/DASHBOARD_PAGE.md +30 -184
  6. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +19 -3
  7. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +172 -0
  8. package/skills/wix-app/references/dashboard-page/WDS_LAYOUT.md +187 -0
  9. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +12 -7
  10. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +31 -2
  11. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +6 -1
  12. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +60 -0
  13. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +6 -6
  14. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +167 -0
  15. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +2 -2
  16. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +187 -0
  17. package/skills/wix-app/scripts/scan-a11y-code.cjs +777 -0
  18. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +201 -0
  19. package/skills/wix-base44-connector/SKILL.md +185 -0
  20. package/skills/wix-base44-connector/scripts/utils.js +212 -0
  21. package/skills/wix-design-system/SKILL.md +19 -15
  22. package/skills/wix-docs/SKILL.md +75 -1
  23. package/skills/wix-headless/references/CAPABILITIES.md +16 -3
  24. package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
  25. package/skills/wix-headless/references/SEED.md +1 -1
  26. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +560 -102
  27. package/skills/wix-headless/references/inline-recipes/setup-forms.md +210 -143
  28. package/skills/wix-manage/SKILL.md +20 -17
  29. package/skills/wix-manage/references/accessibility/scan-site-accessibility.md +98 -0
  30. package/skills/wix-manage/references/analytics/analytics-dashboard-navigation.md +1 -2
  31. package/skills/wix-manage/references/domains/domain-search-purchase-and-connect.md +2603 -0
  32. package/skills/wix-manage/references/events/create-wix-event.md +112 -90
  33. package/skills/wix-manage/references/events/manage-wix-events.md +33 -94
  34. package/skills/wix-manage/references/sites/create-headless-site.md +1 -0
  35. package/skills/wix-manage/references/sites/manage-oauth-apps.md +154 -0
  36. package/skills/wix-manage/references/sites/read-site-context.md +125 -0
  37. package/skills/wix-manage/references/sites/site-import.md +67 -15
  38. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +273 -0
  39. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +1 -1
  40. package/skills/wix-vibe-headless/SKILL.md +2 -1
  41. package/skills/wix-vibe-headless/install/deploy.cjs +63 -3
  42. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +104 -0
  43. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +74 -0
  44. package/skills/wix-vibe-headless/platforms/base44.md +15 -40
  45. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +7 -11
  46. package/skills/wix-vibe-headless/references/blog/seed/SEED.md +1 -1
  47. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +7 -11
  48. package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +1 -1
  49. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +1 -2
  50. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +7 -12
  51. package/skills/wix-vibe-headless/references/events/seed/SEED.md +1 -1
  52. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +7 -11
  53. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +7 -11
  54. package/skills/wix-vibe-headless/references/portfolio/seed/SEED.md +1 -1
  55. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +7 -11
  56. package/skills/wix-vibe-headless/references/pricing-plans/seed/SEED.md +1 -1
  57. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +7 -11
  58. package/skills/wix-vibe-headless/references/restaurants/seed/SEED.md +1 -1
  59. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +1 -1
  60. package/skills/wix-vibe-headless/references/shared/app/rest/wix-config.js +5 -3
  61. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +75 -13
  62. package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +29 -86
  63. package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +3 -8
  64. package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +78 -105
  65. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductCard.js +92 -0
  66. package/skills/wix-vibe-headless/references/storefront/app/hooks/useVariantOptions.js +76 -0
  67. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +1 -1
  68. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +44 -5
  69. package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +0 -326
  70. package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +0 -115
  71. package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +0 -264
  72. package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +0 -37
  73. package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +0 -86
  74. package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +0 -119
  75. package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +0 -103
  76. package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +0 -76
  77. package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +0 -82
  78. package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +0 -89
  79. package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +0 -124
  80. package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +0 -91
  81. package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +0 -71
  82. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +0 -70
  83. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +0 -73
  84. package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +0 -98
  85. package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +0 -278
  86. package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +0 -94
  87. package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +0 -43
  88. package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +0 -66
  89. package/skills/wix-app/references/auto-patterns-dashboard/views.md +0 -76
  90. package/skills/wix-app/scripts/generate-auto-patterns.js +0 -510
  91. package/skills/wix-manage/references/domains/domain-search-and-purchase.md +0 -437
  92. package/skills/wix-manage/references/stores/create-product-from-image.md +0 -1031
  93. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +0 -623
  94. package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +0 -106
@@ -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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: wix-manage
3
- description: "Wix business solution management recipes β€” REST API operations for configuring and managing Wix business solutions. Routes to: stores, bookings, get-paid, CMS, contacts, forms, media, app-installation, pricing-plans, restaurants, rich-content, sites, blog, calendar, domains, events, site-properties, ecommerce, marketing, google-ads, analytics, dashboard-navigation."
3
+ description: "Wix business solution management recipes β€” REST API operations for configuring and managing Wix business solutions. Routes to: stores, bookings, get-paid, CMS, contacts, forms, media, app-installation, pricing-plans, restaurants, rich-content, sites, blog, calendar, domains, events, site-properties, ecommerce, marketing, google-ads, analytics, accessibility, dashboard-navigation."
4
4
  compatibility: Requires Wix REST API access (API key or OAuth).
5
5
  ---
6
6
 
@@ -34,6 +34,13 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
34
34
 
35
35
  ---
36
36
 
37
+ ## Accessibility
38
+
39
+ ### [Scan a Wix Site for Accessibility Issues](references/accessibility/scan-site-accessibility.md)
40
+ **Technical:** Runs an asynchronous accessibility scan for a full site, one page, or every page in any supported Wix page collection. Discovers collection IDs instead of hardcoding verticals, polls the scan to completion, separates failed pages from clean pages, and returns prioritized, agent-friendly findings and fix guidance.
41
+
42
+ ---
43
+
37
44
  ## Analytics
38
45
 
39
46
  ### [Query Site Analytics](references/analytics/query-site-analytics.md)
@@ -159,8 +166,8 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
159
166
 
160
167
  ## Domains
161
168
 
162
- ### [Domain Search and Purchase](references/domains/domain-search-and-purchase.md)
163
- **Technical:** Search for available domains, get domain suggestions, and generate purchase links using Domain Search V2 API. Covers availability checks, TLD filtering, and connecting domains to Wix sites.
169
+ ### [Domain Search, Purchase and Connect](references/domains/domain-search-purchase-and-connect.md)
170
+ **Technical:** Purchase domains, connect domains to Wix sites, search for available domains and get domain suggestions. Covers availability checks, TLD filtering, purchase flow and connecting domains to Wix sites.
164
171
 
165
172
  ### [Domains Dashboard Navigation](references/domains/domains-dashboard-navigation.md)
166
173
  **Technical:** Direct links to the site-level domain settings page and the account-level My Domains page on manage.wix.com, paired with the Domain Search read APIs.
@@ -223,10 +230,10 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
223
230
  ## Events
224
231
 
225
232
  ### [Create Event](references/events/create-wix-event.md)
226
- **Technical:** Creates an event with the Wix Events V3 API β€” required request body, ISO-8601 date and time settings, venue/online/TBD location and street addresses, RSVP vs ticketed registration, guest capacity, and short vs Ricos rich-text descriptions. Distinguishes Wix Events from the Calendar, Marketing Calendar and Automations APIs that share the "events" name. Key endpoint: /events/v3/events.
233
+ **Technical:** Creates an event with the Wix Events V3 API β€” required request body, ISO-8601 date and time settings, venue/online/TBD location and street addresses, RSVP vs ticketed registration, guest capacity, short vs Ricos rich-text descriptions, ticket tiers and pricing, and recurring series from explicit occurrence dates. Distinguishes Wix Events from the Calendar, Marketing Calendar and Automations APIs that share the "events" name. Key endpoints: /events/v3/events, /events/v3/ticket-definitions.
227
234
 
228
235
  ### [Manage Events](references/events/manage-wix-events.md)
229
- **Technical:** Manages existing events with the Wix Events V3 API β€” ticket definitions and pricing (fixed, free, donation, multiple tiers), publishing a draft, cancelling, deleting, cloning, updating an event's date, counting events, and building recurring series from explicit occurrence dates. Key endpoints: /events/v3/events, /events/v3/ticket-definitions.
236
+ **Technical:** Operates on events that already exist with the Wix Events V3 API β€” publishing a draft, cancelling, deleting, cloning, updating an event's date, and counting events, plus the draft-event permission that makes those calls fail with 403. Key endpoint: /events/v3/events.
230
237
 
231
238
  ---
232
239
 
@@ -360,9 +367,15 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
360
367
  ### [Create Headless Site](references/sites/create-headless-site.md)
361
368
  **Technical:** Creates a Wix Headless site (headless business) with one account-level API call β€” site, Wix Business Solution apps, and a configured OAuth client.
362
369
 
370
+ ### [Manage OAuth Apps](references/sites/manage-oauth-apps.md)
371
+ **Technical:** Create, read, update, and query OAuth apps for a Wix headless site. Each OAuth app's `id` is the `client_id` for frontends connecting to the site's Wix APIs. Secret and rotation are dashboard-only.
372
+
363
373
  ### [Query Sites](references/sites/query-sites.md)
364
374
  **Technical:** Lists and queries all sites associated with a Wix account using Sites API. Covers pagination with cursor-based navigation.
365
375
 
376
+ ### [Read Account or Site Context](references/sites/read-site-context.md)
377
+ **Technical:** One call that returns a site's installed apps (by display name), locale, currency, status, and catalog version. Replaces separate query-sites + list-installed-apps + site-properties calls. Use this first on any unfamiliar site to decide which management recipes to follow.
378
+
366
379
  ### [Site Import](references/sites/site-import.md)
367
380
  **Technical:** Drives the autonomous Wix Site Import agent over REST (`/site-import/v1/imports`) to migrate a store/site from another platform (Shopify, WooCommerce, Magento, or any URL) into Wix. Covers Start/Poll/Reply/Cancel, relaying agent questions and progress in plain language, handling `DEPLOYED`/`FAILED`/`AUTH_EXPIRED`/`SESSION_EXPIRED` states, and post-deploy follow-up changes. Use when the user wants to import, migrate, or clone an existing store/site into Wix.
368
381
 
@@ -376,18 +389,11 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
376
389
  ### [Add Store Pages to Site](references/stores/add-store-pages-to-site.md)
377
390
  **Technical:** Adds missing checkout and cart pages to a site when Stores app is installed. Used when store pages are missing after migration or setup issues.
378
391
 
379
- ### [Bulk Create Products with Options](references/stores/bulk-create-products-with-options.md)
380
- **Technical:** Uses bulk products endpoint to create multiple products with inventory in a single request. Handles variant generation from options, media format requirements, and error handling for partial failures.
381
-
382
- ### [Create Product from Image](references/stores/create-product-from-image.md)
383
- **Technical:** **MANDATORY entry point** for any "create product from image" or "create product from photo" request. STEP 1 auto-detects the site's catalog version (V1/V3) via the provision endpoint, then runs the matching flow inline β€” V3 supports up to 3 images, info sections, SEO, options/variants, and atomic creation; V1 supports a single image, simple product, and a separate media-attach call. Combines Media Upload + LLM analysis + Product Creation + (V1 only) Add Product Media in one self-contained recipe.
384
-
385
-
386
392
  ### [Create Product (Catalog V1)](references/stores/create-product-catalog-v1.md)
387
393
  **Technical:** Create products using the Catalog V1 Products API. Use this recipe when the site's catalog version is CATALOG_V1. Covers simple product creation, product with options, and key V1 request structure differences from V3.
388
394
 
389
- ### [Create Product with Options (Catalog V3)](references/stores/create-product-with-options-catalog-v3.md)
390
- **Technical:** Single product creation with options using Catalog V3 Products API. Covers option types (TEXT_CHOICES, SWATCH_CHOICES), choice configuration, and automatic variant generation.
395
+ ### [Create Product (Catalog V3)](references/stores/create-product-catalog-v3.md)
396
+ **Technical:** **Mandatory first read for every Catalog V3 create-product request, including vague requests.** Before any other documentation or API tool, load exactly `https://dev.wix.com/docs/api-reference/business-solutions/stores/skills/create-product-catalog-v3`. When no product is identified, that recipe read must be the final tool call; respond only: β€œWhat product would you like to create? You can upload up to 3 images and I’ll generate the product information from them, or describe the product in text.” Then stop. **Never replace this with a list or questions for name, price, description, type, images, inventory, SKU, options, SEO, or other fields.** If name or price is missing, ask for it or offer to suggest it, then stop. When name and price are present, create from supplied details without requiring optional enrichment. Never default price to `0`. The recipe owns single/bulk endpoint choice, inventory, physical/digital products, images, options, variants, prices, SKUs, limits, and validation.
391
397
 
392
398
  ### [Find Products (Query and Search, Catalog V3)](references/stores/find-products-query-and-search-catalog-v3.md)
393
399
  **Technical:** Find, search, query, and list products from a Wix Store using Catalog V3 Search Products and Query Products endpoints. Explains when to use each endpoint, correct fields enum values, filtering, sorting, and paging.
@@ -395,9 +401,6 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
395
401
  ### [Query Products (Catalog V1)](references/stores/query-products-catalog-v1.md)
396
402
  **Technical:** Query and list products from a Wix Store using the Catalog V1 Query Products endpoint. Use this recipe when the site's catalog version is CATALOG_V1. Covers basic queries, filtering, sorting, and paging.
397
403
 
398
- ### [Setup Online Store (Catalog V3)](references/stores/setup-online-store-catalog-v3.md)
399
- **Technical:** Initializes a Stores catalog with Catalog V3 Products API, bulk products endpoint, and Categories API. Covers product creation, option configuration, variant management, and category assignment.
400
-
401
404
  ### [Update Product Pre-Order](references/stores/update-product-pre-order.md)
402
405
  **Technical:** Manages pre-order settings for product variants using V3 Inventory API. Covers enabling/disabling pre-orders, setting messages, configuring limits, and handling trackQuantity requirements.
403
406