Skip to main content

About

Programmatic access to lead-capture (embed) forms: create and update forms, read submissions as they come in, and pull the analytics behind the app’s form dashboards — conversion funnels, traffic sources, engagement time, and lead routing. All operations go through the developer API gateway — one endpoint, called by operationId. If you haven’t set up a key yet, start with the Developer API Overview.

Operations

Forms and submissions (READ scope)

Form analytics (READ scope)

Writing forms (WRITE scope)

Prefer deactivating over deletingdeleteForm permanently destroys the form’s entire submission history. To simply stop collecting leads, use updateForm with status: INACTIVE.
fieldConfig validationA single-page form uses a flat field array. A multi-step form uses { fields, steps, showStepProgress }; each step has a unique id, required builder-facing name, and optional visitor-facing title, subtitle, and ctaLabel. Fields point to a page with stepId; an unknown step is rejected. Two or more steps render the paged experience.Field type is one of text | email | phone | number | dollar | dropdown | multiselect | textarea | checkbox | address | calendar; mapping is firstName | lastName | fullName | email | phone | address | note | none | customField:<id>; width is full | half | third. Fields may also carry hideLabel, validation rules, dropdown-to-custom-field option mappings, and calendarConfig. A calendar field without calendarConfig renders no picker, so always provide it. At least one field is required and at most one calendar field is allowed. Malformed entries are rejected with a validation error naming the field. fieldKey is limited to 200 characters; each dropdownOptions entry and mapped formOptionLabel is limited to 256. Longer values reject the whole create or update instead of being truncated.

Calendar locations

A calendar field’s calendarConfig.locationType is CUSTOM (the default), VIDEO_CALL, or PHONE_CALL. CUSTOM uses defaultLocation, such as a street address or pasted meeting link. VIDEO_CALL uses the join link created on the host’s calendar: Google Meet, or Microsoft Teams when calendarProvider is MICROSOFT. PHONE_CALL creates no meeting link: the host calls the number the booker entered. That mode requires a field with type: "phone", mapping: "phone", and required: true, or the write is refused. Always supply the rest of calendarConfig; without it, the calendar field renders no booking picker.

Routing calendar bookings

Set assignmentConfig to { assignees, teamIds, participantUserIds }. All three lists are required when supplied and replace the whole pool; omit the object to preserve it. Read getForm and merge before changing one list. Each assignee has a same-organization userId; on a calendar form it also needs calendarConfig: { isFixed, checkExternalCalendars }. Non-fixed assignees rotate in array order by least recent booking. Fixed assignees always attend; if all are fixed, the first is the host. Calendar forms require a non-empty pool and a calendar configuration for every assignee before activation. Some organizations also require the pinned Google/Microsoft calendar provider to be connected on first activation; connect any refused account in the app and retry. A form without a calendar can activate with an empty pool.

Starting workflows on submission

createForm and updateForm accept input.triggerWorkflowGroupIds, the complete set of CONTACT workflow group ids to start for each submission’s contact. Omit the field to leave the wiring untouched; send [] to clear it. Newly added groups must belong to the organization and be neither archived nor hidden. The active version is resolved at submission time, so publishing a new version does not require rewiring the form. Enrollment follows the workflow’s enrollment policy; it does not re-evaluate its trigger predicate. The persisted getForm, createForm, and updateForm responses do not echo this wiring. Keep the intended full set in your integration when replacing it. Workflows with no eligible active version are skipped, and an enrollment failure does not fail the form submission; a successful submission alone does not confirm a workflow ran.
Standalone marketing consent is for SMSTo enable showMarketingConsent, also provide non-empty marketingConsentText that explicitly describes SMS/text messages and a field with type: "phone" and mapping: "phone". On update, resend the enabled toggle and the SMS wording together. This records SMS consent; standalone email consent is not supported by these fields.The full collectSmsConsent block has separate transactional and marketing wording (smsTransactionalConsentText, smsMarketingConsentText). Enabling it also displays a marketing checkbox, using default wording when none is supplied. Configure both deliberately; one consent does not grant the other. An omitted or null label uses and records the built-in wording; an empty string renders and records no wording. Supply explicit copy rather than an empty string. smsDisclaimerText is the paragraph beneath the checkboxes, not a separate opt-in.
An ordinary field does not capture consentA checkbox, dropdown, or multiselect answer only lands in submittedData; it does not record SMS consent evidence or a consent snapshot. Use the Legal & Consent settings above with their explicit wording.createForm refuses a checkbox whose label reads as SMS consent with 400 bad_request. updateForm refuses newly introduced consent checkboxes; an existing one can be carried forward so unrelated edits remain possible. Dropdown and multiselect options are not automatically refused, but they still do not record consent.
Styling is a full replacementstyleConfig controls colors, typography, spacing, borders, inputs, buttons, form width/padding/shadow, dividers, and sanitized custom CSS on both hosted and embedded forms. Read the current object with getForm, merge locally, then send the whole result; {} resets defaults. Unknown keys are ignored at render time, so use the supported key vocabulary in updateForm’s discovery detail rather than guessing property names.
Organization guardForm operations are org-guarded on the formId (or id on updateForm): a form outside your organization returns 403 forbidden. listForms and createForm take no cross-org id — they list / create under your org. See Authorization for the model.

Example

Pull this month’s conversion funnel for one form:
Full variable schemas, response shapes, and worked examples for every operation are available from the discovery endpoint.