Every form has one endpoint:
POST https://formsubmit.app/f/{formId}Accepted content types
| Content-Type | Typical source | Notes |
|---|---|---|
application/x-www-form-urlencoded | Plain HTML forms (default) | Repeated keys and name[] become arrays. |
multipart/form-data | Forms with enctype="multipart/form-data", FormData in JS | Required for file inputs. About 4.5 MB per request. |
application/json | fetch with JSON.stringify | Body must be a JSON object. Nested values are stored as-is. |
text/plain | enctype="text/plain", sendBeacon | Parsed as key=value lines. |
Up to 200 fields are stored per submission and each value is capped at 100,000 characters. Field names starting with _ are reserved for control fields and are not stored as data.
Responses
FormSubmit decides between a redirect and JSON:
- JSON is returned when the body is JSON, the
Acceptheader asks forapplication/json(withouttext/html),X-Requested-With: XMLHttpRequestis sent, or the form includes_format=json. - Otherwise the response is a 303 See Other redirect.
Success
{ "ok": true, "id": "r8T2kLm0Qa9zXc1V", "message": "Thanks! Your submission has been received." }id is null for forms set to "don't store" and for submissions silently discarded by the honeypot. The message is your form's custom success message if you set one.
For HTML forms the redirect goes to, in order of priority:
- The redirect URL in your form settings.
- A
_redirect(or_next) field in the submission — must match your domain allowlist if one is set. - The hosted thank-you page at
https://formsubmit.app/thanks.
Errors
{ "ok": false, "error": { "code": "captcha_failed", "message": "Captcha verification failed. Please try again." } }HTML forms are redirected to a friendly error page instead.
| Code | HTTP | Meaning |
|---|---|---|
form_not_found | 404 | The form id doesn't exist (or was deleted). |
form_inactive | 403 | The form is paused — manually or because your plan's form limit was reduced. |
domain_not_allowed | 403 | The Origin/Referer isn't on the form's allowlist. |
rate_limited | 429 | Too many submissions from one IP (20/min per form) or to one form (600/min). |
captcha_failed | 400 | Missing or invalid captcha token. |
bad_request | 400 | The body couldn't be parsed (e.g. invalid JSON). |
file_too_large | 413 | A file exceeds your plan's per-file limit. |
payload_too_large | 413 | The whole request exceeds the ~4.5 MB body limit. Use direct uploads. |
storage_quota_exceeded | 507 | The form owner's file storage is full. |
uploads_unavailable | 503 | File uploads are temporarily unavailable. |
internal_error | 500 | Something went wrong on our side. Safe to retry. |
CORS
The endpoint answers OPTIONS preflight requests. With no allowlist, any origin may submit. With an allowlist, only matching origins receive Access-Control-Allow-Origin.
Monthly limits
If you're over your plan's monthly submissions, the endpoint still returns success and stores the submission — it is locked until you upgrade or the month resets. Visitors never see an error because of your quota. See limits and plans.
GET requests
Opening the endpoint in a browser shows a short explanation page. Only POST creates submissions.