Embed on your site
Point plain HTML, fetch or React forms at your Nisuform endpoint. Works with JSON, urlencoded and multipart payloads.
Plain HTML
The simplest integration. Set action and method, no JavaScript needed:
<form action="https://api.nisuform.dev/s/YOUR_KEY" method="POST">
<input type="text" name="name" required>
<input type="email" name="email" required>
<textarea name="message"></textarea>
<input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
<button type="submit">Send</button>
</form>Browser submissions redirect to your thank-you page, or to your custom redirectUrl on Pro.
Fetch
For single-page apps, POST JSON or FormData and read the JSON response:
const res = await fetch('https://api.nisuform.dev/s/YOUR_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email, message }),
})
const out = await res.json()
if (!out.ok) {
// out.error is a stable code, see the table below
}A successful submission returns { "ok": true, "submissionId": "..." }.
React
async function handleSubmit(e) {
e.preventDefault()
const data = Object.fromEntries(new FormData(e.currentTarget))
const res = await fetch('https://api.nisuform.dev/s/YOUR_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
const out = await res.json()
if (out.ok) setStatus('sent')
}Payload rules
- Content types:
application/json,application/x-www-form-urlencodedandmultipart/form-data - Up to 50 fields per submission, 10,000 characters per value
- Body size cap: 200 KB
- Fields named with a leading underscore are ignored, so
_gotchaand friends never reach your inbox - CORS is open: submit from any site
- File uploads are skipped for now; file inputs arrive without their contents
Error codes
Failed submissions return { "ok": false, "error": "code" } with a matching status:
| Code | Status | Meaning |
|---|---|---|
unsupported_media_type | 400 | Content type not supported |
invalid_key | 404 | Unknown access key, check the Setup tab |
quota_exceeded | 402 | Monthly submission limit reached |
payload_too_large | 413 | Body over 200 KB |
form_paused | 423 | Form is paused |
rate_limited | 429 | Too fast, honor Retry-After |
NoteSpam that is dropped silently still returns { "ok": true }. This is deliberate: bots learn nothing and real users never see a false rejection.