The forms API
How a signup form takes a POST from any site, as plain HTML or as JSON.
Every signup form has one public address, its hosted page, and the same address takes a POST from anywhere on the internet. A plain HTML form on a static site works with JavaScript off. A fetch call that sends JSON gets JSON back. No key and no CSRF token are needed, because the address only adds someone to your list. Copy a form's address from its page under Money > Forms; below it is written FORM_URL.
Post from an HTML form
<form method="post" action="FORM_URL">
<label>Email <input type="email" name="email" required></label>
<label>Name <input type="text" name="name"></label>
<div style="position:absolute;left:-9999px" aria-hidden="true">
<input type="text" name="website" tabindex="-1" autocomplete="off">
</div>
<button type="submit">Subscribe</button>
</form>The form's page gives you this snippet ready to paste, with a view pixel included so the form's numbers count views from your site.
- On success, the reader goes to the form's redirect URL if you set one, otherwise to a thank-you page with the form's success message.
- On a problem, the reader sees the hosted page again with the problem named and their typing kept.
Post as JSON
Send Content-Type: application/json (or Accept: application/json):
curl -X POST FORM_URL \
-H "Content-Type: application/json" \
-d '{"email": "reader@example.com", "name": "Ada"}'Success is 200:
{"ok": true, "status": "confirm_sent", "message": "..."}status is confirm_sent when the form uses double opt-in (the reader must click the link in their inbox) and subscribed when it does not. message is the form's success message.
A refusal has "ok": false and an error:
| Status | Error | When |
|---|---|---|
| 400 | invalid | The address is not valid; fields names the problem. |
| 400 | challenge_required | The form requires the challenge, which only its hosted page can carry. |
| 404 | unknown_form | No form at that address. |
| 410 | closed | The form is switched off. |
| 429 | rate_limited | Too many signups. Wait the seconds in Retry-After. |
Fields
Only email, name, and website are read. Anything else is dropped.
emailis required.nameis optional.websiteis the honeypot. Keep it in your markup, hidden from people. A post with anything in it is answered as a success and nobody is added.
Things to know
- Cross-origin requests are allowed from any site, so a browser
fetchworks without a proxy. - With double opt-in on, nothing is tagged, enrolled, or mailed (apart from the one confirmation) until the reader clicks.
- One IP address may sign up 5 times in 10 minutes, and one address gets at most 3 confirmation mails a day.
- With the challenge on, link to the hosted page instead of posting to it.
- Only the redirect saved on the form is ever followed, never one sent in the request.