Skip to the documentation
MCP server

Forms

Sign-up forms, the people who fill them in, and their numbers.

Forms tools

ToolWhat it does
listFormsThe workspace’s sign-up forms, most recently changed first, with their status, sign-ups and views.
getFormOne form in full: its fields, copy, audiences, double opt-in and notifications. A published form adds its link, embed code and the address a plain HTML form posts to, and includeDesign returns the draft as JSON.
listFormStartersThe starting points a new form can begin from, with the fields each asks for.
createFormCreate a form from a starter, from a design written as document, or from a starter with changes on top, with any settings. It stays a draft unless publish is true, and has double opt-in on unless doubleOptIn is false.
updateFormChange a form’s name and settings, which apply at once, or its draft design through document. Copy and style merge key by key, and fields replaces the whole list.
publishFormMake the current draft what visitors see, so the form takes sign-ups.
setFormStatusPause a published form, or open it again.
duplicateFormCopy a form into a new draft, without its sign-ups.
deleteFormDelete a form and its sign-ups for good. Its link and embeds stop working, and the people it added stay in your contacts.
getFormAnalyticsViews, sign-ups, people added and still waiting, and the conversion rate over a window, in total and per minute, hour or day. Views are kept per hour.
listFormSubmissionsThe people who filled in a form, newest first, with their answers and status, a page at a time. Search by email address and filter by status.
getFormSubmissionOne sign-up in full: every answer, its status, when it came in and when the person was added, the page it came from and its audiences.
approveFormSubmissionAdd a sign-up that is waiting for its confirmation without the email. Needs contacts:write as well.
resendFormConfirmationEmail a fresh confirmation link to a sign-up still waiting. Nothing is sent when this form emailed that address in the last ten minutes, or when the address has had five from this workspace in the last day. Needs emails:send as well.
removeFormSubmissionsDelete up to 200 sign-ups of a form by id. Contacts and audiences stay as they are.
designFormDesign a new sign-up form from a brief. A designer picks the fields, the copy and the look, and saves it as a draft unless publish is true.
editFormDesignChange the fields, wording or look of a form from instructions. The change lands in the draft, and visitors see the published version until publishForm.

Reading needs forms:read and every change needs forms:write. Anything that makes a form send mail also needs emails:send: turning on double opt-in, setting the sender or the confirmation email, publishing or opening a double opt-in form, and resending a confirmation. A client acting for a member sees only the forms that member made, and a client limited to some addresses may only send confirmations from, and notify, addresses it can reach.

Designing a form from a written brief works the same here as in the app’s chat: designForm makes a new one and editFormDesign changes one, like POST /forms/design and POST /forms/{id}/redesign over REST. A client that would rather design the form itself passes the fields, copy and style as document to createForm or updateForm, and the tools tidy the design and say what they changed.

Some tools on this server make a change the REST API guards with a verification code, and ask for the same code. Until the client has verified a code in the last 60 minutes, or the person has chosen Allow changes for 60 minutes on it in Account → Connected apps, such a tool answers with a result that starts Refused (step_up_required): and changes nothing. emptyAudience never asks for a code. The API Authentication page lists every tool that asks, and shows how to ask for a code and verify it.

The tools apply the same rules and refusals as the REST API, and the /forms pages of the API reference describe every field. listForms orders by last change, and createForm and updateForm tidy a partial document where the API takes it whole.

Reference

listForms

Scopesforms:readThe app's assistant runs it without askingToolkitforms

List the sign-up forms in this workspace, the most recently changed first: name, id, status (draft, live or paused), sign-ups and views. Use it to find a form by name before reading or changing it.

Inputs

Takes no input.

Also available in

API
GET /forms
TypeScript
nextmail.forms.list()nextmail.forms.listAll()nextmail.forms.iterate()
Python
forms.list()forms.list_all()forms.iterate()
Ruby
forms.listforms.list_allforms.iterate
PHP
forms->listforms->listAllforms->iterate
Go
Forms.ListForms.ListAllForms.Iterate
Java
forms().listforms().listAllforms().iterate
C#
Forms.ListAsyncForms.ListAllAsyncForms.IterateAsync

getForm

Scopesforms:readThe app's assistant runs it without askingToolkitforms

Read one sign-up form: its fields, copy, which audiences it fills, double opt-in, what happens after sign-up, notifications and its numbers, and once it is published its public link, the code to embed it on a website and the address a plain HTML form posts to. includeDesign adds the draft design as JSON, to change and pass back to updateForm as document.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
includeDesignboolean
Defaultfalse

Also available in

API
GET /forms/{id}
TypeScript
nextmail.forms.get()
Python
forms.get()
Ruby
forms.get
PHP
forms->get
Go
Forms.Get
Java
forms().get
C#
Forms.GetAsync

listFormStarters

Scopesforms:readThe app's assistant runs it without askingToolkitforms

The starter designs a new sign-up form can begin from: slug, name, the fields each asks for and what it is for. Pass a slug to createForm as starter.

Inputs

Takes no input.

Also available in

API
GET /forms/startersGET /forms/starters/{slug}
TypeScript
nextmail.forms.listStarters()nextmail.forms.getStarter()
Python
forms.list_starters()forms.get_starter()
Ruby
forms.list_startersforms.get_starter
PHP
forms->listStartersforms->getStarter
Go
Forms.ListStartersForms.GetStarter
Java
forms().listStartersforms().getStarter
C#
Forms.ListStartersAsyncForms.GetStarterAsync

createForm

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Create a sign-up form from a starter (listFormStarters names them), from a design written out as document, or from a starter with document changes on top: copy and style merge key by key, and fields, when given, replace the list. With neither it starts from a form that asks only for an email address. The settings updateForm takes can be set at once. It is saved as a draft, whose link does not work yet, unless publish is true. A new form has double opt-in on, sending from the first address you may send as, unless doubleOptIn is false.

Inputs

namestringRequired

A short name for the form.

1 to 120 characters
descriptionstring

One line about what it is for.

Up to 500 characters
starterstring
One of"blank""newsletter""waitlist""event""early-access""contact"
documentRecord<string, any> | string

A form design as JSON: {"fields": [...], "copy": {...}, "style": {...}}. A field needs only type and label, for example {"type": "text", "label": "First name", "mapsTo": "firstName", "required": true}. Types: email, text, textarea, number, phone, url, date, select, radio, checkboxes, checkbox, consent, audiences, hidden, heading, paragraph, divider. Every form has exactly one email field. select, radio, checkboxes and audiences take options, as text or {"label", "value"}; an audiences field offers audiences, with their ids as values. mapsTo makes a field fill a detail of the contact, each from one kind of field: firstName from a text field, lastName from a text field, name from a text field, phone from a phone field, company from a text field, jobTitle from a text field, website from a url field, birthday from a date field. The name is saved on the contact, and the rest on its contact card wherever the card has nothing yet. saveAs instead saves the answer to a custom field of the contact, such as {"type": "select", "label": "Plan", "saveAs": "plan"}, one field per custom field, on any field that takes an answer except the email or an audiences field. Fields also take placeholder, help, defaultValue, width (full or half), minLength, maxLength, min and max. copy holds title, description, submitLabel, successTitle, successMessage, pendingTitle, pendingMessage, closedTitle, closedMessage and footer. style holds accent, background, surface and text (#rrggbb), font (system, sans, serif, mono), radius (none, sm, md, lg, full), width (narrow, normal, wide), layout (card, plain), align (left, center) and logoUrl.

audienceIdsstring[]

Audiences every sign-up joins, by id from listAudiences. None means All contacts.

Up to 20 items
doubleOptInboolean

true emails each new sign-up a link to confirm before they are added.

senderAddressstring

The workspace address confirmation emails come from. Double opt-in needs one.

Can be nullUp to 2000 characters
confirmSubjectstring
1 to 200 characters
confirmMessagestring

The confirmation email text. A blank line starts a new paragraph.

Up to 2000 characters
confirmButtonstring
1 to 60 characters
redirectUrlstring

A page to send people to after sign-up, or null to show the success message.

Can be nullUp to 2000 characters
notifyAddressesstring[]

Workspace addresses that get an email about each new sign-up.

Up to 10 items
allowedSitesstring[]

The sites that may show this form or post to it, at most 20: a domain (example.com, which covers www.example.com too), every subdomain of one (*.example.com), or either with a path (example.com/pricing, example.com/blog/*). A scheme or a port narrows it further (https://example.com, localhost:3000). An empty list means any site. The form's own page always works.

Up to 20 items
publishboolean

true makes it live at once.

Defaultfalse

Also available in

API
POST /forms
TypeScript
nextmail.forms.create()
Python
forms.create()
Ruby
forms.create
PHP
forms->create
Go
Forms.Create
Java
forms().create
C#
Forms.CreateAsync

updateForm

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Change a sign-up form. Its name and settings apply at once, without publishing: the audiences sign-ups join, double opt-in and the address confirmations come from, the confirmation email, what happens after sign-up (message or redirect), which workspace addresses hear about each new sign-up and which sites may show the form or post to it. document changes the design in the draft: copy and style merge into the current ones key by key, and fields, when given, replace the whole list, so start from getForm with includeDesign. A live form keeps showing its published design until publishForm. Pass only what changes.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
namestring
1 to 120 characters
descriptionstring
Can be nullUp to 500 characters
documentRecord<string, any> | string

A form design as JSON: {"fields": [...], "copy": {...}, "style": {...}}. A field needs only type and label, for example {"type": "text", "label": "First name", "mapsTo": "firstName", "required": true}. Types: email, text, textarea, number, phone, url, date, select, radio, checkboxes, checkbox, consent, audiences, hidden, heading, paragraph, divider. Every form has exactly one email field. select, radio, checkboxes and audiences take options, as text or {"label", "value"}; an audiences field offers audiences, with their ids as values. mapsTo makes a field fill a detail of the contact, each from one kind of field: firstName from a text field, lastName from a text field, name from a text field, phone from a phone field, company from a text field, jobTitle from a text field, website from a url field, birthday from a date field. The name is saved on the contact, and the rest on its contact card wherever the card has nothing yet. saveAs instead saves the answer to a custom field of the contact, such as {"type": "select", "label": "Plan", "saveAs": "plan"}, one field per custom field, on any field that takes an answer except the email or an audiences field. Fields also take placeholder, help, defaultValue, width (full or half), minLength, maxLength, min and max. copy holds title, description, submitLabel, successTitle, successMessage, pendingTitle, pendingMessage, closedTitle, closedMessage and footer. style holds accent, background, surface and text (#rrggbb), font (system, sans, serif, mono), radius (none, sm, md, lg, full), width (narrow, normal, wide), layout (card, plain), align (left, center) and logoUrl.

audienceIdsstring[]

Audiences every sign-up joins, by id from listAudiences. None means All contacts.

Up to 20 items
doubleOptInboolean

true emails each new sign-up a link to confirm before they are added.

senderAddressstring

The workspace address confirmation emails come from. Double opt-in needs one.

Can be nullUp to 2000 characters
confirmSubjectstring
1 to 200 characters
confirmMessagestring

The confirmation email text. A blank line starts a new paragraph.

Up to 2000 characters
confirmButtonstring
1 to 60 characters
redirectUrlstring

A page to send people to after sign-up, or null to show the success message.

Can be nullUp to 2000 characters
notifyAddressesstring[]

Workspace addresses that get an email about each new sign-up.

Up to 10 items
allowedSitesstring[]

The sites that may show this form or post to it, at most 20: a domain (example.com, which covers www.example.com too), every subdomain of one (*.example.com), or either with a path (example.com/pricing, example.com/blog/*). A scheme or a port narrows it further (https://example.com, localhost:3000). An empty list means any site. The form's own page always works.

Up to 20 items

Also available in

API
PATCH /forms/{id}
TypeScript
nextmail.forms.update()
Python
forms.update()
Ruby
forms.update
PHP
forms->update
Go
Forms.Update
Java
forms().update
C#
Forms.UpdateAsync

publishForm

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Publish a sign-up form: its current draft becomes what visitors see and it starts taking sign-ups. Use it for a first publish and to push later changes live.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters

Also available in

API
POST /forms/{id}/publish
TypeScript
nextmail.forms.publish()
Python
forms.publish()
Ruby
forms.publish
PHP
forms->publish
Go
Forms.Publish
Java
forms().publish
C#
Forms.PublishAsync

setFormStatus

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Pause a published sign-up form (it shows its closed message and takes no sign-ups) or open it again.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
statusstringRequired

live to take sign-ups, paused to stop.

One of"live""paused"

Also available in

API
POST /forms/{id}/pausePOST /forms/{id}/resume
TypeScript
nextmail.forms.pause()nextmail.forms.resume()
Python
forms.pause()forms.resume()
Ruby
forms.pauseforms.resume
PHP
forms->pauseforms->resume
Go
Forms.PauseForms.Resume
Java
forms().pauseforms().resume
C#
Forms.PauseAsyncForms.ResumeAsync

duplicateForm

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Copy a sign-up form into a new draft with "copy" after its name: the same draft design and settings, and none of its sign-ups. Audiences you cannot see are left out.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters

Also available in

API
POST /forms/{id}/duplicate
TypeScript
nextmail.forms.duplicate()
Python
forms.duplicate()
Ruby
forms.duplicate
PHP
forms->duplicate
Go
Forms.Duplicate
Java
forms().duplicate
C#
Forms.DuplicateAsync

deleteForm

Scopesforms:writeThe app's assistant always asks firstToolkitforms

Delete a sign-up form for good. Its public link and every embed stop working at once and its sign-ups are deleted with it; the contacts it added stay, in their audiences. It cannot be undone.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters

Also available in

API
DELETE /forms/{id}
TypeScript
nextmail.forms.delete()
Python
forms.delete()
Ruby
forms.delete
PHP
forms->delete
Go
Forms.Delete
Java
forms().delete
C#
Forms.DeleteAsync

getFormAnalytics

Scopesforms:readThe app's assistant runs it without askingToolkitforms

How one sign-up form did over a window: views, sign-ups, people added and still waiting to confirm, and the share of views that signed up, in total and per minute, hour or day (grain, day by default). The window reaches back days or minutes from now, minutes winning when both are given, and is 30 days by default. offsetMinutes is the reader's offset from UTC, so a day starts at their midnight.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
daysinteger
At least 1At most 1095
minutesinteger
At least 1At most 1576800
grainstring
One of"minute""hour""day"
offsetMinutesinteger
At least -840At most 840

Also available in

API
GET /forms/{id}/analytics
TypeScript
nextmail.forms.analytics()
Python
forms.analytics()
Ruby
forms.analytics
PHP
forms->analytics
Go
Forms.Analytics
Java
forms().analytics
C#
Forms.AnalyticsAsync

listFormSubmissions

Scopesforms:readThe app's assistant runs it without askingToolkitforms

The people who filled in one sign-up form, newest first: the sign-up id, their answers, and whether they were added or are waiting to confirm by email (a confirmation link lasts 7 days). q searches email addresses, and status keeps pending or added. One page at a time: when more follow, the last line gives a cursor to pass back for the next page.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
qstring

Search by email address.

Up to 200 characters
statusstring
One of"pending""added"
limitinteger
At least 1At most 100
cursorstring

Also available in

API
GET /forms/{id}/submissions
TypeScript
nextmail.forms.listSubmissions()nextmail.forms.listAllSubmissions()nextmail.forms.iterateSubmissions()
Python
forms.list_submissions()forms.list_all_submissions()forms.iterate_submissions()
Ruby
forms.list_submissionsforms.list_all_submissionsforms.iterate_submissions
PHP
forms->listSubmissionsforms->listAllSubmissionsforms->iterateSubmissions
Go
Forms.ListSubmissionsForms.ListAllSubmissionsForms.IterateSubmissions
Java
forms().listSubmissionsforms().listAllSubmissionsforms().iterateSubmissions
C#
Forms.ListSubmissionsAsyncForms.ListAllSubmissionsAsyncForms.IterateSubmissionsAsync

getFormSubmission

Scopesforms:readThe app's assistant runs it without askingToolkitforms

One sign-up in full: every answer, whether it was added or is waiting to confirm, when it came in and was added, the page it was sent from and the audiences it joins.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
submissionIdstringRequired

The sign-up, by id, from listFormSubmissions.

1 to 64 characters

Also available in

API
GET /forms/{id}/submissions/{submissionId}
TypeScript
nextmail.forms.getSubmission()
Python
forms.get_submission()
Ruby
forms.get_submission
PHP
forms->getSubmission
Go
Forms.GetSubmission
Java
forms().getSubmission
C#
Forms.GetSubmissionAsync

approveFormSubmission

Scopesforms:writecontacts:writeThe app's assistant asks first unless you asked for itToolkitforms

Add a sign-up that is waiting to confirm by email without the confirmation: the person becomes a contact and joins the audiences the form fills, now. An address that unsubscribed from one of them before stays unsubscribed there. Use it only when the person really asked to join. A sign-up already added is left as it is.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
submissionIdstringRequired

The sign-up, by id, from listFormSubmissions.

1 to 64 characters

Also available in

API
POST /forms/{id}/submissions/{submissionId}/approve
TypeScript
nextmail.forms.approveSubmission()
Python
forms.approve_submission()
Ruby
forms.approve_submission
PHP
forms->approveSubmission
Go
Forms.ApproveSubmission
Java
forms().approveSubmission
C#
Forms.ApproveSubmissionAsync

resendFormConfirmation

Scopesforms:writeemails:sendThe app's assistant asks first unless you asked for itToolkitforms

Email a new confirmation link to a sign-up that is still waiting to confirm. Nothing is sent to somebody already added, to an address that got one in the last 10 minutes, or to one that has had 5 from this workspace today.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
submissionIdstringRequired

The sign-up, by id, from listFormSubmissions.

1 to 64 characters

Also available in

API
POST /forms/{id}/submissions/{submissionId}/resend
TypeScript
nextmail.forms.resendConfirmation()
Python
forms.resend_confirmation()
Ruby
forms.resend_confirmation
PHP
forms->resendConfirmation
Go
Forms.ResendConfirmation
Java
forms().resendConfirmation
C#
Forms.ResendConfirmationAsync

removeFormSubmissions

Scopesforms:writeThe app's assistant always asks firstToolkitforms

Delete up to 200 sign-ups of one form, by id from listFormSubmissions. Only the sign-ups go: contacts and audiences are not touched. It cannot be undone.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
idsstring[]Required

The sign-ups to delete, by id.

1 to 200 items

Also available in

API
DELETE /forms/{id}/submissions/{submissionId}POST /forms/{id}/submissions/batch-remove
TypeScript
nextmail.forms.deleteSubmission()nextmail.forms.deleteSubmissions()
Python
forms.delete_submission()forms.delete_submissions()
Ruby
forms.delete_submissionforms.delete_submissions
PHP
forms->deleteSubmissionforms->deleteSubmissions
Go
Forms.DeleteSubmissionForms.DeleteSubmissions
Java
forms().deleteSubmissionforms().deleteSubmissions
C#
Forms.DeleteSubmissionAsyncForms.DeleteSubmissionsAsync

designForm

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Design a new sign-up form and save it. Use it whenever the user asks to create, make or build a form, a sign-up or subscribe form, a waitlist, a registration or a contact form. A designer picks the fields, the copy and the look from the brief. It is saved as a draft unless the user asked for it to go live. It takes up to half a minute.

Inputs

namestringRequired

A short name for the form.

1 to 120 characters
briefstringRequired

Everything the form must ask and say: what it is for, the fields, the wording (the user's own text word for word), colours and tone.

1 to 4000 characters
audienceIdsstring[]

Audiences that every sign-up joins, by id from listAudiences.

Up to 20 items
publishboolean

true only when the user asked for it to go live right away.

Defaultfalse

Also available in

API
POST /forms/design
TypeScript
nextmail.forms.design()
Python
forms.design()
Ruby
forms.design
PHP
forms->design
Go
Forms.Design
Java
forms().design
C#
Forms.DesignAsync

editFormDesign

Scopesforms:writeThe app's assistant asks first unless you asked for itToolkitforms

Change the fields, wording or look of an existing sign-up form: add, remove or reorder fields, make one required, change options, rewrite or translate the copy, change colours or fonts. The change is saved to the draft; a live form keeps its published version until publishForm. It takes up to half a minute.

Inputs

idstringRequired

The form, by id (frm_...). listForms finds it by name.

1 to 64 characters
instructionsstringRequired

What to change, with every detail the user gave, their own words word for word.

1 to 4000 characters

Also available in

API
POST /forms/{id}/redesign
TypeScript
nextmail.forms.redesign()
Python
forms.redesign()
Ruby
forms.redesign
PHP
forms->redesign
Go
Forms.Redesign
Java
forms().redesign
C#
Forms.RedesignAsync