> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goliathdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Forms API

> Manage lead-capture forms, read submissions, and pull form analytics through the Goliath developer API

## 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](/developer-api/overview).

## Operations

### Forms and submissions (`READ` scope)

| operationId           | What it does                                                                                                                                                                                                                                                        |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listForms`           | List the organization's lead-capture forms — name, slug, status, lifetime submission count, public URL.                                                                                                                                                             |
| `getForm`             | Fetch one form by id — full config including the single-page or multi-step `fieldConfig`, `submitButtonLabel`, `styleConfig`, auto-apply tags/lists, dedupe settings, notification toggles, and the assignee pool. Read before replacing fields, pages, or styling. |
| `listFormSubmissions` | List submissions (leads), newest first, optionally filtered to one form. Each row carries `submittedData` and the `contactId` it created/matched.                                                                                                                   |
| `getFormSubmission`   | Fetch one submission by id — its `submittedData` and linked `contactId`.                                                                                                                                                                                            |

### Form analytics (`READ` scope)

| operationId                  | What it does                                                                                                                                                                              |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `getFormAnalytics`           | Conversion funnel for one form over a date range — views, starts, submits, conversion rates, median seconds-to-submit, plus a per-day time series. Date ranges over 90 days are rejected. |
| `getFormTrafficSources`      | Where a form's traffic and submissions come from — breakdowns by traffic source, device class, and location.                                                                              |
| `listFormActivity`           | Recent per-session activity (cursor-paginated) — session status, submit/abandon times, traffic source, device, matched contact, assigned agent.                                           |
| `getFormActiveTime`          | Daily active-engagement time — session count and active-ms percentiles (p50/p90), split by submitted vs abandoned.                                                                        |
| `listFormActivityLocations`  | Approximate (\~1 km-rounded) geo coordinates of recent sessions, for plotting a lead map.                                                                                                 |
| `getFormRoutingDistribution` | Lead-assignment distribution for a form's round-robin pool — lead count per assigned user.                                                                                                |

### Writing forms (`WRITE` scope)

| operationId  | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createForm` | Create a form. Requires `name` and `fieldConfig`, either a flat field array or a multi-step `{ fields, steps, showStepProgress }` document. Optional `submitButtonLabel` and `styleConfig` control rendered copy and appearance. New forms start DRAFT; publish via `updateForm(status: ACTIVE)`. Also configurable: SMS and marketing consent capture (`collectSmsConsent`, `showMarketingConsent` and their text fields), legal text and policy links/content (`termsAndConditionsText`, `privacyPolicyUrl`/`privacyPolicyContent`, `termsOfServiceUrl`/`termsOfServiceContent`), AI-employee triggers (`triggerAgentIds`), the lead-routing pool (`assignmentConfig`), submission notifications (`enableEmailNotification`, `enableSmsNotification`, `enableSlackNotification` with `slackChannelId`/`slackChannelName` and `slackMessageTemplate`), plus `source` and `gtmContainerId`. |
| `updateForm` | Update a form by id (patch semantics). `fieldConfig` replaces the entire fields-and-steps document, and `styleConfig` replaces the whole style object; read, merge, and send the full replacement. Activate/deactivate with `status` (`ACTIVE` \| `INACTIVE`). Also configurable: SMS and marketing consent capture (`collectSmsConsent`, `showMarketingConsent` and their text fields), legal text and policy links/content (`termsAndConditionsText`, `privacyPolicyUrl`/`privacyPolicyContent`, `termsOfServiceUrl`/`termsOfServiceContent`), AI-employee triggers (`triggerAgentIds`), the lead-routing pool (`assignmentConfig`), submission notifications (`enableEmailNotification`, `enableSmsNotification`, `enableSlackNotification` with `slackChannelId`/`slackChannelName` and `slackMessageTemplate`), plus `source` and `gtmContainerId`.                                    |
| `deleteForm` | **Hard-delete a form (irreversible, cascading)** — permanently removes ALL its submissions, events, and viewer/lead history.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

<Warning>
  **Prefer deactivating over deleting**

  `deleteForm` permanently destroys the form's entire submission history. To
  simply stop collecting leads, use `updateForm` with `status: INACTIVE`.
</Warning>

<Note>
  **fieldConfig validation**

  A 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.
</Note>

<Note>
  **Styling is a full replacement**

  `styleConfig` 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.
</Note>

<Note>
  **Organization guard**

  Form 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](/developer-api/authorization) for the model.
</Note>

## Example

Pull this month's conversion funnel for one form:

```bash theme={null}
curl -X POST https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer gsk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "operationId": "getFormAnalytics", "variables": { "formId": "FORM_ID", "startDate": "2026-07-01", "endDate": "2026-07-31" } }'
```

Full variable schemas, response shapes, and worked examples for every
operation are available from the
[discovery endpoint](/developer-api/overview#discovering-operations).
