Forms API
List, create, update, duplicate and delete forms, rotate form keys and send test submissions with the Nisuform API.
Every request needs an API key and works in the key's team.
The form object
{
"id": "2f6b7c1e-9a4d-4c3e-8b21-7d5e6f4a3b2c",
"name": "Website contact",
"type": "contact",
"emoji": "✉️",
"key": "k3yz8q2m4n6p0r5t7v9w",
"endpoint": "https://api.nisuform.com/s/k3yz8q2m4n6p0r5t7v9w",
"status": "active",
"closedReason": null,
"notifyEnabled": true,
"notifyEmail": null,
"fields": [
{ "id": "name", "type": "text", "label": "Name", "required": true },
{ "id": "email", "type": "email", "label": "Email", "required": true },
{ "id": "message", "type": "textarea", "label": "Message", "required": true }
],
"createdAt": "2026-09-29T10:00:00.000Z",
"updatedAt": "2026-09-29T10:00:00.000Z"
}The example is shortened. A form has these fields:
| Field | Description |
|---|---|
id | The form ID, used in API paths. |
name | The name shown in the dashboard and in notification emails. |
type | contact, waitlist, feedback, rsvp or custom. Picks the analytics summary. |
emoji | The form's icon in the dashboard, or null. |
key | The public form key. |
endpoint | The URL your form posts to, https://api.nisuform.com/s/{key}. |
status | active or paused. |
closedReason | Why the form stopped taking submissions: manual, max_submissions, auto_close_date, or null while it is open. |
maxSubmissions | Close after this many submissions, or null. |
autoCloseAt | Close at this time, or null. |
closedMessage | Pro. Shown to visitors after the form closed, or null for the default. |
notifyEnabled | Whether new submissions are emailed. |
notifyEmail | Pro. Where notifications go, or null for the team owner's email. |
notifySubject | Subject of notification emails. Supports placeholders. |
notifyFromName | Sender name of notification emails. |
autoreplyEnabled | Pro. Whether people who submit get an auto-reply. |
autoreplySubject, autoreplyBody | Pro. The auto-reply email, or null. |
completionMode | What browser posts see after submitting: default, message or redirect. See After submit. |
completionTitle, completionMessage | Pro. Your thank-you page text, or null. |
redirectUrl | Pro. Where browser posts are sent after submitting, or null. |
fields | The form's fields, used to validate answers and label them. null accepts any fields. See Fields and validation. |
design | Look and copy of the styled embed from the form builder: theme, accent, title, description, submitLabel and successMessage. |
allowedOrigins | Websites allowed to submit. Empty allows every website. See Access rules. |
blockedIps | IP addresses whose submissions are dropped. |
blockedCountries | Two-letter country codes whose submissions are dropped. |
captchaEnabled | Whether a Turnstile token is required. |
captchaProvider | turnstile or null. |
captchaSiteKey | Your Turnstile site key, or null. |
captchaSecretKeySet | Whether a Turnstile secret key is saved. The secret itself is never returned. |
dontStoreIp | Whether visitors' IP addresses are left out of submissions. |
allowUploads | Pro. Whether the form accepts file uploads. |
uploadLimitMb | Largest file size in MB. |
userId | Who created the form. |
createdAt, updatedAt | When the form was created and last changed. |
List forms
GET /v1/formsReturns the team's forms, newest first, in a shorter shape.
{
"forms": [
{
"id": "2f6b7c1e-9a4d-4c3e-8b21-7d5e6f4a3b2c",
"name": "Website contact",
"type": "contact",
"emoji": "✉️",
"status": "active",
"key": "k3yz8q2m4n6p0r5t7v9w",
"endpoint": "https://api.nisuform.com/s/k3yz8q2m4n6p0r5t7v9w",
"createdAt": "2026-09-29T10:00:00.000Z",
"submissionCount": 42
}
]
}submissionCount leaves out spam and test submissions.
Create a form
POST /v1/forms| Body field | Required | Description |
|---|---|---|
name | Yes | 1 to 200 characters. |
type | No | contact (default), waitlist, feedback, rsvp or custom. Sets the starter fields and embed design. custom starts with no fields. |
curl https://api.nisuform.com/v1/forms \
-H "Authorization: Bearer $NISUFORM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Beta waitlist","type":"waitlist"}'Answers 201 with the new form. Point your form at its endpoint. On the Free plan, a team that already has 3 forms gets 402.
Get a form
GET /v1/forms/{id}Returns the full form object, or 404.
Update a form
PATCH /v1/forms/{id}Send only the fields you want to change. Leaving a field out keeps it as it is, and null clears it. Answers with the updated form.
curl -X PATCH https://api.nisuform.com/v1/forms/FORM_ID \
-H "Authorization: Bearer $NISUFORM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"paused","notifySubject":"New lead: {{field.name}}"}'| Body field | Accepts |
|---|---|
name | 1 to 200 characters. |
type | contact, waitlist, feedback, rsvp or custom. Changing it keeps your fields. |
status | active or paused. Resuming a form clears closedReason. |
emoji | Up to 32 characters, or null. |
maxSubmissions | 1 to 1,000,000, or null. |
autoCloseAt | An ISO 8601 time, or null. |
closedMessage | Pro. 1 to 500 characters, or null. |
notifyEnabled | true or false. |
notifyEmail | Pro. An email address, or null. |
notifySubject | 1 to 500 characters. |
notifyFromName | 1 to 100 characters. Pro to change it from the default. |
autoreplyEnabled | true or false. Pro to turn it on. |
autoreplySubject | Pro. 1 to 500 characters, or null. |
autoreplyBody | Pro. 1 to 5,000 characters, or null. |
completionMode | default, message or redirect. |
completionTitle | Pro. 1 to 200 characters, or null. |
completionMessage | Pro. 1 to 2,000 characters, or null. |
redirectUrl | Pro. An http or https URL. null or "" removes it. |
fields | Up to 30 fields, or null. Replaces every field. |
design | The whole design object. Replaces the current design. |
allowedOrigins | Up to 50 website addresses. Paths are dropped, so https://example.com/contact is saved as https://example.com. |
blockedIps | Up to 1,000 IP addresses. |
blockedCountries | Up to 300 two-letter country codes. |
captchaSiteKey | Your Turnstile site key, or null. |
captchaSecretKey | Your Turnstile secret key, or null. Write only. |
captchaEnabled | true or false. Turning it on needs a site key and a secret key, saved before or in the same request. |
dontStoreIp | true or false. |
allowUploads | true or false. Pro to turn it on. |
uploadLimitMb | 1 to 100. Pro to change it from 10. |
A Pro setting on a Free team answers 402 and nothing is saved.
Fields
Each field has an id, which is the name your form sends, a type, a label and required. Types are text, email, textarea, number, date, select, radio, checkbox, rating, tel, url and file.
{
"fields": [
{ "id": "email", "type": "email", "label": "Email", "required": true },
{ "id": "plan", "type": "select", "label": "Plan", "required": false, "options": ["Starter", "Team"] },
{ "id": "score", "type": "rating", "label": "How likely are you to recommend us?", "required": true, "max": 10 }
]
}| Field option | Types | Description |
|---|---|---|
placeholder | All | Up to 200 characters. |
helpText | All | Up to 500 characters. |
minLength, maxLength | text | Answer length. textarea takes maxLength. |
pattern | text | A regular expression the answer must match. |
min, max | number | Smallest and largest allowed value. |
options | select, radio | 1 to 100 choices. |
max | rating | Number of stars, 3 to 10. Defaults to 5. |
Field IDs start with a letter and use letters, digits, - or _, up to 64 characters, and must be unique. See Fields and validation for how answers are checked.
Delete a form
DELETE /v1/forms/{id}Deletes the form with all its submissions and uploaded files, and answers { "ok": true }. Its endpoint stops accepting submissions right away. This can't be undone.
Duplicate a form
POST /v1/forms/{id}/duplicate| Body field | Required | Description |
|---|---|---|
nameSuffix | No | Added to the copy's name. Defaults to " copy". |
Copies the form's settings, fields, design and integrations into a new form with a new key. Google Sheets isn't copied, and a copied webhook gets its own signing secret. The copy starts open, without a submission limit or close date, and without submissions. Answers 201 with the copy. It counts toward the Free plan's form limit.
Rotate the form key
POST /v1/forms/{id}/rotate-keyGives the form a new key and answers with the updated form. The old endpoint stops accepting submissions right away, so update your website with the new endpoint first.
Send a test submission
POST /v1/forms/{id}/test-submissionsStores a sample submission marked as a test and runs the form's notifications and integrations, so you can check your setup. Answers 201 with { "submissionId": "..." }. Test submissions don't count toward your monthly limit.