Building blocks
Forms
What a form is
A form belongs to one website and has a slug that is unique across 1DB, like acme-contact. The site names the form with that slug when it sends a lead, so 1DB knows which fields to expect and which settings to apply. The same visitor can fill in two forms and stay one contact.
Fields
Forms are built from fields, and fields come from your organization’s field library:
- Standard fields such as email, phone, name, company and message, available to every organization and understood by alerts, contacts and HubSpot.
- Custom fields your team creates once and reuses across forms, like a pallet size or a pickup window.
- Presets: saved sets of fields a new form can start from, so every quote form on every site asks the same questions.
A field your site sends that the form doesn’t list isn’t lost. It’s stored with the lead exactly as sent, and added to the field library so you can map it later.
Two ways to put a form on a page
- The hosted form
- 1DB draws the form from its fields, button text, colors and success message. One script tag shows it as a popup, a slide-in or inline. Change its fields and every page updates with nothing to redeploy. Best for static sites and site builders. How it works
- Your own markup
- Keep your HTML, design and validation, and post the values to
/v1/leadsfrom a server route or the page. You get each bad field back by name, to show next to the input. Best when the form is part of your design. How it works
<script src="https://gallant-goshawk-513.convex.site/v1/embed.js?key=1db_YOUR_KEY&form=acme-contact" async></script>
<button data-1db>Get a quote</button>Field names 1DB understands
Send these under these names and they fill the contact, the alert email and HubSpot without any mapping. Common spellings like firstName or zip work too.
email- The visitor’s email. Needed for a contact, alerts by name and HubSpot. Email or phone is required with contract v2.
phone- Checked and stored as an international number.
first_name, last_name- Up to 80 characters each. A single name field also works.
company- Up to 120 characters.
message- Up to 2,000 characters.
quantity- A whole number from 1 to 1,000,000.
address_line_1, city, state, postal_code- The visitor’s address, for the contact and HubSpot.
submission_id- A random ID made when the form loads, so a retry is stored once. Required with contract v2; recommended without it.
Campaign fields (_1db_utm_source, _1db_gclid, the landing page and referrer) are stored as the lead’s attribution. See capturing UTM parameters.
How submissions are checked
Every lead’s email and phone are checked: an address that can’t receive mail, a throwaway address or a made-up number is refused. Add the header X-1DB-Contract: 2 and 1DB checks every field and answers with all the problems at once:
{
"error": "Check the highlighted fields",
"code": "INVALID_FIELDS",
"fields": {
"email": "Did you mean jo@gmail.com?",
"quantity": "Enter a whole number from 1 to 1,000,000"
},
"suggestions": { "email": "jo@gmail.com" }
}Show each message next to its field. Without the header, the lead is stored as sent unless every contact it gives is certainly wrong. The full rules are in the API reference.
What each form controls
- Notifications
- Email each new lead to up to ten addresses.
- Webhook
- Post each lead as JSON to your URL, with headers you set.
- HubSpot
- Create a HubSpot lead for each submission, with your field mapping.
- Embed
- How the hosted form appears: popup, slide-in or inline, and its look.
- Defaults
- The lead type and product type a lead gets when the visitor didn’t choose one, used by forwarding rules.
One form per question, not per page
A quote form on twenty pages is one form. Split forms when they ask different things or should reach different people, not because they sit on different pages: the page each lead came from is stored anyway.
From the terminal
Create a form from a template, or list its fields. An asterisk marks a required field.
npx @1db/cli form northfieldpallets --template quote-request
npx @1db/cli form northfieldpallets --name "Callback" --fields "phone*:phone,first_name,message:textarea"