# Integrating a form

> Wire an endpoint into a static HTML form, a fetch call, or a server, and choose where submissions go.

Integrating means pointing something at the endpoint and deciding where submissions go. Pick the surface that matches your stack.

## Plain HTML form

The simplest integration: set the form `action` to your `endpoint_url` and let the browser POST. Because the browser sends `Accept: text/html`, the visitor is redirected to `/thanks/{form_id}` on success. No JavaScript required.

```html
<form action="https://api.lanes.sh/v1/f/YOUR_FORM_ID" method="POST">
  <input type="email" name="email" required />
  <textarea name="message"></textarea>
  <!-- honeypot: bots fill this, humans never see it -->
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" />
  <button type="submit">Send</button>
</form>
```

Keep the hidden `_gotcha` input in your markup. It is the [honeypot](/docs/forms/submitting#the-honeypot) that silently absorbs bots.

## fetch / AJAX

For a custom UI, POST JSON and handle the receipt yourself:

```js
const res = await fetch("https://api.lanes.sh/v1/f/YOUR_FORM_ID", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email, message, _gotcha: "" }),
});
const { ok, submission_id } = await res.json();
```

**Never put an API key in browser code**

Browser submissions are authorized by the form's `allowed_origins`, not by a secret. A workspace key shipped to the browser is a leaked key. Keep public, browser-facing forms in `open` mode with an origin allowlist. See [Securing your endpoints](/docs/forms/securing-your-endpoints).

## Server-side

From a backend, POST JSON the same way you would with `curl`. If the form is in `api_key` mode, add the workspace key as a bearer token:

```bash
curl -X POST https://api.lanes.sh/v1/f/YOUR_FORM_ID \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer lfk_YOUR_KEY" \
  -d '{"email": "visitor@site.com", "message": "Hello!"}'
```

## Where submissions go

Delivery is configured per form as a list of **workflow actions**. Two are live today:

| Action | Status | What it does |
| --- | --- | --- |
| `email` | Live | Forwards each non-spam submission to your verified recipients (up to 5). |
| `store` (`lanes`) | Live | Keeps submissions in Lanes-hosted storage, viewable and exportable from the dashboard. |
| `store` (`custom`) | Coming soon | Your own database, such as Supabase. Returns `422 action_not_available` today. |
| `webhook` | Coming soon | POST each submission to your URL. Returns `422 action_not_available` today. |

### Email forwarding

Adding a recipient sends a confirmation link (`GET /v1/verify-email/{token}`). Until a recipient confirms, it is silently skipped, so unverified addresses never receive mail. When a form is [claimed](/docs/forms/claiming) with recipients, the first one is verified for you and forwarding starts.

**Forwarding waits for a claim**

An unclaimed form stores submissions but forwards nothing. Delivery activates the moment the form is claimed.

## The thank-you page

Browser posts land on a hosted `/thanks/{form_id}` page. A per-form redirect override (sending visitors to your own thank-you URL) is on the roadmap.

Next: [Securing your endpoints](/docs/forms/securing-your-endpoints) and [API keys](/docs/forms/api-keys).
