Subchapter 8.64
references/forms/create-form.mdMarkdown14 KBView on GitHub
Standard call shape (every curl below). The
<AUTH>placeholder is shorthand forAuthorization: Bearer <TOKEN>only. Body-bearing requests also needContent-Type: application/json.
Create a form on a Wix site that appears in the Forms & Submissions dashboard. The form collects visitor information (e.g., name, email) and can automatically upsert contacts on submission.
Call the Create Form endpoint with the wix.form_app.form namespace. The Wix Forms app (appDefId: 14ce1214-b278-a7e4-1373-00cebd1bef7c) is usually already installed on sites.
curl -X POST \
'https://www.wixapis.com/form-schema-service/v4/forms' \
-H 'Content-Type: application/json' \
-H 'Authorization: <AUTH>' \
-d '{
"form": {
"name": "Contact Form",
"namespace": "wix.form_app.form",
"enabled": true,
"spamFilterProtectionLevel": "ADVANCED",
"formFields": [
{
"id": "c1a2b3d4-0001-4a00-b000-000000000001",
"hidden": false,
"identifier": "CONTACTS_FIRST_NAME",
"fieldType": "INPUT",
"inputOptions": {
"target": "first_name_0001",
"pii": true,
The response includes the created form with its id. Store this ID to manage the form later.
Verify the form in the dashboard: https://manage.wix.com/dashboard/{siteId}/forms
id fields (for formFields, steps) and all fieldId references in the layout must be valid UUIDs. Generate fresh UUIDs for each form you create — do not reuse the example UUIDs above.id and a unique target value. The target is used to map submissions to contact fields.identifier must be a recognized Wix value. Custom identifiers like "product_name" or "color_preference" will cause the field to be silently dropped from the form — no error is thrown. For any generic/custom text field, use "TEXT_INPUT" as the identifier and set the display name via the label property in textInputOptions."format": "UNKNOWN_FORMAT". For email fields, use "format": "EMAIL". For phone fields, use "format": "PHONE". Valid format values: UNKNOWN_FORMAT, DATE, TIME, DATE_TIME, EMAIL, URL, UUID, PHONE, URI, HOSTNAME, COLOR_HEX, CURRENCY, LANGUAGE, DATE_OPTIONAL_TIME.DISPLAY field with identifier: "SUBMIT_BUTTON".maximum number of forms reached), forcing you to GET the form list and DELETE the test forms before the real create can succeed. Assemble all fields (including any RADIO_GROUP/DROPDOWN per § “Choice fields”) and POST once.| Identifier | componentType | format | Use case |
|---|---|---|---|
TEXT_INPUT | TEXT_INPUT | UNKNOWN_FORMAT | Generic single-line text (use label for display name) |
CONTACTS_FIRST_NAME | TEXT_INPUT | UNKNOWN_FORMAT | Contact first name |
CONTACTS_LAST_NAME | TEXT_INPUT | UNKNOWN_FORMAT | Contact last name |
CONTACTS_EMAIL | TEXT_INPUT | EMAIL | Contact email |
CONTACTS_PHONE | TEXT_INPUT | PHONE | Contact phone |
SUBMIT_BUTTON | N/A (DISPLAY field) | N/A | Submit button |
TEXT_INPUT | RADIO_GROUP | UNKNOWN_FORMAT | Single-choice from a fixed list (radio buttons) — see § “Choice fields” |
TEXT_INPUT | DROPDOWN | UNKNOWN_FORMAT | Single-choice from a fixed list (dropdown) — same shape as RADIO_GROUP |
Note:
LONG_TEXT_INPUTis not supported as acomponentTypevia REST — it throwsINVALID_ARGUMENT. UseTEXT_INPUTfor all text fields.
A single-choice field (radio buttons or a dropdown — e.g. an RSVP “Will you attend?”) is a STRING input field, not a separate field type. It uses identifier: "TEXT_INPUT", inputType: "STRING", and sets componentType to RADIO_GROUP (or DROPDOWN) inside stringOptions. Two things must agree or the field breaks:
stringOptions.validation.enum must list every option value (an empty enum is for free-text only).stringOptions.radioGroupOptions.options[] carries the rendered choices — each option needs its own UUID id, a value, and a label. (For DROPDOWN, use dropdownOptions with the same {id, value, label} shape.)CRITICAL — silent fallback to TEXT_INPUT. If
radioGroupOptionsis missing/malformed (wrong key likechoicesinstead ofoptions, an option missing itsid, or an emptyvalidation.enum), the API does not error — it silently creates the field as a plainTEXT_INPUT. If a choice field renders as a text box, this is why. Build it correctly on the first call; do not probe.
{
"id": "a1b2c3d4-1002-4e00-8001-000000000002",
"hidden": false,
"identifier": "TEXT_INPUT",
"fieldType": "INPUT",
"inputOptions": {
"target": "attending_0002",
"pii": false,
"required": true,
"inputType": "STRING",
"readOnly": false,
"stringOptions": {
"validation": {
"format": "UNKNOWN_FORMAT",
"enum": ["Joyfully accepts", "Regretfully declines"]
},
"componentType": "RADIO_GROUP",
"radioGroupOptions": {
"label": "Will you attend?",
"showLabel": true,
"numberOfColumns": "ONE",
"options": [
{ "id": "c3d4e5f6-3001-4a00-8001-000000000001", "value": "Joyfully accepts", "label": "Joyfully accepts" },
{ "id": "c3d4e5f6-3001-4a00-8001-000000000002", "value": "Regretfully declines", "label": "Regretfully declines" }
]
}
}
}
}numberOfColumns is a string enum ("ONE", "TWO", "THREE") controlling the radio layout — omit it and the field still works (defaults to one column).
The steps[].layout.large.items array controls how fields are positioned:
row and column set the position (0-based grid)width sets the column span (max 12 for full width, 6 for half)height is typically 1The postSubmissionTriggers.upsertContact object maps form field targets to contact fields, so each submission automatically creates or updates a contact. The fieldsMapping keys must match the target values from the form fields.
The Wix Forms app (appDefId: 14ce1214-b278-a7e4-1373-00cebd1bef7c) must be installed on the site. It is usually pre-installed, but if the API returns a “missing installed app” error, install it first using the Install Wix Apps recipe.
| Error | Cause | Fix |
|---|---|---|
Unrecognized value passed for enum | Invalid componentType value (e.g., LONG_TEXT_INPUT) | Use only componentType values from the schema: TEXT_INPUT, RADIO_GROUP, DROPDOWN, DATE_TIME, PHONE_INPUT, DATE_INPUT, TIME_INPUT, DATE_PICKER, PASSWORD |
| Field silently missing from created form | Custom identifier value (e.g., "product_name") | Use a recognized identifier like TEXT_INPUT and set display name via label |
| Choice field rendered as a plain text box | radioGroupOptions/dropdownOptions malformed (wrong key, option missing id, empty validation.enum) — API silently falls back to TEXT_INPUT | Match the § “Choice fields” shape exactly: componentType in stringOptions, options[] each with a UUID id, and validation.enum listing all option values |
maximum number of forms reached / form-cap error | Sites cap at ~4 forms; reached by creating throwaway test forms | GET form-schema-service/v4/forms then DELETE the unwanted forms; build the real form in one call (don’t probe) |
Permissions for given namespace not found | wix.form_app.form namespace not active | Ensure the Wix Forms app is installed; try creating a form through the UI first to activate the namespace |
missing installed app | Wix Forms app not installed | Install app 14ce1214-b278-a7e4-1373-00cebd1bef7c via the Install Wix Apps recipe |