Lead capture is a form plus a destination: an inbox, a CRM, a spreadsheet. Lanes Forms is the endpoint that connects the two without a backend.
One POST /v1/forms with a schema returns a live endpoint_url, no signup first. For a signup form the schema is usually one required email field, and a hidden field can carry a campaign tag. Keys you post that are not in the schema are stored under extra rather than rejected, so adding a UTM parameter to your markup later does not break collection. See provisioning and submitting.
How Lanes Forms does it
- One endpoint per form. Provision it, drop it on the page, done. Only
schemais required on the create call, and separate forms for separate campaigns cost one request each, so attribution stays clean. - Route new leads. Forward by email, push to a webhook, or write to Supabase. Email forwarding and Lanes-hosted storage are live today; webhook and Supabase delivery are on the roadmap and return
422 action_not_availableuntil they ship. Stored leads are viewable and exportable from the dashboard. See integrating. - Keep the list clean. Disposable-email rejection and rate limits reduce junk signups. Every form also reserves a hidden
_gotchahoneypot: a bot that fills it is silently marked as spam while still receiving success, and spam is never forwarded to your inbox. Submissions are limited to 10 per minute per IP. - Origin-locked. Only your domain can submit to the endpoint.
allowed_originslists the hostnames allowed to post from a browser; any other origin gets403 origin_not_allowed, and an empty list rejects browser posts entirely. See securing your endpoints.
Why it matters
New contacts flow straight into the tools you already use, without a server in the middle and without the junk.
Capture also does not wait for the destination. Submissions are stored from the first second, so the landing page can go live before you decide where leads should land. Claiming the form releases everything collected so far into the dashboard and switches on forwarding to your verified recipients, up to 5 per form.
Set it up
- Provision the endpoint. One
POST /v1/formswith your email field and your domain inallowed_origins. The response includes theendpoint_url; see provisioning. - Wire your signup UI. POST JSON from your own component and read back the receipt. Keep
_gotchapresent and empty; it is the honeypot.
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 the page. Browser posts are authorized by the form's
allowed_origins, not by a secret, so there is nothing to leak. - Claim and export. Open the claim link, sign in, and manage the list from the dashboard, exporting whenever you want it somewhere else.
Where this breaks without Lanes
The DIY version is a serverless function, a table, and a queue of small chores: validation, deduplication, rate limiting, spam. Each one is an afternoon, and none of them is your product. The common shortcut, pasting a marketing tool's embed script into the page, couples your markup to their widget and their styling.
An endpoint keeps the page yours. Plain HTML or one fetch call, junk filtered before it reaches the list, and the data captured from the first second.
Further reading
- Provisioning a form: schema options, hidden fields, and the create call.
- Integrating a form: fetch wiring and where submissions go today.
- Securing your endpoints: origin allowlists and why browser forms need no key.
- Add a waitlist form without a backend: the same endpoint pattern for a prelaunch list.