[{"data":1,"prerenderedAt":53},["ShallowReactive",2],{"doc-forms":3},{"html":4,"headings":5},"\u003Cp>Collect people before you launch, or whenever you want to hear from them: a\nwaitlist, a &quot;notify me when it is ready&quot; box, an early-access request or a short\ninterest form. Put it on your site with one script tag, as a plain HTML form, on\na hosted page, in a SwiftUI app, or post to the API from your own UI.\u003C\u002Fp>\n\u003Cp>Everyone who signs up becomes a \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FCONTACTS.md\" target=\"_blank\" rel=\"noopener\">contact\u003C\u002Fa> of the project: you see\nthem under \u003Cstrong>Contacts → People\u003C\u002Fstrong> with \u003Cstrong>Added via: Lead form\u003C\u002Fstrong>, each form gets a\nsegment of its own, and you can send them a welcome email, start them on a\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FMARKETING.md#sequences\" target=\"_blank\" rel=\"noopener\">sequence\u003C\u002Fa> and email them later with a campaign.\u003C\u002Fp>\n\u003Cp>Panel: \u003Cstrong>Project → Forms\u003C\u002Fstrong>, in the web panel or the native app.\u003C\u002Fp>\n\u003Ch2 id=\"a-form\">A form\u003Ca class=\"heading-anchor\" href=\"#a-form\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>A project has up to 50 forms. Each has a \u003Cstrong>key\u003C\u002Fstrong> (the name your site asks for it\nby, such as \u003Ccode>waitlist\u003C\u002Fcode>), a name, and can be switched off: a form that is not\ntaking sign-ups answers \u003Ccode>404\u003C\u002Fcode>, and the script draws nothing.\u003C\u002Fp>\n\u003Ch3 id=\"fields\">Fields\u003Ca class=\"heading-anchor\" href=\"#fields\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Up to 12, in order. There is always exactly one email field; everything else is\nup to you, from a single email box to a longer form.\u003C\u002Fp>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Type\u003C\u002Fth>\n\u003Cth>Saved as\u003C\u002Fth>\n\u003Cth>Notes\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>email\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the contact's email\u003C\u002Ftd>\n\u003Ctd>Always there, always required.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>name\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the contact's name\u003C\u002Ftd>\n\u003Ctd>At most one.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>text\u003C\u002Fcode>, \u003Ccode>textarea\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an attribute\u003C\u002Ftd>\n\u003Ctd>Up to 200 and 500 characters.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>number\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an attribute (a number)\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>url\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an attribute\u003C\u002Ftd>\n\u003Ctd>An http(s) address.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>phone\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an attribute\u003C\u002Ftd>\n\u003Ctd>Digits, spaces, \u003Ccode>+ ( ) . \u002F -\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>select\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an attribute\u003C\u002Ftd>\n\u003Ctd>One of up to 20 options.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>checkbox\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>an attribute (\u003Ccode>true\u003C\u002Fcode> \u002F \u003Ccode>false\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd>Make it required for &quot;I agree to…&quot;.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>file\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a private file of the contact\u003C\u002Ftd>\n\u003Ctd>Up to 3 per form. See \u003Ca href=\"#files\">Files\u003C\u002Fa>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Every field but \u003Ccode>email\u003C\u002Fcode> and \u003Ccode>name\u003C\u002Fcode> has a \u003Ccode>key\u003C\u002Fcode>: the \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FCONTACTS.md#fields\" target=\"_blank\" rel=\"noopener\">contact attribute\u003C\u002Fa>\nits answer is saved in (letters, digits and \u003Ccode>_\u003C\u002Fcode>, starting with a letter). Two\nforms that ask the same thing should use the same key. A form never overwrites\nan answer a contact already has (anyone can type someone else's address into a\nform), so the first answer stays; change it in the panel or with the contacts API.\u003C\u002Fp>\n\u003Ch3 id=\"words-and-look\">Words and look\u003Ca class=\"heading-anchor\" href=\"#words-and-look\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>\u003Ccode>content\u003C\u002Fcode>: the \u003Ccode>title\u003C\u002Fcode>, \u003Ccode>description\u003C\u002Fcode>, \u003Ccode>buttonLabel\u003C\u002Fcode>, the \u003Ccode>successTitle\u003C\u002Fcode> and\n\u003Ccode>successMessage\u003C\u002Fcode> shown afterwards, the \u003Ccode>confirmMessage\u003C\u002Fcode> shown instead while\nsomeone still has to confirm their address, and an optional \u003Ccode>footnote\u003C\u002Fcode> (a privacy\nline). \u003Ccode>style\u003C\u002Fcode>: \u003Ccode>accent\u003C\u002Fcode>, \u003Ccode>background\u003C\u002Fcode> and \u003Ccode>text\u003C\u002Fcode> colours (empty: the project's\naccent; no background, so the form sits on your page; text that follows your\npage's light or dark), \u003Ccode>radius\u003C\u002Fcode>, \u003Ccode>font\u003C\u002Fcode> (\u003Ccode>system\u003C\u002Fcode>, \u003Ccode>rounded\u003C\u002Fcode>, \u003Ccode>serif\u003C\u002Fcode>, \u003Ccode>mono\u003C\u002Fcode>) and \u003Ccode>layout\u003C\u002Fcode>:\n\u003Ccode>stacked\u003C\u002Fcode>, or \u003Ccode>inline\u003C\u002Fcode> for the inputs and the button on one row.\u003C\u002Fp>\n\u003Ch3 id=\"files\">Files\u003Ca class=\"heading-anchor\" href=\"#files\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>A \u003Ccode>file\u003C\u002Fcode> field takes one file: \u003Ccode>accept\u003C\u002Fcode> says which kind (\u003Ccode>images\u003C\u002Fcode>: PNG, JPEG,\nGIF or WebP; \u003Ccode>documents\u003C\u002Fcode>: PDF, Word, Excel, PowerPoint, OpenDocument, RTF, text,\nCSV or Markdown; \u003Ccode>any\u003C\u002Fcode>: either, or a ZIP archive) and \u003Ccode>maxMB\u003C\u002Fcode> how large (1 to 20,\n10 by default). Files are checked by what they really are, not by their name, so\na renamed program is refused.\u003C\u002Fp>\n\u003Cp>Files are kept privately for your team: they are not attributes and have no\npublic link. You see them on the contact (\u003Cstrong>Files sent\u003C\u002Fstrong>) and on the form, and\ndownload them with your session or an admin key. Their bytes count towards the\nworkspace's storage; when it is full the form answers \u003Ccode>402\u003C\u002Fcode> to anyone who sends\na file. Erasing a contact deletes their files; deleting a form keeps them with\nthe contact. File fields need the server's S3 storage (\u003Ccode>S3_ENDPOINT\u003C\u002Fcode>,\n\u003Ccode>S3_ACCESS_KEY\u003C\u002Fcode>, \u003Ccode>S3_SECRET_KEY\u003C\u002Fcode>, \u003Ccode>S3_BUCKET\u003C\u002Fcode>); without it a form cannot have one.\u003C\u002Fp>\n\u003Ch3 id=\"languages\">Languages\u003Ca class=\"heading-anchor\" href=\"#languages\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>A form is written in one language (\u003Ccode>locale\u003C\u002Fcode>, \u003Ccode>en\u003C\u002Fcode> by default) and can carry a\ntranslation per language (up to 20): its words, and each field's label,\nplaceholder and options. Write them in the panel's language bar, or have the AI\nfill them in (it keeps what you already translated unless you overwrite). A word\na translation leaves out shows in the form's own language.\u003C\u002Fp>\n\u003Cp>Visitors get the language they ask for when the form has it, else the form's\nown: the script sends your page's \u003Ccode>&lt;html lang&gt;\u003C\u002Fcode> (or \u003Ccode>data-locale\u003C\u002Fcode>), the hosted\npage and the read API take \u003Ccode>?locale=\u003C\u002Fcode> and the browser's \u003Ccode>Accept-Language\u003C\u002Fcode>, and\nthe Swift snippet sends the device's language. That language follows them:\nerrors, the hosted page, the confirmation page and email, and the welcome email\n(when its template has a translation for it). A choice keeps its original\noptions as the values it saves, whatever language it was shown in.\u003C\u002Fp>\n\u003Cp>The words HelpBites writes itself (errors, &quot;(optional)&quot;, the confirmation page\nand the built-in confirmation email) come in English, Spanish, Catalan, French,\nGerman, Italian, Portuguese, Japanese, Korean and Chinese; other languages get\nEnglish.\u003C\u002Fp>\n\u003Ch2 id=\"what-happens-when-someone-signs-up\">What happens when someone signs up\u003Ca class=\"heading-anchor\" href=\"#what-happens-when-someone-signs-up\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>They become a contact\u003C\u002Fstrong>, matched by email like every other write\n(\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FCONTACTS.md#one-person-one-contact\" target=\"_blank\" rel=\"noopener\">one person, one contact\u003C\u002Fa>). Someone new\nremembers how they got here: \u003Ccode>origin: { type: 'lead_form', id: &lt;form id&gt; }\u003C\u002Fcode>,\nshown as \u003Cstrong>Added via\u003C\u002Fstrong> in the people list. People who were already contacts\nkeep their origin. The first language of their browser fills the contact's\n\u003Ccode>language\u003C\u002Fcode> when it is empty, so the welcome email can come in it.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>They join the form's segment.\u003C\u002Fstrong> The form's id is added to the contact's\n\u003Ccode>leadForms\u003C\u002Fcode>. Creating a form makes a segment \u003Cstrong>Leads · &lt;form name&gt;\u003C\u002Fstrong>\n(\u003Ccode>leadForms includes &lt;id&gt;\u003C\u002Fcode>), and the project's first form also makes\n\u003Cstrong>All leads\u003C\u002Fstrong> (\u003Ccode>leadForms is set\u003C\u002Fcode>). They are ordinary segments, marked \u003Cem>Auto\u003C\u002Fem>:\nrename, edit or delete them; deleting a form keeps its segment and its leads.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>They get the form's tags.\u003C\u002Fstrong>\u003C\u002Fli>\n\u003Cli>\u003Cstrong>They confirm their address\u003C\u002Fstrong> when the form asks for it (\u003Ccode>doubleOptIn\u003C\u002Fcode>, on by\ndefault): they are \u003Ccode>pending\u003C\u002Fcode> until they press the button behind the link in\nthe confirmation email, valid for seven days. The email is the template you\npick (it must have a \u003Ccode>{{confirmUrl}}\u003C\u002Fcode> button), else the project's\n\u003Ccode>confirm-subscription\u003C\u002Fcode> template, else HelpBites' own. That click, with when\nand from where, is their recorded consent.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Once they are on the list\u003C\u002Fstrong> (subscribed: confirmed, or right away without\ndouble opt-in), the \u003Cstrong>welcome email\u003C\u002Fstrong> goes out (any of the project's\ntemplates; it is sent once per form and person, with their answers as\nplaceholders such as \u003Ccode>{{firstName}}\u003C\u002Fcode> or \u003Ccode>{{company}}\u003C\u002Fcode>, and \u003Ccode>{{unsubscribeUrl}}\u003C\u002Fcode>;\nin the person's language when the template has a\n\u003Ca href=\"\u002Fdocs\u002Flanguages#a-contacts-language\">translation\u003C\u002Fa> of it)\nand they start the form's \u003Cstrong>sequence\u003C\u002Fstrong>. A draft or paused sequence holds them at\nthe first step until you activate it.\u003C\u002Fli>\n\u003Cli>The \u003Cstrong>redirect URL\u003C\u002Fstrong> is where a plain HTML form, the hosted page and the\nconfirmation link send people afterwards; without one they see the form's\nthank-you words on a HelpBites page.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>The consent rules are the newsletter sign-up's\n(\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FMARKETING.md#sign-up-form-and-double-opt-in\" target=\"_blank\" rel=\"noopener\">MARKETING.md\u003C\u002Fa>): a subscriber stays\nas they are, and someone who unsubscribed only comes back through the\nconfirmation email, double opt-in or not. After the answers check out, the\nanswer is the same whether or not the address was already known.\u003C\u002Fp>\n\u003Cp>Welcome emails count as marketing: they carry \u003Ccode>List-Unsubscribe\u003C\u002Fcode>, show in the\nemail log with source \u003Cstrong>Lead form\u003C\u002Fstrong> and batch id \u003Ccode>lf_&lt;form&gt;_&lt;contact&gt;\u003C\u002Fcode>, and count\ntowards your plan's email. Confirmation emails are sent by HelpBites itself.\u003C\u002Fp>\n\u003Ch2 id=\"plug-and-play-web\">Plug and play: web\u003Ca class=\"heading-anchor\" href=\"#plug-and-play-web\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>One script tag. It draws the form where you put it:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-html\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">src\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fforms.js\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-project\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"pk_…\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-form\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">defer\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Without \u003Ccode>data-form\u003C\u002Fcode> it draws the project's first form, so \u003Ccode>data-project\u003C\u002Fcode> alone\nworks. It is MIT-licensed, has no dependencies, and draws the form from JSON in a\nshadow root (your CSS and its CSS never collide). It posts the answers itself and\nshows the thank-you words; a form with double opt-in shows its \u003Ccode>confirmMessage\u003C\u002Fcode>.\nA form with a file field sends its answers as \u003Ccode>multipart\u002Fform-data\u003C\u002Fcode>, checks each\nfile's size before sending and shows how large a file may be.\u003C\u002Fp>\n\u003Ch3 id=\"options\">Options\u003Ca class=\"heading-anchor\" href=\"#options\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Set them as \u003Ccode>data-*\u003C\u002Fcode> attributes or in \u003Ccode>init\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Option\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>form\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The form's key. Default: the project's first form.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>target\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A selector. Draws the form in that element instead of after the script tag.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>theme\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>light\u003C\u002Fcode>, \u003Ccode>dark\u003C\u002Fcode> or \u003Ccode>system\u003C\u002Fcode> (the visitor's setting). Defaults to a \u003Ccode>dark\u003C\u002Fcode> or \u003Ccode>light\u003C\u002Fcode> class on your \u003Ccode>&lt;html&gt;\u003C\u002Fcode>, then the colour behind the form, so it reads on your page whatever the visitor's setting. A form with a background colour of its own picks its text from that.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>accent\u003C\u002Fcode>, \u003Ccode>radius\u003C\u002Fcode>, \u003Ccode>font\u003C\u002Fcode>, \u003Ccode>layout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Override the form's look.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>show\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The parts to show besides the inputs: \u003Ccode>title,description,footnote\u003C\u002Fcode> (default), any of them plus \u003Ccode>logo\u003C\u002Fcode>, or \u003Ccode>none\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>locale\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The language to show it in, when the form has a translation for it. Default: your \u003Ccode>&lt;html lang&gt;\u003C\u002Fcode>, then the visitor's browser.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Where HelpBites is, when you serve \u003Ccode>forms.js\u003C\u002Fcode> from your own site.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-html\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">div\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">id\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">div\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n  window\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-class\">HelpBitesForms\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan> window\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-class\">HelpBitesForms\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">||\u003C\u002Fspan> []\n  \u003Cspan class=\"shj-syn-class\">HelpBitesForms\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">push\u003C\u002Fspan>([\u003Cspan class=\"shj-syn-str\">'init'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> {\n    labels\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> { title\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'Get early access'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> button\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'Count me in'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> successTitle\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'You are in!'\u003C\u002Fspan> }\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan>\n    values\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> { plan\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'pro'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> referrer\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> document\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>referrer }\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan>   \u003Cspan class=\"shj-syn-cmnt\">\u002F\u002F answers you add yourself, by key\n\u003C\u002Fspan>    onSuccess\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> ({ form\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> pending }) \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> analytics\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">track\u003C\u002Fspan>(\u003Cspan class=\"shj-syn-str\">'waitlist_joined'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> { form\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> pending })\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan>\n    onError\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> (message) \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> {}\n  }])\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">src\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fforms.js\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-project\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"pk_…\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-form\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-target\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"#waitlist\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-layout\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"inline\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">defer\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>labels\u003C\u002Fcode> takes \u003Ccode>title\u003C\u002Fcode>, \u003Ccode>description\u003C\u002Fcode>, \u003Ccode>button\u003C\u002Fcode>, \u003Ccode>successTitle\u003C\u002Fcode>,\n\u003Ccode>successMessage\u003C\u002Fcode>, \u003Ccode>confirmMessage\u003C\u002Fcode> and \u003Ccode>footnote\u003C\u002Fcode>. \u003Ccode>values\u003C\u002Fcode> fills in answers for\nfields the visitor does not see; only keys the form has are saved. More forms on\none page: another script tag, or \u003Ccode>HelpBitesForms.push(['render', { form: 'beta', target: '#beta' }])\u003C\u002Fcode>.\nEvery outcome is also a \u003Ccode>helpbites:form\u003C\u002Fcode> event on \u003Ccode>window\u003C\u002Fcode>, with \u003Ccode>detail.type\u003C\u002Fcode>\nset to \u003Ccode>submit\u003C\u002Fcode>, \u003Ccode>success\u003C\u002Fcode> (and \u003Ccode>detail.pending\u003C\u002Fcode>) or \u003Ccode>error\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch3 id=\"restyle-it\">Restyle it\u003Ca class=\"heading-anchor\" href=\"#restyle-it\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Set these variables on \u003Ccode>.help-bites-form\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-css\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">.help-bites-form\u003C\u002Fspan> {\n  --\u003Cspan class=\"shj-syn-var\">hb-form-accent\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">#0ea5e9\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-on-accent\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">#fff\u003C\u002Fspan>;      \u003Cspan class=\"shj-syn-cmnt\">\u002F* text on the button *\u002F\u003C\u002Fspan>\n  --\u003Cspan class=\"shj-syn-var\">hb-form-bg\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">transparent\u003C\u002Fspan>;      \u003Cspan class=\"shj-syn-cmnt\">\u002F* a colour makes it a card *\u002F\u003C\u002Fspan>\n  --\u003Cspan class=\"shj-syn-var\">hb-form-text\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">#0f172a\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-muted\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">#64748b\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-border\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">#e2e8f0\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-input-bg\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">#fff\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-radius\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">10\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-syn-num\">\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-font\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Inter\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-num\">sans-serif\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-gap\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">10\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-syn-num\">\u003C\u002Fspan>;\n  --\u003Cspan class=\"shj-syn-var\">hb-form-max-width\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">440\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-syn-num\">\u003C\u002Fspan>;\n}\n\u003Cspan class=\"shj-syn-var\">.help-bites-form\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">::part\u003C\u002Fspan>(\u003Cspan class=\"shj-syn-kwd\">button\u003C\u002Fspan>) { \u003Cspan class=\"shj-syn-var\">text-transform\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">uppercase\u003C\u002Fspan>; \u003Cspan class=\"shj-syn-var\">letter-spacing\u003C\u002Fspan>: .\u003Cspan class=\"shj-syn-num\">04\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">em\u003C\u002Fspan>\u003Cspan class=\"shj-syn-num\">\u003C\u002Fspan>; }\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Parts you can style: \u003Ccode>form\u003C\u002Fcode>, \u003Ccode>title\u003C\u002Fcode>, \u003Ccode>description\u003C\u002Fcode>, \u003Ccode>logo\u003C\u002Fcode>, \u003Ccode>fields\u003C\u002Fcode>, \u003Ccode>field\u003C\u002Fcode>,\n\u003Ccode>label\u003C\u002Fcode>, \u003Ccode>input\u003C\u002Fcode>, \u003Ccode>hint\u003C\u002Fcode>, \u003Ccode>button\u003C\u002Fcode>, \u003Ccode>footnote\u003C\u002Fcode>, \u003Ccode>success\u003C\u002Fcode> and \u003Ccode>error\u003C\u002Fcode>. The layout\nis HelpBites'.\u003C\u002Fp>\n\u003Ch2 id=\"a-plain-html-form\">A plain HTML form\u003Ca class=\"heading-anchor\" href=\"#a-plain-html-form\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>No script at all: the form posts to HelpBites and the browser comes back to your\nredirect URL (or the form's thank-you page). Each field's answer goes under its\nkey; the panel's \u003Cstrong>HTML\u003C\u002Fstrong> tab writes this for your form:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-html\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">form\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">action\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fv1\u002Fforms\u002Fpk_…\u002Fwaitlist\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">method\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"post\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">input\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">type\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">name\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">placeholder\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"you@example.com\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">required\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">input\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">type\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"text\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">name\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"name\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">placeholder\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"Your name\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-cmnt\">&lt;!-- Leave this empty: bots fill it in. --&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">input\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">type\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"text\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">name\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"website\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">tabindex\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"-1\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">autocomplete\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"off\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">aria-hidden\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"true\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">style\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"position:absolute;left:-10000px\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">button\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">type\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"submit\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>Join the waitlist\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">button\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">form\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>A wrong answer comes back as the hosted page with the problem and what was typed.\nA form with a file field needs \u003Ccode>enctype=&quot;multipart\u002Fform-data&quot;\u003C\u002Fcode> and an\n\u003Ccode>&lt;input type=&quot;file&quot; name=&quot;&lt;key&gt;&quot;&gt;\u003C\u002Fcode>; the HTML tab writes both. Add\n\u003Ccode>&lt;input type=&quot;hidden&quot; name=&quot;locale&quot; value=&quot;es&quot;&gt;\u003C\u002Fcode> for errors and emails in that\nlanguage.\u003C\u002Fp>\n\u003Ch2 id=\"a-hosted-page\">A hosted page\u003Ca class=\"heading-anchor\" href=\"#a-hosted-page\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>https:\u002F\u002FYOUR-SUPPORT-HOST\u002Ff\u002F&lt;public key&gt;\u002F&lt;form key&gt;\u003C\u002Fcode>: link to it from a tweet, a\nQR code or an app, or frame it:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-html\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">iframe\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">src\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Ff\u002Fpk_…\u002Fwaitlist\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">title\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"Join the waitlist\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">style\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"width:100%;max-width:480px;height:520px;border:0\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">iframe\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>It is plain HTML with no JavaScript, in the form's words and accent. Add\n\u003Ccode>?locale=es\u003C\u002Fcode> for a language of the form's (else the browser's is used).\u003C\u002Fp>\n\u003Ch2 id=\"plug-and-play-swift\">Plug and play: Swift\u003Ca class=\"heading-anchor\" href=\"#plug-and-play-swift\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Paste this file into your app. It needs no package: plain \u003Ccode>URLSession\u003C\u002Fcode> against\nthe public API.\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-plain\">\u003Ccode>\u002F\u002F HelpBitesLeadForm.swift. MIT. A HelpBites lead form in SwiftUI. iOS 17, macOS 14.\nimport SwiftUI\nimport UniformTypeIdentifiers\n\nstruct HelpBitesLeadFormData: Decodable, Equatable {\n  struct Field: Decodable, Identifiable, Equatable {\n    let id, key, type, label, placeholder: String\n    let required: Bool\n    \u002F\u002F\u002F The values a choice sends; `optionLabels` say what they show in this language.\n    let options: [String]\n    let optionLabels: [String]?\n    \u002F\u002F\u002F `file` fields: images, documents or any, and the largest file in MB.\n    let accept: String?\n    let maxMB: Int?\n  }\n  struct Content: Decodable, Equatable { let title, description, buttonLabel, successTitle, successMessage, confirmMessage, footnote: String }\n  struct Style: Decodable, Equatable { let accent: String; let radius: Double }\n  let key: String\n  \u002F\u002F\u002F The language of these words.\n  let locale: String?\n  let fields: [Field]\n  let content: Content\n  let style: Style\n  let doubleOptIn: Bool\n}\n\nstruct HelpBitesLeadForm: View {\n  let host: URL\n  let projectKey: String\n  \u002F\u002F\u002F The form's key; empty draws the project's first form.\n  var form = \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>\n  \u002F\u002F\u002F The language to show it in, when the form has a translation for it.\n  var locale = Locale.preferredLanguages.first ?? \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>\n  var accent: Color?\n  var cornerRadius: CGFloat?\n  var design: Font.Design = .default\n  \u002F\u002F\u002F Answers you add yourself (a plan, a referrer), by key.\n  var values: [String: String] = [:]\n  \u002F\u002F\u002F `true` when they still have to confirm their email.\n  var onSuccess: (Bool) -&gt; Void = { _ in }\n\n  @State private var data: HelpBitesLeadFormData?\n  @State private var text: [String: String] = [:]\n  @State private var ticked: [String: Bool] = [:]\n  @State private var files: [String: (name: String, data: Data)] = [:]\n  \u002F\u002F\u002F The file field being picked.\n  @State private var picking: String?\n  @State private var sending = false\n  @State private var error = \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>\n  @State private var pending: Bool?\n\n  var body: some View {\n    Group {\n      if let data, let pending { done(data, pending) }\n      else if let data { fields(data) }\n      else { ProgressView().frame(maxWidth: .infinity) }\n    }\n    .fontDesign(design)\n    .task { await load() }\n  }\n\n  private var url: URL {\n    let url = host.appending(path: form.isEmpty ? \u003Cspan class=\"shj-syn-str\">\"v1\u002Fforms\u002F\\(projectKey)\"\u003C\u002Fspan> : \u003Cspan class=\"shj-syn-str\">\"v1\u002Fforms\u002F\\(projectKey)\u002F\\(form)\"\u003C\u002Fspan>)\n    return locale.isEmpty ? url : url.appending(queryItems: [URLQueryItem(name: \u003Cspan class=\"shj-syn-str\">\"locale\"\u003C\u002Fspan>, value: locale)])\n  }\n  #if os(iOS)\n  private static let keyboards: [String: UIKeyboardType] = [\u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan>: .emailAddress, \u003Cspan class=\"shj-syn-str\">\"number\"\u003C\u002Fspan>: .decimalPad, \u003Cspan class=\"shj-syn-str\">\"url\"\u003C\u002Fspan>: .URL, \u003Cspan class=\"shj-syn-str\">\"phone\"\u003C\u002Fspan>: .phonePad]\n  #endif\n\n  private func fields(_ data: HelpBitesLeadFormData) -&gt; some View {\n    let tint = accent ?? Color(helpBitesHex: data.style.accent) ?? .accentColor\n    let radius = cornerRadius ?? data.style.radius\n    return VStack(alignment: .leading, spacing: 12) {\n      if !data.content.title.isEmpty { Text(data.content.title).font(.title2.weight(.semibold)) }\n      if !data.content.description.isEmpty { Text(data.content.description).foregroundStyle(.secondary) }\n      ForEach(data.fields) { field in\n        switch field.type {\n        case \u003Cspan class=\"shj-syn-str\">\"checkbox\"\u003C\u002Fspan>: Toggle(field.label, isOn: binding(ticked, field.key, false)).tint(tint)\n        case \u003Cspan class=\"shj-syn-str\">\"select\"\u003C\u002Fspan>:\n          Picker(field.label, selection: binding(text, field.key, \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>)) {\n            Text(\u003Cspan class=\"shj-syn-str\">\"—\"\u003C\u002Fspan>).tag(\u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>)\n            ForEach(Array(field.options.enumerated()), id: \\.offset) { i, option in Text(field.optionLabels?[i] ?? option).tag(option) }\n          }\n        case \u003Cspan class=\"shj-syn-str\">\"file\"\u003C\u002Fspan>:\n          Button { picking = field.key } label: {\n            Label(files[field.key]?.name ?? field.label, systemImage: files[field.key] == nil ? \u003Cspan class=\"shj-syn-str\">\"paperclip\"\u003C\u002Fspan> : \u003Cspan class=\"shj-syn-str\">\"checkmark.circle\"\u003C\u002Fspan>)\n              .lineLimit(1).frame(maxWidth: .infinity, minHeight: 46, alignment: .leading).padding(.horizontal, 12)\n              .background(.quaternary.opacity(0.5), in: .rect(cornerRadius: radius * 0.75))\n          }\n          .buttonStyle(.plain)\n        default:\n          TextField(field.placeholder.isEmpty ? field.label : field.placeholder, text: binding(text, field.key, \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>), axis: field.type == \u003Cspan class=\"shj-syn-str\">\"textarea\"\u003C\u002Fspan> ? .vertical : .horizontal)\n            .lineLimit(field.type == \u003Cspan class=\"shj-syn-str\">\"textarea\"\u003C\u002Fspan> ? 3 ... 6 : 1 ... 1)\n            .padding(12)\n            .background(.quaternary.opacity(0.5), in: .rect(cornerRadius: radius * 0.75))\n            .autocorrectionDisabled(field.type != \u003Cspan class=\"shj-syn-str\">\"textarea\"\u003C\u002Fspan> &#38;&#38; field.type != \u003Cspan class=\"shj-syn-str\">\"text\"\u003C\u002Fspan>)\n            #if os(iOS)\n            .keyboardType(Self.keyboards[field.type] ?? .default)\n            .textInputAutocapitalization([\u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"url\"\u003C\u002Fspan>].contains(field.type) ? .never : .sentences)\n            #endif\n            .accessibilityLabel(field.label)\n        }\n      }\n      if !error.isEmpty { Text(error).font(.footnote).foregroundStyle(.red) }\n      Button { Task { await send(data) } } label: {\n        Text(data.content.buttonLabel).fontWeight(.semibold).frame(maxWidth: .infinity, minHeight: 46)\n          .background(tint, in: .rect(cornerRadius: radius * 0.75)).foregroundStyle(.white)\n      }\n      .buttonStyle(.plain)\n      .disabled(sending || data.fields.contains { $0.required &#38;&#38; missing($0) })\n      if !data.content.footnote.isEmpty { Text(data.content.footnote).font(.footnote).foregroundStyle(.secondary) }\n    }\n    .fileImporter(isPresented: Binding(get: { picking != nil }, set: { if !$0 { picking = nil } }), allowedContentTypes: types(data.fields.first { $0.key == picking })) { result in\n      if let key = picking, let file = try? result.get() { pick(file, key, data) }\n    }\n  }\n\n  private func done(_ data: HelpBitesLeadFormData, _ pending: Bool) -&gt; some View {\n    VStack(alignment: .leading, spacing: 6) {\n      Label(data.content.successTitle, systemImage: \u003Cspan class=\"shj-syn-str\">\"checkmark.circle.fill\"\u003C\u002Fspan>).font(.headline)\n      Text(pending ? data.content.confirmMessage : data.content.successMessage).foregroundStyle(.secondary)\n    }\n  }\n\n  private func missing(_ field: HelpBitesLeadFormData.Field) -&gt; Bool {\n    switch field.type {\n    case \u003Cspan class=\"shj-syn-str\">\"checkbox\"\u003C\u002Fspan>: ticked[field.key] != true\n    case \u003Cspan class=\"shj-syn-str\">\"file\"\u003C\u002Fspan>: files[field.key] == nil\n    default: (text[field.key] ?? \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>).isEmpty\n    }\n  }\n\n  private func binding&lt;T&gt;(_ store: [String: T], _ key: String, _ empty: T) -&gt; Binding&lt;T&gt; {\n    Binding(get: { store[key] ?? empty }, set: { value in\n      if let value = value as? String { text[key] = value } else if let value = value as? Bool { ticked[key] = value }\n    })\n  }\n\n  \u002F\u002F\u002F What the picker offers; the server checks what each file really is.\n  private func types(_ field: HelpBitesLeadFormData.Field?) -&gt; [UTType] {\n    switch field?.accept {\n    case \u003Cspan class=\"shj-syn-str\">\"images\"\u003C\u002Fspan>: [.image]\n    case \u003Cspan class=\"shj-syn-str\">\"documents\"\u003C\u002Fspan>: [.pdf, .text, .rtf, .spreadsheet, .presentation] + [\u003Cspan class=\"shj-syn-str\">\"doc\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"docx\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"odt\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"md\"\u003C\u002Fspan>].compactMap { UTType(filenameExtension: $0) }\n    default: [.item]\n    }\n  }\n\n  private func pick(_ url: URL, _ key: String, _ data: HelpBitesLeadFormData) {\n    let scoped = url.startAccessingSecurityScopedResource()\n    defer { if scoped { url.stopAccessingSecurityScopedResource() } }\n    guard let bytes = try? Data(contentsOf: url) else { return }\n    let limit = data.fields.first { $0.key == key }?.maxMB ?? 10\n    if bytes.count &gt; limit * 1024 * 1024 { error = \u003Cspan class=\"shj-syn-str\">\"That file is larger than \\(limit) MB.\"\u003C\u002Fspan>; return }\n    files[key] = (url.lastPathComponent, bytes)\n    error = \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>\n  }\n\n  private func load() async {\n    struct Envelope: Decodable { let form: HelpBitesLeadFormData }\n    guard let answer = try? await URLSession.shared.data(from: url), (answer.1 as? HTTPURLResponse)?.statusCode == 200 else { return }\n    data = try? JSONDecoder().decode(Envelope.self, from: answer.0).form\n  }\n\n  private func send(_ data: HelpBitesLeadFormData) async {\n    sending = true\n    defer { sending = false }\n    var answers: [String: Any] = values\n    for (key, value) in text { answers[key] = value.trimmingCharacters(in: .whitespacesAndNewlines) }\n    for (key, value) in ticked { answers[key] = value }\n    \u002F\u002F Errors and emails come in the language the form was shown in.\n    if let locale = data.locale { answers[\u003Cspan class=\"shj-syn-str\">\"locale\"\u003C\u002Fspan>] = locale }\n    var request = URLRequest(url: host.appending(path: \u003Cspan class=\"shj-syn-str\">\"v1\u002Fforms\u002F\\(projectKey)\u002F\\(data.key)\"\u003C\u002Fspan>))\n    request.httpMethod = \u003Cspan class=\"shj-syn-str\">\"POST\"\u003C\u002Fspan>\n    if files.isEmpty {\n      request.setValue(\u003Cspan class=\"shj-syn-str\">\"application\u002Fjson\"\u003C\u002Fspan>, forHTTPHeaderField: \u003Cspan class=\"shj-syn-str\">\"Content-Type\"\u003C\u002Fspan>)\n      request.httpBody = try? JSONSerialization.data(withJSONObject: answers)\n    } else {\n      \u002F\u002F With a file it is multipart: each answer a text part, each file a part named by its field's key.\n      let boundary = \u003Cspan class=\"shj-syn-str\">\"hb-\\(UUID().uuidString)\"\u003C\u002Fspan>\n      var body = Data()\n      func part(_ name: String, _ filename: String?, _ bytes: Data) {\n        body.append(Data(\u003Cspan class=\"shj-syn-str\">\"--\\(boundary)\\r\\nContent-Disposition: form-data; name=\\\"\\(name)\\\"\\(filename.map { \"\u003C\u002Fspan>; filename=\\\u003Cspan class=\"shj-syn-str\">\"\\($0)\\\"\"\u003C\u002Fspan> } ?? \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>)\\r\\n\\r\\n\u003Cspan class=\"shj-syn-str\">\".utf8))\u003C\u002Fspan>\n        body.append(bytes)\n        body.append(Data(\u003Cspan class=\"shj-syn-str\">\"\\r\\n\"\u003C\u002Fspan>.utf8))\n      }\n      for (key, value) in answers { part(key, nil, Data(((value as? Bool).map { $0 ? \u003Cspan class=\"shj-syn-str\">\"true\"\u003C\u002Fspan> : \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan> } ?? \u003Cspan class=\"shj-syn-str\">\"\\(value)\"\u003C\u002Fspan>).utf8)) }\n      for (key, file) in files { part(key, file.name.replacingOccurrences(of: \u003Cspan class=\"shj-syn-str\">\"\\\"\"\u003C\u002Fspan>, with: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>), file.data) }\n      body.append(Data(\u003Cspan class=\"shj-syn-str\">\"--\\(boundary)--\\r\\n\"\u003C\u002Fspan>.utf8))\n      request.setValue(\u003Cspan class=\"shj-syn-str\">\"multipart\u002Fform-data; boundary=\\(boundary)\"\u003C\u002Fspan>, forHTTPHeaderField: \u003Cspan class=\"shj-syn-str\">\"Content-Type\"\u003C\u002Fspan>)\n      request.httpBody = body\n    }\n    guard let answer = try? await URLSession.shared.data(for: request) else { error = \u003Cspan class=\"shj-syn-str\">\"Could not reach the server.\"\u003C\u002Fspan>; return }\n    let json = (try? JSONSerialization.jsonObject(with: answer.0)) as? [String: Any] ?? [:]\n    if (200 ..&lt; 300).contains((answer.1 as? HTTPURLResponse)?.statusCode ?? 0) {\n      let waiting = json[\u003Cspan class=\"shj-syn-str\">\"pending\"\u003C\u002Fspan>] as? Bool ?? false\n      pending = waiting\n      onSuccess(waiting)\n    } else {\n      error = json[\u003Cspan class=\"shj-syn-str\">\"message\"\u003C\u002Fspan>] as? String ?? \u003Cspan class=\"shj-syn-str\">\"Something went wrong. Please try again.\"\u003C\u002Fspan>\n    }\n  }\n}\n\nprivate extension Color {\n  init?(helpBitesHex hex: String) {\n    guard hex.count == 7, hex.hasPrefix(\u003Cspan class=\"shj-syn-str\">\"#\"\u003C\u002Fspan>), let v = Int(hex.dropFirst(), radix: 16) else { return nil }\n    self.init(red: Double(v &gt;&gt; 16 &#38; 255) \u002F 255, green: Double(v &gt;&gt; 8 &#38; 255) \u002F 255, blue: Double(v &#38; 255) \u002F 255)\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Then, anywhere in your app:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-plain\">\u003Ccode>HelpBitesLeadForm(host: URL(string: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\"\u003C\u002Fspan>)!, projectKey: \u003Cspan class=\"shj-syn-str\">\"pk_…\"\u003C\u002Fspan>, form: \u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan>)\n  .padding()\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Cstrong>Customise it\u003C\u002Fstrong> with \u003Ccode>accent\u003C\u002Fcode>, \u003Ccode>cornerRadius\u003C\u002Fcode> and \u003Ccode>design\u003C\u002Fcode> (\u003Ccode>.rounded\u003C\u002Fcode>,\n\u003Ccode>.serif\u003C\u002Fcode>…), set \u003Ccode>locale\u003C\u002Fcode> for another language than the device's, pass \u003Ccode>values\u003C\u002Fcode>\nfor answers you know already (an app version, a plan), and use \u003Ccode>onSuccess\u003C\u002Fcode> to\nmove on. File fields open the system file picker and send the form as multipart. It is your file, so change anything: the layout,\nthe error words, how a field looks. The button text and the thank-you words come\nfrom the form, so you change them in the panel without a release.\u003C\u002Fp>\n\u003Ch2 id=\"your-own-ui\">Your own UI\u003Ca class=\"heading-anchor\" href=\"#your-own-ui\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Read the form, then post the answers. Both are public, open to any origin, and\nneed only the project's public key:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-bash\">\u003Ccode>\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fv1\u002Fforms\u002FPROJECT_PUBLIC_KEY\u002Fwaitlist?locale=es'\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-json\">\u003Ccode>{\n  \u003Cspan class=\"shj-syn-var\">\"form\"\u003C\u002Fspan>: {\n    \u003Cspan class=\"shj-syn-var\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"name\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Launch waitlist\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"doubleOptIn\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-bool\">true\u003C\u002Fspan>,\n    \u003Cspan class=\"shj-syn-var\">\"locale\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"es\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"locales\"\u003C\u002Fspan>: [\u003Cspan class=\"shj-syn-str\">\"en\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"es\"\u003C\u002Fspan>],\n    \u003Cspan class=\"shj-syn-var\">\"project\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"name\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Acme\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"logoUrl\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002Fcdn.acme.test\u002Ficon.png\"\u003C\u002Fspan> },\n    \u003Cspan class=\"shj-syn-var\">\"fields\"\u003C\u002Fspan>: [\n      { \u003Cspan class=\"shj-syn-var\">\"id\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"fd_1\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"type\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"label\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Correo\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"placeholder\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"tu@ejemplo.com\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"required\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-bool\">true\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"options\"\u003C\u002Fspan>: [], \u003Cspan class=\"shj-syn-var\">\"optionLabels\"\u003C\u002Fspan>: [], \u003Cspan class=\"shj-syn-var\">\"accept\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"maxMB\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">0\u003C\u002Fspan> },\n      { \u003Cspan class=\"shj-syn-var\">\"id\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"fd_2\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"role\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"type\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"select\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"label\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Tu rol\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"placeholder\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"required\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-bool\">false\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"options\"\u003C\u002Fspan>: [\u003Cspan class=\"shj-syn-str\">\"Founder\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"Developer\"\u003C\u002Fspan>], \u003Cspan class=\"shj-syn-var\">\"optionLabels\"\u003C\u002Fspan>: [\u003Cspan class=\"shj-syn-str\">\"Fundador\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"Desarrollador\"\u003C\u002Fspan>], \u003Cspan class=\"shj-syn-var\">\"accept\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"maxMB\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">0\u003C\u002Fspan> },\n      { \u003Cspan class=\"shj-syn-var\">\"id\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"fd_3\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"cv\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"type\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"file\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"label\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Currículum\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"placeholder\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"required\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-bool\">false\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"options\"\u003C\u002Fspan>: [], \u003Cspan class=\"shj-syn-var\">\"optionLabels\"\u003C\u002Fspan>: [], \u003Cspan class=\"shj-syn-var\">\"accept\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"documents\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"maxMB\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">5\u003C\u002Fspan> }\n    ],\n    \u003Cspan class=\"shj-syn-var\">\"content\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"title\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Join the waitlist\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"description\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"…\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"buttonLabel\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Join the waitlist\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"successTitle\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"You are on the list\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"successMessage\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"…\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"confirmMessage\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"…\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"footnote\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan> },\n    \u003Cspan class=\"shj-syn-var\">\"style\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"accent\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"#0ea5e9\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"background\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"text\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"radius\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">12\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"font\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"system\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"layout\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"stacked\"\u003C\u002Fspan> }\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-bash\">\u003Ccode>\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fv1\u002Fforms\u002FPROJECT_PUBLIC_KEY\u002Fwaitlist \\\n \u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'content-type: application\u002Fjson'\u003C\u002Fspan> \\\n \u003Cspan class=\"shj-syn-kwd\"> -d\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'{\"email\":\"ada@example.com\",\"role\":\"Founder\",\"locale\":\"es\"}'\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-cmnt\"># 202 {\"ok\":true,\"pending\":true}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-syn-cmnt\"># With a file field: multipart, the file under its field's key\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fv1\u002Fforms\u002FPROJECT_PUBLIC_KEY\u002Fwaitlist \\\n \u003Cspan class=\"shj-syn-kwd\"> -F\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">email\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>ada@example.com\u003Cspan class=\"shj-syn-kwd\"> -F\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">role\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>Founder\u003Cspan class=\"shj-syn-kwd\"> -F\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">locale\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>es\u003Cspan class=\"shj-syn-kwd\"> -F\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">cv\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>@cv.pdf\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Send a choice's value from \u003Ccode>options\u003C\u002Fcode> (what \u003Ccode>optionLabels\u003C\u002Fcode> shows in that\nlanguage is understood too). \u003Ccode>locale\u003C\u002Fcode> (or \u003Ccode>Accept-Language\u003C\u002Fcode>) sets the language of\nerrors and emails.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>GET \u002Fv1\u002Fforms\u002F{pk}\u003C\u002Fcode> (no key) is the project's first active form.\u003C\u002Fli>\n\u003Cli>\u003Ccode>404\u003C\u002Fcode>: an unknown project or form, or one that is switched off.\u003C\u002Fli>\n\u003Cli>\u003Ccode>400\u003C\u002Fcode>: an answer or a file is missing or invalid; \u003Ccode>data.errors\u003C\u002Fcode> lists each one\n(\u003Ccode>message\u003C\u002Fcode> joins them), in the visitor's language.\u003C\u002Fli>\n\u003Cli>\u003Ccode>411\u003C\u002Fcode> \u002F \u003Ccode>413\u003C\u002Fcode>: a multipart body without a \u003Ccode>Content-Length\u003C\u002Fcode>, or one larger than\nthe form's file fields allow (their \u003Ccode>maxMB\u003C\u002Fcode> added up, plus 1 MB).\u003C\u002Fli>\n\u003Cli>\u003Ccode>pending: true\u003C\u002Fcode> means &quot;check your inbox&quot;: the form asks people to confirm.\u003C\u002Fli>\n\u003Cli>\u003Ccode>403\u003C\u002Fcode>: a browser on a site that is not in the project's \u003Cstrong>allowed origins\u003C\u002Fstrong>\n(when it has any). Server-to-server calls send no \u003Ccode>Origin\u003C\u002Fcode> and are fine.\u003C\u002Fli>\n\u003Cli>\u003Ccode>402\u003C\u002Fcode>: the workspace is at its plan's contact limit (or, for a submission with\na file, its storage limit); nobody can sign up until there is room again.\u003C\u002Fli>\n\u003Cli>\u003Ccode>429\u003C\u002Fcode>: too many sign-ups from one address (10 in ten minutes) or for the\nproject (300 an hour). Multipart posts are also limited to 20 in ten minutes per\naddress, counted before the files are read. Confirmation emails to one address are limited to three a\nday, together with the newsletter's.\u003C\u002Fli>\n\u003Cli>A filled-in \u003Ccode>website\u003C\u002Fcode> field is treated as a bot: the answer is the same, and\nnothing is saved.\u003C\u002Fli>\n\u003Cli>Reads are limited to 1,200 a minute per IP address, carry an \u003Ccode>ETag\u003C\u002Fcode> and may be\ncached for a minute.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"managing-forms-over-the-api\">Managing forms over the API\u003Ca class=\"heading-anchor\" href=\"#managing-forms-over-the-api\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Use an admin API key (\u003Cstrong>API keys\u003C\u002Fstrong>) or an operator session. Every route is\nscoped to your workspace; a key limited to some projects only reaches those.\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-bash\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">HOST\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>https:\u002F\u002FYOUR-SUPPORT-HOST\n\u003Cspan class=\"shj-syn-var\">KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>ak_...\n\n\u003Cspan class=\"shj-syn-cmnt\"># A waitlist that asks people to confirm, then welcomes them and starts a sequence\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u002Fv1\u002Fadmin\u002Flead-forms\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'content-type: application\u002Fjson'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -d\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-str\">\"project\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"PROJECT_ID\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"name\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Launch waitlist\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"preset\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan>,\n  \u003Cspan class=\"shj-syn-str\">\"settings\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"doubleOptIn\"\u003C\u002Fspan>: true, \u003Cspan class=\"shj-syn-str\">\"welcomeTemplate\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"waitlist-welcome\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"sequence\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"SEQUENCE_ID\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"tags\"\u003C\u002Fspan>: [\u003Cspan class=\"shj-syn-str\">\"waitlist\"\u003C\u002Fspan>] \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">'\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-syn-cmnt\"># Ask one more thing, and put the button on the same row\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -X\u003C\u002Fspan> PATCH \u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u002Fv1\u002Fadmin\u002Flead-forms\u002FFORM_ID\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'content-type: application\u002Fjson'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -d\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-str\">\"fields\"\u003C\u002Fspan>: [\n    \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"type\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"email\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"placeholder\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"you@example.com\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>,\n    \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"type\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"select\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"platform\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"label\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Your phone\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"options\"\u003C\u002Fspan>: [\u003Cspan class=\"shj-syn-str\">\"iPhone\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"Android\"\u003C\u002Fspan>], \u003Cspan class=\"shj-syn-str\">\"required\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-bool\">true\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\n  ],\n  \u003Cspan class=\"shj-syn-str\">\"style\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"layout\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"inline\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">'\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-syn-cmnt\"># Everyone who came through it, newest first (contacts API; the project secret works too)\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u002Fv1\u002Fcontacts?project=PROJECT_ID&#38;leadForm=FORM_ID\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-syn-cmnt\"># Spanish and French, translated by AI, then a Spanish word of your own\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u002Fv1\u002Fadmin\u002Flead-forms\u002FFORM_ID\u002Ftranslate\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'content-type: application\u002Fjson'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -d\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'{ \"locales\": [\"es\", \"fr\"] }'\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -X\u003C\u002Fspan> PATCH \u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u002Fv1\u002Fadmin\u002Flead-forms\u002FFORM_ID\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'content-type: application\u002Fjson'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -d\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-str\">\"translations\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"es\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"content\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-oper\">{\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"title\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Únete a la lista\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-str\">\"fields\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-oper\">{}\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-oper\">}\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">'\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-syn-cmnt\"># The files sent through it, and one of them\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u002Fv1\u002Fadmin\u002Flead-files?project=PROJECT_ID&#38;form=FORM_ID\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -s\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -OJ\u003C\u002Fspan> \u003Cspan class=\"shj-syn-var\">$HOST\u003C\u002Fspan>\u002Fv1\u002Fadmin\u002Flead-files\u002FFILE_ID\u002Fdownload\u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Route\u003C\u002Fth>\n\u003Cth>What it does\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fv1\u002Fadmin\u002Flead-forms?project=\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Every form, with \u003Ccode>stats\u003C\u002Fcode> (\u003Ccode>leads\u003C\u002Fcode>, and \u003Ccode>confirmed\u003C\u002Fcode>: how many are subscribed), \u003Ccode>path\u003C\u002Fcode> and \u003Ccode>pagePath\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>POST \u002Fv1\u002Fadmin\u002Flead-forms\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Create one, live at once. \u003Ccode>preset\u003C\u002Fcode>: \u003Ccode>email\u003C\u002Fcode> (default), \u003Ccode>waitlist\u003C\u002Fcode> or \u003Ccode>detailed\u003C\u002Fcode>; \u003Ccode>key\u003C\u002Fcode> must be unused (\u003Ccode>409\u003C\u002Fcode>). Makes its segment.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fv1\u002Fadmin\u002Flead-forms\u002F{id}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>One form.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PATCH \u002Fv1\u002Fadmin\u002Flead-forms\u002F{id}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Change \u003Ccode>name\u003C\u002Fcode>, \u003Ccode>key\u003C\u002Fcode>, \u003Ccode>active\u003C\u002Fcode>, \u003Ccode>fields\u003C\u002Fcode> (the full list), \u003Ccode>content\u003C\u002Fcode>, \u003Ccode>style\u003C\u002Fcode>, \u003Ccode>settings\u003C\u002Fcode> (merged), \u003Ccode>locale\u003C\u002Fcode> or \u003Ccode>translations\u003C\u002Fcode> (by language; \u003Ccode>null\u003C\u002Fcode> removes one). Templates and the sequence must exist; the confirmation template must use \u003Ccode>{{confirmUrl}}\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>POST \u002Fv1\u002Fadmin\u002Flead-forms\u002F{id}\u002Ftranslate\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>AI-translate its words into \u003Ccode>locales\u003C\u002Fcode> (up to 8 at once); \u003Ccode>overwrite: true\u003C\u002Fcode> replaces words already translated. \u003Ccode>501\u003C\u002Fcode> without an AI provider.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>DELETE \u002Fv1\u002Fadmin\u002Flead-forms\u002F{id}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Delete it. Its leads, their files and its segment stay.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fv1\u002Fadmin\u002Flead-files?project=&amp;contact=\u003C\u002Fcode> or \u003Ccode>&amp;form=\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Files sent through file fields, newest first (\u003Ccode>before\u003C\u002Fcode>, \u003Ccode>limit\u003C\u002Fcode> up to 200).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fv1\u002Fadmin\u002Flead-files\u002F{id}\u002Fdownload\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The file, as an attachment.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>DELETE \u002Fv1\u002Fadmin\u002Flead-files\u002F{id}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Delete a file for good.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fv1\u002Fforms\u002F{pk}\u002F{key}\u003C\u002Fcode>, \u003Ccode>POST\u003C\u002Fcode> the same\u003C\u002Ftd>\n\u003Ctd>Public: read the form, sign up.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Invalid values answer \u003Ccode>400\u003C\u002Fcode> with every problem listed. The full schema is in the\nOpenAPI docs at \u003Ccode>\u002F_docs\u002Fscalar\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"leads-in-your-contacts\">Leads in your contacts\u003Ca class=\"heading-anchor\" href=\"#leads-in-your-contacts\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ccode>GET \u002Fv1\u002Fcontacts?leadForm=&lt;id&gt;\u003C\u002Fcode> lists a form's leads; \u003Ccode>?origin=lead_form\u003C\u002Fcode>\neveryone a lead form brought in first.\u003C\u002Fli>\n\u003Cli>Every contact has \u003Ccode>origin\u003C\u002Fcode> (\u003Ccode>{ type, id, at }\u003C\u002Fcode>: \u003Ccode>app\u003C\u002Fcode>, \u003Ccode>lead_form\u003C\u002Fcode>, \u003Ccode>signup\u003C\u002Fcode>,\n\u003Ccode>import\u003C\u002Fcode>, \u003Ccode>sync\u003C\u002Fcode>, \u003Ccode>stripe\u003C\u002Fcode>, \u003Ccode>api\u003C\u002Fcode>, \u003Ccode>panel\u003C\u002Fcode> or \u003Ccode>feedback\u003C\u002Fcode>) and \u003Ccode>leadForms\u003C\u002Fcode>.\nSegments can use both: \u003Cstrong>Added via\u003C\u002Fstrong> is \u003Ccode>lead_form\u003C\u002Fcode> and \u003Cstrong>Lead form\u003C\u002Fstrong> includes\na form. See \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FCONTACTS.md#fields\" target=\"_blank\" rel=\"noopener\">CONTACTS.md\u003C\u002Fa>.\u003C\u002Fli>\n\u003Cli>To mirror leads into your own database, use the event webhook\n(\u003Ccode>contact.subscription_changed\u003C\u002Fcode> fires when a lead confirms) or poll\n\u003Ccode>GET \u002Fv1\u002Fcontacts?updatedSince=\u003C\u002Fcode> (\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Felrumo\u002Fhelp-bites-oss\u002Fblob\u002Fmain\u002Fdocs\u002FMARKETING.md#event-webhook\" target=\"_blank\" rel=\"noopener\">MARKETING.md\u003C\u002Fa>).\u003C\u002Fli>\n\u003C\u002Ful>\n",[6,10,14,17,20,23,26,29,32,35,38,41,44,47,50],{"id":7,"text":8,"level":9},"a-form","A form",2,{"id":11,"text":12,"level":13},"fields","Fields",3,{"id":15,"text":16,"level":13},"words-and-look","Words and look",{"id":18,"text":19,"level":13},"files","Files",{"id":21,"text":22,"level":13},"languages","Languages",{"id":24,"text":25,"level":9},"what-happens-when-someone-signs-up","What happens when someone signs up",{"id":27,"text":28,"level":9},"plug-and-play-web","Plug and play: web",{"id":30,"text":31,"level":13},"options","Options",{"id":33,"text":34,"level":13},"restyle-it","Restyle it",{"id":36,"text":37,"level":9},"a-plain-html-form","A plain HTML form",{"id":39,"text":40,"level":9},"a-hosted-page","A hosted page",{"id":42,"text":43,"level":9},"plug-and-play-swift","Plug and play: Swift",{"id":45,"text":46,"level":9},"your-own-ui","Your own UI",{"id":48,"text":49,"level":9},"managing-forms-over-the-api","Managing forms over the API",{"id":51,"text":52,"level":9},"leads-in-your-contacts","Leads in your contacts",1792677543076]