Docs
From an empty HTML file to a working inbox in under ten minutes.
Quick start
Create an endpoint, then point your form at it.
curl -s -X POST http://localhost:8107/api/forms \
-H "Content-Type: application/json" \
-d '{"email":"you@site.com","name":"Contact"}'
# response: { "id": "...", "token": "...", "endpoint": "..." }
# save the token - it reads submissions back Point your form
Zero JavaScript needed. The honeypot field is what keeps bots out, so keep it exactly as rendered below.
<form action="http://localhost:8107/f/ENDPOINT" method="POST">
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message"></textarea>
<input name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />
<button>Send</button>
</form>
Set a redirect field on the form to control where submitters land
afterwards.
AJAX mode
POST FormData with an
Accept: application/json header and you get JSON instead of a redirect.
await fetch("http://localhost:8107/f/ENDPOINT", {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(document.querySelector("form")),
});
// -> { status: "received" } Spam controls
Three layers run before anything reaches your inbox: a honeypot field,
per-IP rate limits (5 per minute), and a link-count heuristic. Flagged
submissions are stored but hidden. Review them by adding
?spam=show to any read request.
Reading submissions
curl -s "http://localhost:8107/api/forms/FORM_ID/subs?spam=show" \
-H "Authorization: Bearer TOKEN" Notifications go to your account email on every non-spam submission.
Plan limits
| Free | Pro $9/mo | Team $29/mo | |
|---|---|---|---|
| Forms | 2 | 10 | 50 |
| Submissions / month | 100 | 1,000 | 10,000 |
| File uploads | 5MB | 25MB | 25MB |
| Notification emails | 1 | 3 | 5 seats |