How it works
What happens between your form and your inbox: the checks a submission passes, how it is stored before anything is delivered, and how the endpoint decides what to answer.
Overview
MakeTheForm is one HTTP endpoint per form. Your page sends a POST to https://mtform.co/f/your-form-key, we check it, store it, and answer. Email, webhooks and every other destination happen afterwards, from a queue, so a slow mail provider never slows down the person pressing Submit.
There is no SDK and nothing runs on your site. The form key in the URL is an address, not a credential: it lets anyone submit to the form and lets nobody read from it.
Workspaces, projects and forms
Everything you create sits in three levels.
| Level | What it holds | What it decides |
|---|---|---|
| Workspace | Your account: members, billing and the plan. | Entitlements and the monthly submission quota, which is shared by every form in the workspace. |
| Project | A group of forms, usually one website or one client. | Who can see what. Access for clients and teammates is granted per project. A default project is created for you, so you can ignore projects until you need them. |
| Form | One endpoint and its settings: recipients, allowed domains, spam settings, integrations. | What happens to each submission sent to that endpoint. |
Archiving a project takes it out of the project switcher but keeps its forms accepting submissions, so tidying up never breaks a live site. See Projects for clients and Team.
What happens to a submission
Checks run cheapest first, so abuse is turned away before it costs anything. The rate limit runs before the quota check, so a flood cannot spend your allowance.
- Find the form by its key. An unknown or retired key is a 404.
- Check the form is not paused and the workspace is active.
- Rate limit per IP address and form: 5 requests in 30 seconds, 30 in 10 minutes.
- Origin policy, when the form is restricted to its allowed domains.
- Content type and size limits, then parsing.
- Split out the reserved control fields, such as the honeypot and the redirect target, so they are never stored as your data.
- The honeypot, your own block rules and, if you turned it on, the disposable email check.
- The Turnstile challenge, verified on our side, if the form uses one.
- Validation: a submission with no fields at all is refused.
- Content scoring from 0 to 100. Likely spam is kept in the Spam view; near-certain spam is refused and does not count against your quota.
- Duplicate check: the same submission from the same visitor within a minute is not stored twice.
- Quota check.
- Store the submission and its delivery jobs in one database transaction.
Storage, then delivery
The last step writes the submission and one queue entry per destination (email, each webhook, Slack and so on) in the same transaction. Either both exist or neither does, so a success response always means the submission is in your dashboard and every delivery is queued. Nothing after that point can turn it back into an error.
A separate worker picks up the queue and delivers. When a destination fails with something temporary, it tries again on this schedule:
| Attempt | When |
|---|---|
| 1 | Immediately |
| 2 | 1 minute later |
| 3 | 5 minutes later |
| 4 | 30 minutes later |
| 5 | 2 hours later |
| 6 | 12 hours later |
After the sixth attempt the job stops rather than retrying forever. A permanent failure, such as a mailbox that does not exist, stops at once, because retrying a hard bounce damages deliverability for everyone.
Submissions held in the Spam view are stored but not delivered anywhere. On the Free plan, notification email is sent as one daily digest instead of one message per submission; storage, the dashboard and webhooks are unaffected. See Email notifications.
What the caller gets back
The endpoint answers a browser and a script differently. It decides from the request headers, never from the user agent.
| The request | The response |
|---|---|
Accept or Content-Type includes application/json | JSON. 201 with a submission_id on success, or an error object with a code and a safe message. |
A browser form post, Accept includes text/html | A 303 redirect to your thank-you page if one was requested and allowed, or to a plain confirmation page. Errors show a short HTML page. |
| Anything else, such as curl with no Accept header | JSON, as in the first row. |
The 303 means the browser lands on a normal page with a GET, so refreshing it cannot send the form again. The full response shapes and error codes are in the API reference.