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

# Forms and leads

> Create lead sources and see what a form submission creates.

A lead source is a place where people come from before they write to you. It can be a website form, a lead form of
a connected tool, or any system that sends a webhook. Every source keeps each submission once and turns it into a
contact.

Only an owner or an admin can read or change lead sources. Other members get a `403`.

## Create a website form

```bash theme={null}
curl -X POST https://api.impellabs.tech/api/v1/lead-sources \
  -H "Authorization: Bearer imp_..." \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "website_form",
    "name": "Spring offer",
    "fields": [
      {"key": "name", "label": "Name", "type": "text", "required": true},
      {"key": "phone", "label": "Phone", "type": "phone"},
      {"key": "email", "label": "Email", "type": "email"}
    ],
    "slug": "spring-offer"
  }'
```

The reply has status `201`. It is an object with a `source` key. A form has its own public page and an address that takes
submissions. The source shows both.

| Field of the source | Meaning |
| - | - |
| `id` | The lead source id. |
| `kind` | `website_form`, `webhook` or `connection`. |
| `on` | Whether the source takes submissions. |
| `page` | The public page of a form, built from its `slug`. |
| `address` and `url` | The address that takes submissions. It is empty for a source that ImpelLabs reads on a schedule. |
| `snippet` | An HTML form that posts to the address, for your own site. |
| `fields` | The questions of the form. |
| `mapping` | Which answers name the person: `name`, `phone`, `email`. |
| `values` | Fixed values that a new CRM lead from this source gets. |
| `owner_id` | The member who owns a new contact from this source. |
| `submissions` | How many submissions the source kept. |

Request fields for a new source:

* `name` is required, up to 120 characters.
* `kind` is `website_form` (default), `webhook` or `connection`.
* `fields` is a list of field objects or a list of field keys of your CRM. With nothing, the form starts with the
  fields of your CRM that a customer may fill.
* `slug` is the link of the page: 3 to 60 small letters, numbers and single hyphens. It is unique on the platform.
  With nothing, ImpelLabs makes one from the name.
* `design` is `{title, intro, submit, thanks_title, thanks_text, accent}`. `accent` is a color like `#111827`.
* `mapping`, `values` and `owner_id` are optional.
* For `webhook`: `verify`, `secret` and `id_path`. The reply carries the `secret` once. Read
  [incoming events](https://docs.impellabs.tech/api/incoming-events.md) for these fields.
* For `connection`: `event_source_id`, or `connection_id` with `event`, and `input` when the event needs it.

A bad request returns `400` with the name of the field and a plain sentence. A link that is taken returns
`{"slug": "This link is taken. Choose another."}`.

## Read and change sources

| Task | Call |
| - | - |
| List the sources. | `GET /api/v1/lead-sources` |
| Read the fields a new form starts with. | `GET /api/v1/lead-sources/fields` |
| Read one source. | `GET /api/v1/lead-sources/{source_id}` |
| Change `name`, `on`, `fields`, `mapping`, `values`, `owner_id`, and for a form `design` and `slug`. | `PATCH /api/v1/lead-sources/{source_id}` |
| Archive a source and switch it off. | `DELETE /api/v1/lead-sources/{source_id}` |
| Read the submissions, newest first. | `GET /api/v1/lead-sources/{source_id}/submissions` |
| Check what a submission would do. Nothing is kept. | `POST /api/v1/lead-sources/{source_id}/test` |

The submissions reply is `{"results": [...], "next": "..."}`. Pass `next` as `?before=` for older ones. Each
submission has `external_id`, `contact`, `outcome`, `problem`, `answers`, `touch`, `lead_record_id` and `at`.

The test call takes an `answers` object, such as `name` and `phone`. It returns the person it finds, the
contact it would find or make, and the campaigns it would join.

## The public form

A form with a `slug` has a public address that needs no token. These two calls are what the public page uses. You can
call them from your own site.

```bash theme={null}
# What the page shows: the design, the questions and the business name.
curl https://api.impellabs.tech/api/v1/forms/spring-offer

# Send the answers.
curl -X POST https://api.impellabs.tech/api/v1/forms/spring-offer \
  -H "Content-Type: application/json" \
  -d '{"answers": {"name": "Sam", "phone": "+971501234567"}}'
```

A good submission returns `ok` set to `true` and a `thanks` object with a `title` and a `text`.

* `answers` holds only the keys of the form. Other keys are dropped. Each value is cut to 2000 characters.
* A wrong answer returns `400` with a `problems` object. Each problem is one field key and one sentence, such as `phone` and `Write the number with its country code, like +971 50 123 4567.`
  A required field that is empty, an email, a phone number, a number and a choice are checked by the field type.
* `website` is a hidden box. Leave it empty. A request that fills it gets the same thanks answer and nothing is kept.
* `utm_campaign` is optional. It matches a campaign that has a `utm_campaign` source.
* An unknown or archived form returns `404`. A form that is switched off answers `200` and keeps nothing.
* Each sender address can send 20 submissions an hour to one form. More returns `429`.

## What a submission creates

ImpelLabs keeps each submission once for each source and id. Then, in this order:

1. It finds the person by the phone, or else the email, in the answers. It makes a contact when it finds none. A new
   contact needs at least a name, a phone or an email. A submission with none of them is kept with the outcome
   `failed`.
2. It writes a `touch` on the contact timeline: `Came from <source name>.`
3. It raises the events `contact.touch` and `lead.submitted`. See [event types](https://docs.impellabs.tech/api/events.md). A workflow or a webhook
   can start on them.
4. It adds the contact to each active campaign that has a matching source: a website form, a form of an ad, a
   `utm_campaign` value or an ad.
5. It creates or updates the CRM lead of the contact. A contact has one lead, and an existing lead keeps its owner.

The contact is never joined to another contact here. A form that was opened from a broadcast email also adds the
person to that broadcast campaign and counts as a click.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.