Skip to content

Collect form submissions

Point an HTML form’s action at deploybase and every submission is stored, scored for spam, and emailed to your team. There is no backend to run, no JavaScript required, and the form does not have to be on a site we host.

Open a project, go to the Forms tab, and create a form. Then point a form at the endpoint it gives you:

<form action="https://api.deploybase.eu/f/0123456789abcdef" method="POST">
<input type="email" name="email" />
<input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />
<button>Send</button>
</form>

No JavaScript and no API key are involved. The endpoint accepts requests from any origin, so the form can live anywhere.

0123456789abcdef is deliberately fake. Every form has its own id, shown on the form’s page in the dashboard, and a real one is random rather than a tidy run of hex.

Opening the endpoint in a browser shows a live-check page that renders your own snippet back at you, which is the quickest way to confirm you have the right id before wiring it into a real page.

Send Accept: application/json and you get a JSON response rather than a redirect:

const res = await fetch("https://api.deploybase.eu/f/0123456789abcdef", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ email: "jane@example.com", message: "Hello" }),
});
const { ok, id } = await res.json();

Success is 200 {"ok": true, "id": "..."}. Without that header the same request gets a 303 redirect instead, which is what makes a plain HTML form post work.

Content type Notes
application/x-www-form-urlencoded A standard HTML form post
multipart/form-data Fields only. A file part returns 422 FILES_NOT_SUPPORTED
application/json An object. Nested values are stored as they arrive

A submission can carry up to 100 fields and 256 KB.

A small set of field names is reserved, matching Formspree’s. Migrating from Formspree is usually a matter of changing the action URL.

Field What it does
_gotcha Honeypot. Keep it in the markup, hidden with CSS. Arriving filled in means a bot, and the submission is quarantined silently while the sender still sees success. Rename it per form under Settings → Honeypot field
_replyto Sets Reply-To on the notification email. Falls back to a field named email
_subject Overrides the notification subject, up to 200 characters
_next Where to send the browser afterwards. Must be on the submitting site’s origin or one of your project’s verified domains, which is an open-redirect guard. Anything else is ignored
_cc Accepted for Formspree compatibility. Not currently used

Reserved fields are stripped before the submission is stored or exported, so they never appear in your inbox data.

After a non-JSON submission the browser is redirected with 303 See Other, so refreshing the destination does not resubmit. The target is the first of these that applies:

  1. The _next field, if present and valid
  2. The form’s redirect URL, set in Settings
  3. A hosted deploybase thank-you page

No CAPTCHA, no Akismet, no reCAPTCHA. Five layers, in order:

  • Honeypot (_gotcha). Filled in means bot, quarantined silently
  • Origin allow-list, configurable per form. Empty accepts any origin
  • Per-IP rate limit of 20 requests a minute per form, the only case that gets an explicit 429
  • Per-form flood limit of 120 submissions a minute. Anything over is still accepted, just quarantined, so a genuine traffic spike does not cost you leads
  • Duplicate absorption. Identical submissions inside a one-minute window are absorbed rather than stored twice

Nothing is deleted. Everything quarantined lands in the form’s Spam tab, and marking one “Not spam” restores it to the inbox. Quarantined submissions never send a notification and never count against your quota, and the sender never learns which verdict they got.

  • Submissions are stored in the EU, in Paris
  • Raw IP addresses are never stored or logged. By default a truncated form is kept, 203.0.113.x, and a per-form setting turns off even that
  • Retention: keep submissions indefinitely, or purge automatically after 30, 90 or 365 days. Changing the window applies to existing submissions, not only new ones
  • Erasure: owners and admins can hard-delete every submission matching an email address, from Forms → privacy tools or over the API. API keys act as Member and cannot make this call, so it needs a signed-in user’s token:
Terminal window
curl -X DELETE "https://api.deploybase.eu/api/v1/teams/form-submissions?email=jane@example.com" \
-H "Authorization: Bearer $DEPLOYBASE_TOKEN"

Each erasure is written to an audit trail, recording a hashed email, the number of submissions removed and who asked, so you have a record to show.

Each submission emails the form’s notify addresses: verified team members, plus any external recipients who have confirmed.

Above 30 submissions an hour, notifications collapse into one hourly digest rather than one email each. If you pass your plan’s monthly allowance you get a single “notifications paused” notice for that billing period rather than a stream. Teams can opt out entirely in notification preferences.

To get submissions to a client, a contractor or a shared inbox, add an external recipient in Forms → form → Settings.

  1. An owner or admin adds the address
  2. One confirmation email goes out. Until the link is clicked the recipient sits at Pending and receives nothing
  3. After confirming, they receive every new submission. Anything that arrived while they were pending is not backfilled, and stays in the inbox
  4. Every notification carries an unsubscribe link. Unsubscribing stops mail immediately and permanently, until an admin removes and re-adds the address, which starts a fresh confirmation

Limits keep this from becoming a way to email strangers: five recipients per team awaiting confirmation at once, across every form, ten confirmation emails per team per day, and one confirmation per address per hour, so Resend has an hour of cooldown. Confirmation links are single use and expire.

Team member addresses are rejected here deliberately. Tick them in the notify list instead, which needs no confirmation.

Two more statuses can appear on a recipient row, and both mean deploybase has stopped sending on its own:

  • Bounced: mail failed permanently, usually a typo or a mailbox that no longer exists
  • Complained: the recipient marked one of our emails as spam. Sending to that address stops for good

Mail providers judge a sender by how much undeliverable and unwanted mail it sends, so continuing would degrade delivery for every other recipient on the platform. Honouring a spam complaint permanently is standard practice across email providers.

There is no button to switch a suppressed recipient back on. If you have fixed whatever caused a bounce, remove the recipient and add the address again to start a fresh confirmation. For a complaint, only re-add the address if the person asks you to.

The same applies to your team’s notification email under Settings → Notifications. If that address bounces or reports us, notifications stop and the page says so.

Forms themselves are unlimited on every plan. The limit is on verified, non-spam submissions per month, and the current allowance is on the pricing page.

Spam and quarantined submissions never count. Past the allowance, submissions keep being stored and are marked uncounted, notifications pause, and your site is not affected. There is no overage charge.

Export a form’s inbox as CSV or JSON from the dashboard, or over MCP, which exposes list_forms, list_form_submissions, export_form_submissions and the spam-marking tools to an AI assistant.

  • File uploads
  • Outbound webhooks and Slack notifications
  • Autoresponders back to the submitter