Start free
Developers

Form schema

A OneForm form is a JSON definition: its questions, logic and screens. This is the JSON Schema (draft 2020-12) OneForm checks every save against, generated from the same code.

Structure

fieldsThe questions, in order: each with a unique id, a type, a title and required.
welcomeThe first screen, if any.
thankYouThe default thank-you screen.
endingsOther thank-you screens, chosen by conditions.
variablesNumbers and text that logic can change, for scores.
hiddenFieldsValues the form takes from its link or embed: [{ key, label }].
settingsLanguages and other form settings.
translationsText in other languages.
reportThe document OneFormAI writes from each submission: { enabled, title, prompt, docType }.

Questions can carry visibleIf conditions and jumps; operators are is, is_not, contains, not_contains, any_of, none_of, all_of, eq, neq, gt, gte, lt, lte, before, after, answered, not_answered. A role (first_name, last_name, full_name, email, phone, company) tells OneForm who the respondent is, for names in reports and emails and for Leads.

Question types

typeShown asCollects
short_textShort textOne line of text.
long_textLong textA paragraph.
multiple_choiceMultiple choiceOne or several of choices: [{ id, label }]. multiple allows several, allowOther adds an Other box.
yes_noYes / NoYes or no.
emailEmailAn email address.
phonePhone numberA phone number.
numberNumberA number.
dateDateA date.
contact_groupContact infoSeveral contact details on one screen, in fields of type short_text, email, phone, number.
line_itemsLine itemsRows of items, such as receipts or expenses.
statementStatementText to read. Asks nothing.

The schema

Open a property to see what it holds. Required properties are marked.

form-schema.json
  • welcomeobject
    • enabledbooleandefault true
    • titlestringrequired
    • descriptionstring
    • layoutstring
      "classic""card""image-top""banner""background""background-dark""split-left""split-right""side-third""avatar"
    • imageobject
      • urlstringrequired
      • altstring
    • overlaynumber≥ 0≤ 0.9
    • showLogoboolean
    • linksobject[]at most 10
      • kindstringrequired
        "website""linkedin""x""facebook""instagram""youtube""tiktok""email""phone""booking"
      • urlstringrequiredmax length 2000
      • labelstring
    • buttonTextstringdefault "Start"
    • imageUrlstring
    • badgestring
    • headlinestring
  • fieldsobject[]required
    • idstringrequiredmin length 1
    • titlestringrequired
    • descriptionstring
    • requiredbooleandefault false
    • placeholderstring
    • rolestring
      "first_name""last_name""full_name""email""phone""company"
    • typestringrequired
      "short_text""long_text""multiple_choice""yes_no""email""phone""number""date""contact_group""line_items""statement"
    • choicesobject[]
      • idstringrequiredmin length 1
      • labelstringrequired
    • allowOtherboolean
    • multipleboolean
    • fieldsobject[]
      • idstringrequiredmin length 1
      • titlestringrequired
      • descriptionstring
      • requiredbooleandefault false
      • placeholderstring
      • rolestring
        "first_name""last_name""full_name""email""phone""company"
      • typestringrequired
        "short_text""email""phone""number"
    • mediaobject
      • kindstringrequired
        "image""video"
      • urlstringrequired
      • altstring
      • layoutstring
        "stack""split-left""split-right"
    • buttonTextstring
    • visibleIfobject
      • matchstringrequired
        "all""any"
      • conditionsobject[]required
        • idstringrequired
        • leftobject | object | objectrequired
        • opstringrequired
          "is""is_not""contains""not_contains""any_of""none_of""all_of""eq""neq""gt""gte""lt""lte""before""after""answered""not_answered"
        • valuestring | number | boolean | string[]
    • jumpsobject[]
      • idstringrequired
      • whenobjectrequired
        • matchstringrequired
          "all""any"
        • conditionsobject[]required
          • idstringrequired
          • leftobject | object | objectrequired
          • opstringrequired
            "is""is_not""contains""not_contains""any_of""none_of""all_of""eq""neq""gt""gte""lt""lte""before""after""answered""not_answered"
          • valuestring | number | boolean | string[]
      • gotoobject | objectrequired
    • otherwiseobject | object
    • calcobject[]
      • idstringrequired
      • varstringrequired
      • opstringrequired
        "add""subtract""multiply""set""add_answer"
      • amountnumberrequired
      • whenobject
        • matchstringrequired
          "all""any"
        • conditionsobject[]required
          • idstringrequired
          • leftobject | object | objectrequired
          • opstringrequired
            "is""is_not""contains""not_contains""any_of""none_of""all_of""eq""neq""gt""gte""lt""lte""before""after""answered""not_answered"
          • valuestring | number | boolean | string[]
    • leadPoints{ [key]: number }
    • lineItemsobject
      • currencystring
      • showDateboolean
      • showCategoryboolean
      • showQuantityboolean
      • categoriesstring[]
      • taxRatenumber
      • maxRowsinteger≥ -9007199254740991≤ 9007199254740991
    • pinstring
      "first""last"
  • thankYouobjectrequired
    • idstring
    • titlestringrequired
    • descriptionstring
    • layoutstring
      "classic""card""image-top""banner""background""background-dark""split-left""split-right""side-third""avatar"
    • imageobject
      • urlstringrequired
      • altstring
    • overlaynumber≥ 0≤ 0.9
    • showLogoboolean
    • linksobject[]at most 10
      • kindstringrequired
        "website""linkedin""x""facebook""instagram""youtube""tiktok""email""phone""booking"
      • urlstringrequiredmax length 2000
      • labelstring
    • ctaobject
      • textstringrequired
      • urlstringrequiredmax length 2000
    • redirectobject
      • urlstringrequired
      • delaySecnumber≥ 0≤ 30
      • paramsstring[]
    • whenobject
      • matchstringrequired
        "all""any"
      • conditionsobject[]required
        • idstringrequired
        • leftobject | object | objectrequired
        • opstringrequired
          "is""is_not""contains""not_contains""any_of""none_of""all_of""eq""neq""gt""gte""lt""lte""before""after""answered""not_answered"
        • valuestring | number | boolean | string[]
    • hideOfferboolean
    • schedulerobject
      • providerstringrequired
        "calendly""calcom""tidycal""acuity""savvycal""youcanbookme""hubspot""zoho""msbookings""google""other""oneform"
      • urlstringmax length 500
      • displaystring
        "inline""button"
      • heightinteger≥ 400≤ 1600
      • prefillboolean
      • labelstringmax length 60
  • endingsobject[]
    • idstringrequired
    • titlestringrequired
    • descriptionstring
    • layoutstring
      "classic""card""image-top""banner""background""background-dark""split-left""split-right""side-third""avatar"
    • imageobject
      • urlstringrequired
      • altstring
    • overlaynumber≥ 0≤ 0.9
    • showLogoboolean
    • linksobject[]at most 10
      • kindstringrequired
        "website""linkedin""x""facebook""instagram""youtube""tiktok""email""phone""booking"
      • urlstringrequiredmax length 2000
      • labelstring
    • ctaobject
      • textstringrequired
      • urlstringrequiredmax length 2000
    • redirectobject
      • urlstringrequired
      • delaySecnumber≥ 0≤ 30
      • paramsstring[]
    • whenobject
      • matchstringrequired
        "all""any"
      • conditionsobject[]required
        • idstringrequired
        • leftobject | object | objectrequired
        • opstringrequired
          "is""is_not""contains""not_contains""any_of""none_of""all_of""eq""neq""gt""gte""lt""lte""before""after""answered""not_answered"
        • valuestring | number | boolean | string[]
    • hideOfferboolean
    • schedulerobject
      • providerstringrequired
        "calendly""calcom""tidycal""acuity""savvycal""youcanbookme""hubspot""zoho""msbookings""google""other""oneform"
      • urlstringmax length 500
      • displaystring
        "inline""button"
      • heightinteger≥ 400≤ 1600
      • prefillboolean
      • labelstringmax length 60
  • variablesobject[]
    • namestringrequired
    • labelstring
    • initialnumber
  • hiddenFieldsobject[]
    • keystringrequired
    • labelstring
  • settingsobject
    • showQuestionNumbersboolean
    • languagesobject
      • enabledbooleanrequired
      • defaultstring
        "en""fr""es"
      • availablestring[]
      • autoDetectboolean
    • voiceobject
      • enabledbooleanrequired
      • maxSecondsnumber
      • modestring
        "offer""native"
      • voicestring
      • fillManyboolean
      • goalstring
      • colorsstring[]at most 3
    • personalizationobject
      • enabledbooleanrequired
    • consultationobject
      • enabledbooleanrequired
      • titlestringmax length 120
      • descriptionstringmax length 600
      • durationMininteger≥ 5≤ 480
      • priceobject
        • amountintegerrequired≥ 0≤ 1000000
        • currencystringrequiredmin length 3max length 3
      • locationobject
        • kindstringrequired
          "zoom""meet""teams""phone""in_person""custom"
        • phoneModestring
          "firm_calls""invitee_calls"
        • phonestringmax length 40
        • addressstringmax length 300
        • urlstringmax length 500
      • bufferBeforeMininteger≥ 0≤ 240
      • bufferAfterMininteger≥ 0≤ 240
      • minNoticeMininteger≥ 0≤ 43200
      • maxDaysAheadinteger≥ 1≤ 365
      • maxPerDayinteger≥ 1≤ 50
      • hours{ [key]: object[] }
      • remindersboolean
      • changeHoursinteger≥ 0≤ 720
      • refundHoursinteger≥ 0≤ 720
      • confirmationstringmax length 600
    • kindstring
      "booking"
    • dynamicobject
      • enabledbooleanrequired
      • maxQuestionsinteger≥ -9007199254740991≤ 9007199254740991
      • minQuestionsinteger≥ -9007199254740991≤ 9007199254740991
      • goalstring
  • translations{ [key]: { [key]: object } }
  • reportobject
    • enabledbooleanrequired
    • titlestringdefault "Your personalized report"
    • promptstringdefault ""
    • ideastring
    • kindstring
      "report""document"
    • docTypestring
      "report""onboarding""engagement_letter""proposal""invoice""bill""checklist""hr_record""tax_organizer""document_request""memo""scope""task_list"
    • audiencestring
      "respondent""internal"
    • useAiboolean
    • pdfStylestring
      "classic""modern""executive""minimal"
    • deliverystring
      "ai""file"
    • fileobject
      • idstringrequired
      • namestringrequired
      • bytesintegerrequired≥ -9007199254740991≤ 9007199254740991
    • fileSummarystringmax length 600
    • autoSendboolean
    • autoSendAckstring
    • nextStepobject
      • kindstringrequired
        "none""booking""form"
      • formIdstring
      • labelstringmax length 60
    • pricingobject
      • enabledbooleanrequired
      • amountintegerrequired≥ 0≤ 1000000
      • currencystringrequiredmin length 3max length 3
      • headlinestringmax length 120
      • bulletsstring[]at most 5
      • buttonLabelstringmax length 60

Example

A small, valid form: five questions, one shown only to business owners, and a report.

definition.json
{  "welcome": {    "enabled": true,    "title": "Let's find your tax savings",    "description": "Two minutes, five questions.",    "buttonText": "Start"  },  "fields": [    {      "id": "name",      "type": "short_text",      "title": "What's your first name?",      "required": true,      "role": "first_name"    },    {      "id": "business",      "type": "yes_no",      "title": "Do you own a business?",      "required": true    },    {      "id": "entity",      "type": "multiple_choice",      "title": "How is it set up?",      "required": true,      "choices": [        {          "id": "sole",          "label": "Sole proprietor"        },        {          "id": "llc",          "label": "LLC"        },        {          "id": "scorp",          "label": "S corporation"        }      ],      "visibleIf": {        "match": "all",        "conditions": [          {            "id": "c1",            "left": {              "kind": "field",              "fieldId": "business"            },            "op": "is",            "value": true          }        ]      }    },    {      "id": "income",      "type": "number",      "title": "Roughly what did you earn last year?",      "required": false    },    {      "id": "contact",      "type": "contact_group",      "title": "Where should we send your report?",      "required": true,      "fields": [        {          "id": "email",          "type": "email",          "title": "Email",          "required": true,          "role": "email"        },        {          "id": "phone",          "type": "phone",          "title": "Phone",          "required": false,          "role": "phone"        }      ]    }  ],  "thankYou": {    "title": "Thanks, {{first_name|there}}!",    "description": "We'll email your report once a CPA has reviewed it."  },  "report": {    "enabled": true,    "title": "Your tax opportunities",    "prompt": "Write a short, friendly report of the tax-saving opportunities that fit these answers."  }}

Checking a definition

AI agents connected to OneForm's MCP server can read this schema with get_form_schema (or the oneform://docs/form-schema resource), check a draft with validate_form_definition, and then create it with create_form. New forms are drafts until someone publishes them.

In your own code, any JSON Schema 2020-12 validator can check a definition against form-schema.json. OneForm also checks what a schema can't: that uploaded files and booking links work, and logic rules that point nowhere or can never be true (warnings). That's what validate_form_definition reports.

Questions about the API, webhooks or embeds? Ask a developer.