Create forms, retrieve submissions, and manage your form backend programmatically. Full CRUD access with API key authentication.
https://formslist.com/api/v1All API requests require a Bearer token using your API key. Generate API keys from your dashboard under Account → API Keys.
API keys are hashed (SHA-256) before storage and cannot be retrieved after creation. Keep your key secure: treat it like a password. If compromised, revoke it immediately from the dashboard and generate a new one.
Authorization: Bearer fl_your_api_key_herecurl https://formslist.com/api/v1/forms \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6"const response = await fetch('https://formslist.com/api/v1/forms', {
headers: {
'Authorization': 'Bearer fl_live_a1b2c3d4e5f6',
'Content-Type': 'application/json',
},
});
const { data } = await response.json();
console.log(data); // Array of formsimport requests
headers = {"Authorization": "Bearer fl_live_a1b2c3d4e5f6"}
response = requests.get("https://formslist.com/api/v1/forms", headers=headers)
data = response.json()["data"]
print(data) # List of formsSecurity: Never expose your API key in client-side JavaScript (browser code). API keys should only be used in server-side code, environment variables, or CI/CD pipelines.
All endpoints are rate-limited to 100 requests per 60-second window per API key. Exceeding the limit returns 429 Too Many Requests.
All successful responses return JSON with a data field. List endpoints include a meta field with pagination info.
{
"data": { ... },
"meta": {
"page": 1,
"per_page": 25,
"total": 42,
"total_pages": 2
}
}{
"error": "Missing or invalid Authorization header"
}Create, read, update, and delete form endpoints. Each form has a unique hash used as the submission endpoint at /f/{hash}.
/api/v1/formsReturns all forms belonging to your team.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Optional | Unique form ID |
name | string | Optional | Form name |
hash | string | Optional | Public form hash for the submission endpoint |
endpoint | string | Optional | Full submission path (/f/{hash}) |
submission_count | number | Optional | Total submissions received |
is_active | boolean | Optional | Whether the form accepts submissions |
created_at | string | Optional | ISO 8601 timestamp |
curl https://formslist.com/api/v1/forms \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6"{
"data": [
{
"id": "frm_8kTn2xLm",
"name": "Contact Form",
"hash": "abc123def",
"endpoint": "/f/abc123def",
"submission_count": 47,
"is_active": true,
"created_at": "2026-03-15T10:30:00Z"
}
],
"meta": { "total": 1 }
}/api/v1/formsCreates a new form endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Form name |
description | string | Optional | Form description |
curl -X POST https://formslist.com/api/v1/forms \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{"name": "Contact Form", "description": "Main site contact"}'{
"data": {
"id": "frm_9pQr3yMn",
"name": "Contact Form",
"hash": "xyz789abc",
"endpoint": "/f/xyz789abc",
"is_active": true,
"created_at": "2026-03-22T14:00:00Z"
}
}/api/v1/forms/:formIdReturns details for a single form.
curl https://formslist.com/api/v1/forms/frm_8kTn2xLm \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6"/api/v1/forms/:formIdUpdates a form's properties. All fields are optional.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Optional | New form name |
description | string | Optional | New description |
is_active | boolean | Optional | Enable or disable the form |
curl -X PATCH https://formslist.com/api/v1/forms/frm_8kTn2xLm \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Contact Form", "is_active": false}'/api/v1/forms/:formIdPermanently deletes a form and all its submissions. This action cannot be undone.
curl -X DELETE https://formslist.com/api/v1/forms/frm_8kTn2xLm \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6"{
"data": { "deleted": true }
}Retrieve form submissions programmatically. Submissions are created when users submit forms via the /f/{hash} endpoint; they cannot be created via the API.
/api/v1/forms/:formId/submissionsReturns paginated submissions for a form, newest first.
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | Optional | Page number (default: 1) |
per_page | number | Optional | Results per page (max 100) (default: 25) |
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Optional | Submission ID |
data | object | Optional | Submitted form data as key-value pairs |
is_spam | boolean | Optional | Whether flagged as spam by AI scoring |
created_at | string | Optional | ISO 8601 timestamp |
curl "https://formslist.com/api/v1/forms/frm_8kTn2xLm/submissions?page=1&per_page=50" \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6"{
"data": [
{
"id": "sub_4jKp7rWs",
"data": {
"name": "Sarah Chen",
"email": "sarah@example.com",
"message": "Interested in your Pro plan. Can we schedule a demo?"
},
"is_spam": false,
"created_at": "2026-03-22T09:15:00Z"
},
{
"id": "sub_2mNq9tYu",
"data": {
"name": "Marcus Rivera",
"email": "marcus@agency.co",
"message": "We build 20+ client sites per year. Is there an agency plan?"
},
"is_spam": false,
"created_at": "2026-03-21T16:42:00Z"
}
],
"meta": {
"page": 1,
"per_page": 50,
"total": 47,
"total_pages": 1
}
}/api/v1/submissions/:submissionIdReturns a single submission with full details including metadata.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Optional | Submission ID |
form_id | string | Optional | Parent form ID |
data | object | Optional | Submitted form data |
metadata | object | null | Optional | Request metadata (IP geolocation, user agent, UTM params) |
is_spam | boolean | Optional | Whether flagged as spam |
is_read | boolean | Optional | Whether marked as read in the dashboard |
created_at | string | Optional | ISO 8601 timestamp |
curl https://formslist.com/api/v1/submissions/sub_4jKp7rWs \
-H "Authorization: Bearer fl_live_a1b2c3d4e5f6"{
"data": {
"id": "sub_4jKp7rWs",
"form_id": "frm_8kTn2xLm",
"data": {
"name": "Sarah Chen",
"email": "sarah@example.com",
"message": "Interested in your Pro plan."
},
"metadata": {
"ip": "203.0.113.42",
"country": "US",
"city": "San Francisco",
"user_agent": "Mozilla/5.0...",
"utm_source": "twitter",
"utm_medium": "social"
},
"is_spam": false,
"is_read": true,
"created_at": "2026-03-22T09:15:00Z"
}
}Form submissions are sent to https://formslist.com/f/{hash}. This is a separate endpoint from the REST API and does not require authentication.
<form action="https://formslist.com/f/your_form_hash" method="POST">
<input name="name" type="text" required />
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>Set Accept: application/json to receive a JSON response instead of a redirect.
const response = await fetch('https://formslist.com/f/your_form_hash', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
name: 'Sarah Chen',
email: 'sarah@example.com',
message: 'Hello from JavaScript!',
}),
});
const result = await response.json();
// { "ok": true, "submission_id": "..." }| Parameter | Type | Required | Description |
|---|---|---|---|
_next | string | Optional | URL to redirect to after submission (HTML forms only). `_redirect` also works |
_subject | string | Optional | Overrides the notification email subject |
_replyto | string | Optional | Email address for auto-responder (overrides "email" field) |
_gotcha | string | Optional | Honeypot field: leave empty. If filled, submission is marked as spam |
_captcha | string | Optional | CAPTCHA token (reCAPTCHA, Turnstile, or hCaptcha) |
One script tag adds a floating contact button that opens a form. Optional attributes: data-color, data-position, data-title, data-fields. The “Powered by FormsList” badge is removed on paid plans.
<script src="https://formslist.com/widget.js" data-form="your_form_hash"></script>A small client for custom forms. It posts to formslist.com, attaches UTM parameters and exposes a useFormsList React hook.
<script src="https://formslist.com/sdk/formflow.js"></script>
<script>
const fl = new FormsList('your_form_hash');
fl.submit({ name: 'Sarah', email: 'sarah@example.com', message: 'Hi!' })
.then((r) => console.log(r)); // { ok: true, submission_id: '...' }
</script>
// React (with the script loaded):
const { submit, submitting, success, error } = useFormsList('your_form_hash');Add this next to your form to see what visitors typed before leaving. A visitor who entered an email address and left without submitting gets one short “you were almost done” email after an hour; people who submit are never emailed. Passwords, card numbers and similar fields are never captured. Results appear under each form’s Partials tab.
<script src="https://formslist.com/capture.js" data-form="your_form_hash" defer></script>FormsList runs a remote MCP server. Connect it once and ask your assistant to create a form, wire it into your site and summarise the submissions. You sign in with your FormsList account and choose what the app may do, so there is no API key to copy. Only a workspace owner or admin can connect apps.
https://formslist.com/mcpOpen Settings → Connectors → Add custom connector, name it FormsList, paste the server URL and click Add. Click Connect, sign in to FormsList and choose Allow. On Team and Enterprise plans an owner adds it once under organization settings, then each person connects.
Open Settings → Apps & Connectors. Under Advanced settings, turn on Developer mode, then Create a connector: name FormsList, MCP server URL as above, authentication OAuth. Sign in to FormsList and choose Allow.
claude mcp add --transport http formslist https://formslist.com/mcp
# then run /mcp inside Claude Code and choose "Authenticate"Add FormsList to Cursor (one click), or add it to ~/.cursor/mcp.json:
{ "mcpServers": { "formslist": { "url": "https://formslist.com/mcp" } } }Install in VS Code (one click), or add it to .vscode/mcp.json:
{ "servers": { "formslist": { "type": "http", "url": "https://formslist.com/mcp" } } }Point it at the server URL; it discovers sign-in through standard OAuth metadata. Clients without OAuth can send an API key from Account → API keys as a header:
Authorization: Bearer ff_sk_your_api_key| Tool | Access | What it does |
|---|---|---|
list_forms | read | Every form with its id, endpoint URL, submission count and status |
get_form | read | One form’s settings: notification emails, auto-response, redirect, validation |
create_form | write | Create a form and get its live https://formslist.com/f/… endpoint |
update_form | write | Rename, set notification emails, add validation, turn a form on or off |
configure_autoresponse | write | Set the automatic reply people get after submitting (Pro) |
get_submissions | read | Read submissions, newest first, 20 per page (up to 100) |
get_embed_snippet | read | Ready-to-paste HTML form (with spam honeypot) for a form |
The consent screen asks for forms:read, forms:write and submissions:read. Connected apps can never delete forms or submissions, or see billing and API keys. Access tokens last an hour and renew automatically; see and revoke connected apps under Account → API keys. Prefer a local server? npx -y formslist-mcp runs the stdio version.
| Status | Meaning | Common Cause |
|---|---|---|
400 | Bad Request | Missing required fields (e.g., name on form creation) |
401 | Unauthorized | Missing, malformed, or invalid API key |
403 | Forbidden | Team has reached its plan's form limit |
404 | Not Found | Resource does not exist or belongs to a different team |
429 | Too Many Requests | Rate limit exceeded (100 req/min per key) |
500 | Server Error | Internal error; contact support if persistent |
API access is available on Pro ($15/mo) and Business ($45/mo) plans.